diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index 48fcae18f..cffedfcb2 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -21,6 +21,8 @@ jobs: PYTHON_VERSION: 3.7 TOXENV: py37 CERTBOT_NO_PIN: 1 + linux-external-mock: + TOXENV: external-mock linux-boulder-v1-integration-certbot-oldest: PYTHON_VERSION: 3.6 TOXENV: integration-certbot-oldest diff --git a/.dockerignore b/.dockerignore index b94bf7960..2ce8a8209 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,5 +8,4 @@ .git .tox venv -venv3 docs diff --git a/.envrc b/.envrc index 4d2077ebb..43c3170d6 100644 --- a/.envrc +++ b/.envrc @@ -3,7 +3,7 @@ # activated and then deactivated when you cd elsewhere. Developers have to have # direnv set up and run `direnv allow` to allow this file to execute on their # system. You can find more information at https://direnv.net/. -. venv3/bin/activate +. venv/bin/activate # direnv doesn't support modifying PS1 so we unset it to squelch the error # it'll otherwise print about this being done in the activate script. See # https://github.com/direnv/direnv/wiki/PS1. If you would like your shell diff --git a/.pylintrc b/.pylintrc index 0e78828bd..a2468b0cf 100644 --- a/.pylintrc +++ b/.pylintrc @@ -254,7 +254,7 @@ ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis -ignored-modules=pkg_resources,confargparse,argparse,six.moves,six.moves.urllib +ignored-modules=pkg_resources,confargparse,argparse # import errors ignored only in 1.4.4 # https://bitbucket.org/logilab/pylint/commits/cd000904c9e2 diff --git a/Dockerfile-dev b/Dockerfile-dev index ae197b1cb..86847f8fd 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -15,6 +15,6 @@ RUN apt-get update && \ /tmp/* \ /var/tmp/* -RUN VENV_NAME="../venv3" python3 tools/venv3.py +RUN VENV_NAME="../venv" python3 tools/venv.py -ENV PATH /opt/certbot/venv3/bin:$PATH +ENV PATH /opt/certbot/venv/bin:$PATH diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 376e9a382..41a2aa258 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -9,7 +9,6 @@ import socket from cryptography.hazmat.primitives import hashes # type: ignore import josepy as jose import requests -import six from OpenSSL import SSL # type: ignore # https://github.com/python/typeshed/issues/2052 from OpenSSL import crypto @@ -145,8 +144,7 @@ class KeyAuthorizationChallengeResponse(ChallengeResponse): return jobj -@six.add_metaclass(abc.ABCMeta) -class KeyAuthorizationChallenge(_TokenChallenge): +class KeyAuthorizationChallenge(_TokenChallenge, metaclass=abc.ABCMeta): """Challenge based on Key Authorization. :param response_cls: Subclass of `KeyAuthorizationChallengeResponse` diff --git a/acme/acme/client.py b/acme/acme/client.py index d413ce13d..c3f8c550f 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -4,9 +4,9 @@ import collections import datetime from email.utils import parsedate_tz import heapq +import http.client as http_client import logging import re -import sys import time import josepy as jose @@ -15,8 +15,6 @@ import requests from requests.adapters import HTTPAdapter from requests.utils import parse_header_links from requests_toolbelt.adapters.source import SourceAddressAdapter -import six -from six.moves import http_client from acme import crypto_util from acme import errors @@ -30,17 +28,6 @@ from acme.mixins import VersionedLEACMEMixin logger = logging.getLogger(__name__) -# Prior to Python 2.7.9 the stdlib SSL module did not allow a user to configure -# many important security related options. On these platforms we use PyOpenSSL -# for SSL, which does allow these options to be configured. -# https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning -if sys.version_info < (2, 7, 9): # pragma: no cover - try: - requests.packages.urllib3.contrib.pyopenssl.inject_into_urllib3() # type: ignore - except AttributeError: - import urllib3.contrib.pyopenssl - urllib3.contrib.pyopenssl.inject_into_urllib3() - DEFAULT_NETWORK_TIMEOUT = 45 DER_CONTENT_TYPE = 'application/pkix-cert' @@ -260,7 +247,7 @@ class Client(ClientBase): if net is None: net = ClientNetwork(key, alg=alg, verify_ssl=verify_ssl) - if isinstance(directory, six.string_types): + if isinstance(directory, str): directory = messages.Directory.from_json( net.get(directory).json()) super(Client, self).__init__(directory=directory, @@ -475,7 +462,7 @@ class Client(ClientBase): exhausted.add(authzr) if exhausted or any(authzr.body.status == messages.STATUS_INVALID - for authzr in six.itervalues(updated)): + for authzr in updated.values()): raise errors.PollError(exhausted, updated) updated_authzrs = tuple(updated[authzr] for authzr in authzrs) diff --git a/acme/acme/messages.py b/acme/acme/messages.py index 3a505843d..44ecb143c 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -1,8 +1,8 @@ """ACME protocol messages.""" import json +from collections.abc import Hashable import josepy as jose -import six from acme import challenges from acme import errors @@ -11,13 +11,6 @@ from acme import jws from acme import util from acme.mixins import ResourceMixin -try: - from collections.abc import Hashable -except ImportError: # pragma: no cover - from collections import Hashable - - - OLD_ERROR_PREFIX = "urn:acme:error:" ERROR_PREFIX = "urn:ietf:params:acme:error:" @@ -68,7 +61,6 @@ def is_acme_error(err): return False -@six.python_2_unicode_compatible class Error(jose.JSONObjectWithFields, errors.Error): """ACME error. diff --git a/acme/acme/standalone.py b/acme/acme/standalone.py index 7a61ba868..94397f0de 100644 --- a/acme/acme/standalone.py +++ b/acme/acme/standalone.py @@ -1,14 +1,13 @@ """Support for standalone client challenge solvers. """ import collections import functools +import http.client as http_client +import http.server as BaseHTTPServer import logging import socket +import socketserver import threading -from six.moves import BaseHTTPServer # type: ignore -from six.moves import http_client -from six.moves import socketserver # type: ignore - from acme import challenges from acme import crypto_util from acme.magic_typing import List diff --git a/acme/acme/util.py b/acme/acme/util.py index b3b0d79eb..20fa455fd 100644 --- a/acme/acme/util.py +++ b/acme/acme/util.py @@ -1,7 +1,6 @@ """ACME utilities.""" -import six def map_keys(dikt, func): """Map dictionary keys.""" - return {func(key): value for key, value in six.iteritems(dikt)} + return {func(key): value for key, value in dikt.items()} diff --git a/acme/docs/conf.py b/acme/docs/conf.py index 9d3c4d05c..d419326df 100644 --- a/acme/docs/conf.py +++ b/acme/docs/conf.py @@ -87,7 +87,6 @@ language = 'en' # directories to ignore when looking for source files. exclude_patterns = [ '_build', - 'man/*' ] # The reST default role (used for this markup: `text`) to use for all diff --git a/acme/docs/man/jws.rst b/acme/docs/man/jws.rst index d7ff8f405..7e83328b2 100644 --- a/acme/docs/man/jws.rst +++ b/acme/docs/man/jws.rst @@ -1 +1,3 @@ +:orphan: + .. literalinclude:: ../jws-help.txt diff --git a/acme/setup.py b/acme/setup.py index 056b00107..847ca9299 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -1,11 +1,9 @@ -from distutils.version import LooseVersion import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ @@ -17,21 +15,11 @@ install_requires = [ 'PyOpenSSL>=17.3.0', 'pyrfc3339', 'pytz', - 'requests[security]>=2.6.0', # security extras added in 2.4.1 + 'requests>=2.6.0', 'requests-toolbelt>=0.3.0', 'setuptools>=39.0.1', - 'six>=1.11.0', ] -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - dev_extras = [ 'pytest', 'pytest-xdist', diff --git a/acme/tests/challenges_test.py b/acme/tests/challenges_test.py index 70371051c..cc604b0de 100644 --- a/acme/tests/challenges_test.py +++ b/acme/tests/challenges_test.py @@ -1,14 +1,11 @@ """Tests for acme.challenges.""" +import urllib.parse as urllib_parse import unittest +from unittest import mock import josepy as jose import OpenSSL -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore import requests -from six.moves.urllib import parse as urllib_parse from acme import errors diff --git a/acme/tests/client_test.py b/acme/tests/client_test.py index c84878c42..6f9aecda2 100644 --- a/acme/tests/client_test.py +++ b/acme/tests/client_test.py @@ -2,17 +2,14 @@ # pylint: disable=too-many-lines import copy import datetime +import http.client as http_client import json import unittest +from unittest import mock import josepy as jose -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore import OpenSSL import requests -from six.moves import http_client # pylint: disable=import-error from acme import challenges from acme import errors diff --git a/acme/tests/crypto_util_test.py b/acme/tests/crypto_util_test.py index 705a3c856..f271ad37d 100644 --- a/acme/tests/crypto_util_test.py +++ b/acme/tests/crypto_util_test.py @@ -1,14 +1,13 @@ """Tests for acme.crypto_util.""" import itertools import socket +import socketserver import threading import time import unittest import josepy as jose import OpenSSL -import six -from six.moves import socketserver # type: ignore # pylint: disable=import-error from acme import errors import test_util @@ -27,8 +26,6 @@ class SSLSocketAndProbeSNITest(unittest.TestCase): class _TestServer(socketserver.TCPServer): - # six.moves.* | pylint: disable=attribute-defined-outside-init,no-init - def server_bind(self): # pylint: disable=missing-docstring self.socket = SSLSocket(socket.socket(), certs) @@ -62,7 +59,6 @@ class SSLSocketAndProbeSNITest(unittest.TestCase): self.assertRaises(errors.Error, self._probe, b'bar') def test_probe_connection_error(self): - # pylint has a hard time with six self.server.server_close() original_timeout = socket.getdefaulttimeout() try: @@ -121,9 +117,9 @@ class PyOpenSSLCertOrReqSANTest(unittest.TestCase): @classmethod def _get_idn_names(cls): """Returns expected names from '{cert,csr}-idnsans.pem'.""" - chars = [six.unichr(i) for i in itertools.chain(range(0x3c3, 0x400), - range(0x641, 0x6fc), - range(0x1820, 0x1877))] + chars = [chr(i) for i in itertools.chain(range(0x3c3, 0x400), + range(0x641, 0x6fc), + range(0x1820, 0x1877))] return [''.join(chars[i: i + 45]) + '.invalid' for i in range(0, len(chars), 45)] diff --git a/acme/tests/errors_test.py b/acme/tests/errors_test.py index fb90a3f0d..11c57059c 100644 --- a/acme/tests/errors_test.py +++ b/acme/tests/errors_test.py @@ -1,10 +1,6 @@ """Tests for acme.errors.""" import unittest - -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore +from unittest import mock class BadNonceTest(unittest.TestCase): diff --git a/acme/tests/magic_typing_test.py b/acme/tests/magic_typing_test.py index 9e4fd29f5..048995916 100644 --- a/acme/tests/magic_typing_test.py +++ b/acme/tests/magic_typing_test.py @@ -1,11 +1,7 @@ """Tests for acme.magic_typing.""" import sys import unittest - -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore +from unittest import mock class MagicTypingTest(unittest.TestCase): diff --git a/acme/tests/messages_test.py b/acme/tests/messages_test.py index 70b05b419..74d1737ec 100644 --- a/acme/tests/messages_test.py +++ b/acme/tests/messages_test.py @@ -1,11 +1,8 @@ """Tests for acme.messages.""" import unittest +from unittest import mock import josepy as jose -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore from acme import challenges import test_util diff --git a/acme/tests/standalone_test.py b/acme/tests/standalone_test.py index 3d068fb46..e6aa8f2d6 100644 --- a/acme/tests/standalone_test.py +++ b/acme/tests/standalone_test.py @@ -1,16 +1,13 @@ """Tests for acme.standalone.""" +import http.client as http_client import socket +import socketserver import threading import unittest +from unittest import mock import josepy as jose -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore import requests -from six.moves import http_client # pylint: disable=import-error -from six.moves import socketserver # type: ignore # pylint: disable=import-error from acme import challenges from acme import crypto_util diff --git a/certbot-apache/certbot_apache/_internal/interfaces.py b/certbot-apache/certbot_apache/_internal/interfaces.py index 647790c41..77daa5b56 100644 --- a/certbot-apache/certbot_apache/_internal/interfaces.py +++ b/certbot-apache/certbot_apache/_internal/interfaces.py @@ -100,12 +100,10 @@ For this reason the internal representation of data should not ignore the case. """ import abc -import six -@six.add_metaclass(abc.ABCMeta) -class ParserNode(object): +class ParserNode(object, metaclass=abc.ABCMeta): """ ParserNode is the basic building block of the tree of such nodes, representing the structure of the configuration. It is largely meant to keep @@ -204,9 +202,7 @@ class ParserNode(object): """ -# Linter rule exclusion done because of https://github.com/PyCQA/pylint/issues/179 -@six.add_metaclass(abc.ABCMeta) # pylint: disable=abstract-method -class CommentNode(ParserNode): +class CommentNode(ParserNode, metaclass=abc.ABCMeta): """ CommentNode class is used for representation of comments within the parsed configuration structure. Because of the nature of comments, it is not able @@ -249,8 +245,7 @@ class CommentNode(ParserNode): metadata=kwargs.get('metadata', {})) # pragma: no cover -@six.add_metaclass(abc.ABCMeta) -class DirectiveNode(ParserNode): +class DirectiveNode(ParserNode, metaclass=abc.ABCMeta): """ DirectiveNode class represents a configuration directive within the configuration. It can have zero or more parameters attached to it. Because of the nature of @@ -325,8 +320,7 @@ class DirectiveNode(ParserNode): """ -@six.add_metaclass(abc.ABCMeta) -class BlockNode(DirectiveNode): +class BlockNode(DirectiveNode, metaclass=abc.ABCMeta): """ BlockNode class represents a block of nested configuration directives, comments and other blocks as its children. A BlockNode can have zero or more parameters diff --git a/certbot-apache/certbot_apache/_internal/parser.py b/certbot-apache/certbot_apache/_internal/parser.py index 4d997545b..75be0833f 100644 --- a/certbot-apache/certbot_apache/_internal/parser.py +++ b/certbot-apache/certbot_apache/_internal/parser.py @@ -5,7 +5,6 @@ import logging import re import sys -import six from acme.magic_typing import Dict from acme.magic_typing import List @@ -275,7 +274,7 @@ class ApacheParser(object): while len(mods) != prev_size: prev_size = len(mods) - for match_name, match_filename in six.moves.zip( + for match_name, match_filename in zip( iterator, iterator): mod_name = self.get_arg(match_name) mod_filename = self.get_arg(match_filename) diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index bebca6b25..f129343b3 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -1,11 +1,7 @@ -from distutils.version import LooseVersion -import sys - -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -18,15 +14,6 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - dev_extras = [ 'apacheconfig>=0.3.2', ] diff --git a/certbot-apache/tests/autohsts_test.py b/certbot-apache/tests/autohsts_test.py index d15600215..db1c46b52 100644 --- a/certbot-apache/tests/autohsts_test.py +++ b/certbot-apache/tests/autohsts_test.py @@ -7,7 +7,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock # type: ignore -import six # pylint: disable=unused-import # six is used in mock.patch() from certbot import errors from certbot_apache._internal import constants diff --git a/certbot-apache/tests/configurator_test.py b/certbot-apache/tests/configurator_test.py index 6753995c6..302bf0023 100644 --- a/certbot-apache/tests/configurator_test.py +++ b/certbot-apache/tests/configurator_test.py @@ -10,7 +10,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock # type: ignore -import six # pylint: disable=unused-import # six is used in mock.patch() from acme import challenges from certbot import achallenges @@ -726,7 +725,7 @@ class MultipleVhostsTest(util.ApacheTest): # This calls open self.config.reverter.register_file_creation = mock.Mock() mock_open.side_effect = IOError - with mock.patch("six.moves.builtins.open", mock_open): + with mock.patch("builtins.open", mock_open): self.assertRaises( errors.PluginError, self.config.make_vhost_ssl, self.vh_truth[0]) @@ -1834,7 +1833,7 @@ class InstallSslOptionsConfTest(util.ApacheTest): def test_open_module_file(self): mock_open = mock.mock_open(read_data="testing 12 3") - with mock.patch("six.moves.builtins.open", mock_open): + with mock.patch("builtins.open", mock_open): self.assertEqual(self.config._open_module_file("/nonsense/"), "testing 12 3") if __name__ == "__main__": diff --git a/certbot-auto b/certbot-auto index e8012439a..002fd5ffc 100755 --- a/certbot-auto +++ b/certbot-auto @@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then fi VENV_BIN="$VENV_PATH/bin" BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt" -LE_AUTO_VERSION="1.11.0" +LE_AUTO_VERSION="1.12.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -803,6 +803,7 @@ if [ -f /etc/debian_version ]; then elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/redhat-release ]; then DEPRECATED_OS=1 # Run DeterminePythonVersion to decide on the basis of available Python versions @@ -863,22 +864,31 @@ elif [ -f /etc/redhat-release ]; then LE_PYTHON="$prev_le_python" elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/arch-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/manjaro-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/gentoo-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq FreeBSD ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq Darwin ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 else DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 fi # We handle this case after determining the normal bootstrap version to allow @@ -1107,7 +1117,9 @@ if [ "$1" = "--le-auto-phase2" ]; then fi if [ -f "$VENV_BIN/letsencrypt" -a "$INSTALL_ONLY" != 1 ]; then - error "Certbot will no longer receive updates." + error "certbot-auto and its Certbot installation will no longer receive updates." + error "You will not receive any bug fixes including those fixing server compatibility" + error "or security problems." error "Please visit https://certbot.eff.org/ to check for other alternatives." "$VENV_BIN/letsencrypt" "$@" exit 0 @@ -1475,18 +1487,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.11.0 \ - --hash=sha256:b7faa66c40a1ce5a31bfc8668d8feb5d2db6f7af9e791079a6d95c77b6593bf4 \ - --hash=sha256:6b0ce04e55379aff0a47f873fa05c084538ad0f4a9b79f33108dbb0a7a668b43 -acme==1.11.0 \ - --hash=sha256:77d6ce61b155315d7d7031489bbd245c0ea42c0453a04d4304393414e741a56d \ - --hash=sha256:092eb09a074a935da4c10f66cb8634ffb2cc2d2cc1035d2998d608996efab924 -certbot-apache==1.11.0 \ - --hash=sha256:ea7ac88733aad91a89c700289effda2a0c0658778da1ae2c54a0aefaee351285 \ - --hash=sha256:3ed001427ec0b49324f2b9af7170fa6e6e88948fa51c3678b07bf17f8138863d -certbot-nginx==1.11.0 \ - --hash=sha256:79de69782a1199e577787ff9790dee02a44aac17dbecd6a7287593030842a306 \ - --hash=sha256:9afe611f99a78b8898941b8ad7bdcf7f3c2b6e0fce27125268f7c713e64b34ee +certbot==1.12.0 \ + --hash=sha256:f4bb3da5391e4a28e9a2e52ab54986171c0864feff17eaaaca6729a1d4c433a6 \ + --hash=sha256:5ee738773479bcb7794e43fedd2415acc0969b75bdd2a21f451e3bff9d99df59 +acme==1.12.0 \ + --hash=sha256:ca4ad044429f1b8b670b958e5c7ea38159def9d601f4af2359355993918c3317 \ + --hash=sha256:aa363474d50e9fdda27acb8b1aa7efb26fecc5650e02039a0de3a3f0e696c2f2 +certbot-apache==1.12.0 \ + --hash=sha256:38899f6fa08799de9535795d919acf968f288d7208909baf7733f9a763c15227 \ + --hash=sha256:e5679b40d99bd241f4fcd9fe44b73e6e25ccc969a617131ff6ebc90d562a49f2 +certbot-nginx==1.12.0 \ + --hash=sha256:332cd70067bbcf6db52a002650ffa4844d0bd9780279d662aa6725b43f776c14 \ + --hash=sha256:3fb6a55290d37ad466681a89a85ceca4c4026fdd8702f3010b87a74266a6fe7b UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-ci/certbot_integration_tests/utils/misc.py b/certbot-ci/certbot_integration_tests/utils/misc.py index 799b079fe..e6b9f0c88 100644 --- a/certbot-ci/certbot_integration_tests/utils/misc.py +++ b/certbot-ci/certbot_integration_tests/utils/misc.py @@ -4,10 +4,12 @@ or outside during setup/teardown of the integration tests environment. """ import contextlib import errno +import http.server as SimpleHTTPServer import multiprocessing import os import re import shutil +import socketserver import stat import sys import tempfile @@ -23,8 +25,6 @@ from cryptography.x509 import load_pem_x509_certificate from OpenSSL import crypto import pkg_resources import requests -from six.moves import SimpleHTTPServer -from six.moves import socketserver from certbot_integration_tests.utils.constants import \ PEBBLE_ALTERNATE_ROOTS, PEBBLE_MANAGEMENT_URL diff --git a/certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py b/certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py index b86e1cbc9..4db72998f 100755 --- a/certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py +++ b/certbot-ci/certbot_integration_tests/utils/pebble_ocsp_server.py @@ -4,6 +4,7 @@ This runnable module interfaces itself with the Pebble management interface in o to serve a mock OCSP responder during integration tests against Pebble. """ import datetime +import http.server as BaseHTTPServer import re from cryptography import x509 @@ -13,7 +14,6 @@ from cryptography.hazmat.primitives import serialization from cryptography.x509 import ocsp from dateutil import parser import requests -from six.moves import BaseHTTPServer from certbot_integration_tests.utils.constants import MOCK_OCSP_SERVER_PORT from certbot_integration_tests.utils.constants import PEBBLE_MANAGEMENT_URL diff --git a/certbot-ci/certbot_integration_tests/utils/proxy.py b/certbot-ci/certbot_integration_tests/utils/proxy.py index 225f98e6e..7c46e640d 100644 --- a/certbot-ci/certbot_integration_tests/utils/proxy.py +++ b/certbot-ci/certbot_integration_tests/utils/proxy.py @@ -1,12 +1,12 @@ #!/usr/bin/env python # pylint: disable=missing-module-docstring +import http.server as BaseHTTPServer import json import re import sys import requests -from six.moves import BaseHTTPServer from certbot_integration_tests.utils.misc import GracefulTCPServer diff --git a/certbot-ci/setup.py b/certbot-ci/setup.py index 3277df1c0..9f9c1f462 100644 --- a/certbot-ci/setup.py +++ b/certbot-ci/setup.py @@ -18,7 +18,6 @@ install_requires = [ 'python-dateutil', 'pyyaml', 'requests', - 'six' ] # Add pywin32 on Windows platforms to handle low-level system calls. diff --git a/certbot-compatibility-test/Dockerfile b/certbot-compatibility-test/Dockerfile index f66e4c945..e0a439d01 100644 --- a/certbot-compatibility-test/Dockerfile +++ b/certbot-compatibility-test/Dockerfile @@ -8,11 +8,11 @@ RUN apt-get update && \ WORKDIR /opt/certbot/src # We copy all contents of the build directory to allow us to easily use -# things like tools/venv3.py which expects all of our packages to be available. +# things like tools/venv.py which expects all of our packages to be available. COPY . . -RUN tools/venv3.py -ENV PATH /opt/certbot/src/venv3/bin:$PATH +RUN tools/venv.py +ENV PATH /opt/certbot/src/venv/bin:$PATH # install in editable mode (-e) to save space: it's not possible to # "rm -rf /opt/certbot/src" (it's stays in the underlaying image); diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py index b6fbe2817..2b3f94581 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py @@ -2,11 +2,8 @@ import os import shutil import subprocess +from unittest import mock -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore import zope.interface from certbot import errors as le_errors diff --git a/certbot-compatibility-test/certbot_compatibility_test/validator.py b/certbot-compatibility-test/certbot_compatibility_test/validator.py index bfa03f22d..9a082523a 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/validator.py +++ b/certbot-compatibility-test/certbot_compatibility_test/validator.py @@ -3,8 +3,6 @@ import logging import socket import requests -import six -from six.moves import xrange from acme import crypto_util from acme import errors as acme_errors @@ -19,11 +17,11 @@ class Validator(object): """Verifies the certificate presented at name is cert""" if alt_host is None: host = socket.gethostbyname(name).encode() - elif isinstance(alt_host, six.binary_type): + elif isinstance(alt_host, bytes): host = alt_host else: host = alt_host.encode() - name = name if isinstance(name, six.binary_type) else name.encode() + name = name if isinstance(name, bytes) else name.encode() try: presented_cert = crypto_util.probe_sni(name, host, port) @@ -62,7 +60,7 @@ class Validator(object): else: response = requests.get(url, allow_redirects=False) - return response.status_code in xrange(300, 309) + return response.status_code in range(300, 309) def hsts(self, name): """Test for HTTP Strict Transport Security header""" diff --git a/certbot-compatibility-test/certbot_compatibility_test/validator_test.py b/certbot-compatibility-test/certbot_compatibility_test/validator_test.py index 0b1056561..711d1b38e 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/validator_test.py +++ b/certbot-compatibility-test/certbot_compatibility_test/validator_test.py @@ -1,10 +1,7 @@ """Tests for certbot_compatibility_test.validator.""" import unittest +from unittest import mock -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore import OpenSSL import requests diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index e7b7d9c3a..af19b126e 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -1,29 +1,17 @@ -from distutils.version import LooseVersion import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' install_requires = [ 'certbot', 'certbot-apache', - 'six', 'requests', 'zope.interface', ] -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - if sys.version_info < (2, 7, 9): # For secure SSL connexion with Python 2.7 (InsecurePlatformWarning) install_requires.append('ndg-httpsclient') diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index 7ee81c103..eab6cdb70 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index f57eb4d64..83513ef7c 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index d1e84710d..6e60444cf 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -1,19 +1,16 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. install_requires = [ 'python-digitalocean>=1.11', 'setuptools>=39.0.1', - 'six>=1.11.0', 'zope.interface', ] @@ -28,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index f73f6f7c8..f1fcfd11d 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -26,15 +24,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - # This package normally depends on dns-lexicon>=3.2.1 to address the # problem described in https://github.com/AnalogJ/lexicon/issues/387, # however, the fix there has been backported to older versions of diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index e7cd2e1ed..185048a2d 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index 0cba57800..0ae9c1bf7 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ @@ -26,15 +24,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 09dace6c0..b16d014c6 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -30,15 +28,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index 6f796b45c..21ccf9d42 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ @@ -26,15 +24,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index ee4fc352e..2312d6fcc 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index fe667fe6c..658027b9a 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index fc8402ff2..b4f73ddb4 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index 2af5566c4..ce74611cd 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index 4b60d8570..8def9a702 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -27,15 +25,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index b4d59e7b6..6f4f8e506 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -1,12 +1,10 @@ -from distutils.version import LooseVersion import os import sys -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ @@ -26,15 +24,6 @@ elif 'bdist_wheel' in sys.argv[1:]: if os.environ.get('SNAP_BUILD'): install_requires.append('packaging') -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - docs_extras = [ 'Sphinx>=1.0', # autodoc_member_order = 'bysource', autodoc_default_flags 'sphinx_rtd_theme', diff --git a/certbot-nginx/certbot_nginx/_internal/nginxparser.py b/certbot-nginx/certbot_nginx/_internal/nginxparser.py index 5f723dcef..f043b0e4d 100644 --- a/certbot-nginx/certbot_nginx/_internal/nginxparser.py +++ b/certbot-nginx/certbot_nginx/_internal/nginxparser.py @@ -15,7 +15,6 @@ from pyparsing import restOfLine from pyparsing import stringEnd from pyparsing import White from pyparsing import ZeroOrMore -import six from acme.magic_typing import IO, Any # pylint: disable=unused-import logger = logging.getLogger(__name__) @@ -79,7 +78,7 @@ class RawNginxDumper(object): """Iterates the dumped nginx content.""" blocks = blocks or self.blocks for b0 in blocks: - if isinstance(b0, six.string_types): + if isinstance(b0, str): yield b0 continue item = copy.deepcopy(b0) @@ -96,7 +95,7 @@ class RawNginxDumper(object): yield '}' else: # not a block - list of strings semicolon = ";" - if isinstance(item[0], six.string_types) and item[0].strip() == '#': # comment + if isinstance(item[0], str) and item[0].strip() == '#': # comment semicolon = "" yield "".join(item) + semicolon @@ -131,14 +130,14 @@ def load(_file): def dumps(blocks): - # type: (UnspacedList) -> six.text_type + # type: (UnspacedList) -> str """Dump to a Unicode string. :param UnspacedList block: The parsed tree - :rtype: six.text_type + :rtype: str """ - return six.text_type(RawNginxDumper(blocks.spaced)) + return str(RawNginxDumper(blocks.spaced)) def dump(blocks, _file): @@ -154,7 +153,7 @@ def dump(blocks, _file): _file.write(dumps(blocks)) -spacey = lambda x: (isinstance(x, six.string_types) and x.isspace()) or x == '' +spacey = lambda x: (isinstance(x, str) and x.isspace()) or x == '' class UnspacedList(list): """Wrap a list [of lists], making any whitespace entries magically invisible""" diff --git a/certbot-nginx/certbot_nginx/_internal/obj.py b/certbot-nginx/certbot_nginx/_internal/obj.py index 4e0d8cf35..2dd02f180 100644 --- a/certbot-nginx/certbot_nginx/_internal/obj.py +++ b/certbot-nginx/certbot_nginx/_internal/obj.py @@ -1,7 +1,6 @@ """Module contains classes used by the Nginx Configurator.""" import re -import six from certbot.plugins import common @@ -211,7 +210,7 @@ class VirtualHost(object): def contains_list(self, test): """Determine if raw server block contains test list at top level """ - for i in six.moves.range(0, len(self.raw) - len(test) + 1): + for i in range(0, len(self.raw) - len(test) + 1): if self.raw[i:i + len(test)] == test: return True return False @@ -250,7 +249,7 @@ def _find_directive(directives, directive_name, match_content=None): """Find a directive of type directive_name in directives. If match_content is given, Searches for `match_content` in the directive arguments. """ - if not directives or isinstance(directives, six.string_types): + if not directives or isinstance(directives, str): return None # If match_content is None, just match on directive type. Otherwise, match on diff --git a/certbot-nginx/certbot_nginx/_internal/parser.py b/certbot-nginx/certbot_nginx/_internal/parser.py index 72091b03f..fe5d7bb31 100644 --- a/certbot-nginx/certbot_nginx/_internal/parser.py +++ b/certbot-nginx/certbot_nginx/_internal/parser.py @@ -7,7 +7,6 @@ import logging import re import pyparsing -import six from acme.magic_typing import Dict from acme.magic_typing import List @@ -549,7 +548,7 @@ def _is_include_directive(entry): """ return (isinstance(entry, list) and len(entry) == 2 and entry[0] == 'include' and - isinstance(entry[1], six.string_types)) + isinstance(entry[1], str)) def _is_ssl_on_directive(entry): """Checks if an nginx parsed entry is an 'ssl on' directive. @@ -654,7 +653,7 @@ def _add_directive(block, directive, insert_at_top): directive_name = directive[0] def can_append(loc, dir_name): """ Can we append this directive to the block? """ - return loc is None or (isinstance(dir_name, six.string_types) + return loc is None or (isinstance(dir_name, str) and dir_name in REPEATABLE_DIRECTIVES) err_fmt = 'tried to insert directive "{0}" but found conflicting "{1}".' diff --git a/certbot-nginx/certbot_nginx/_internal/parser_obj.py b/certbot-nginx/certbot_nginx/_internal/parser_obj.py index 390e18e4d..d616a1a99 100644 --- a/certbot-nginx/certbot_nginx/_internal/parser_obj.py +++ b/certbot-nginx/certbot_nginx/_internal/parser_obj.py @@ -4,7 +4,6 @@ raw lists of tokens from pyparsing. """ import abc import logging -import six from acme.magic_typing import List from certbot import errors @@ -152,7 +151,7 @@ class Statements(Parsable): if not isinstance(raw_list, list): raise errors.MisconfigurationError("Statements parsing expects a list!") # If there's a trailing whitespace in the list of statements, keep track of it. - if raw_list and isinstance(raw_list[-1], six.string_types) and raw_list[-1].isspace(): + if raw_list and isinstance(raw_list[-1], str) and raw_list[-1].isspace(): self._trailing_whitespace = raw_list[-1] raw_list = raw_list[:-1] self._data = [parse_raw(elem, self, add_spaces) for elem in raw_list] @@ -184,7 +183,7 @@ class Statements(Parsable): def _space_list(list_): """ Inserts whitespace between adjacent non-whitespace tokens. """ spaced_statement = [] # type: List[str] - for i in reversed(six.moves.xrange(len(list_))): + for i in reversed(range(len(list_))): spaced_statement.insert(0, list_[i]) if i > 0 and not list_[i].isspace() and not list_[i-1].isspace(): spaced_statement.insert(0, " ") @@ -206,7 +205,7 @@ class Sentence(Parsable): :returns: whether this lists is parseable by `Sentence`. """ return isinstance(lists, list) and len(lists) > 0 and \ - all(isinstance(elem, six.string_types) for elem in lists) + all(isinstance(elem, str) for elem in lists) def parse(self, raw_list, add_spaces=False): """ Parses a list of string types into this object. @@ -214,7 +213,7 @@ class Sentence(Parsable): if add_spaces: raw_list = _space_list(raw_list) if not isinstance(raw_list, list) or \ - any(not isinstance(elem, six.string_types) for elem in raw_list): + any(not isinstance(elem, str) for elem in raw_list): raise errors.MisconfigurationError("Sentence parsing expects a list of string types.") self._data = raw_list diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 4f6f7ed2a..385f4cc17 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -1,11 +1,7 @@ -from distutils.version import LooseVersion -import sys - -from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.12.0.dev0' +version = '1.13.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. @@ -18,15 +14,6 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - setup( name='certbot-nginx', version=version, diff --git a/certbot-nginx/tests/http_01_test.py b/certbot-nginx/tests/http_01_test.py index 8f0673c1f..2947b099d 100644 --- a/certbot-nginx/tests/http_01_test.py +++ b/certbot-nginx/tests/http_01_test.py @@ -6,7 +6,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock # type: ignore -import six from acme import challenges from certbot import achallenges @@ -79,7 +78,7 @@ class HttpPerformTest(util.NginxTest): http_responses = self.http01.perform() self.assertEqual(len(http_responses), 4) - for i in six.moves.range(4): + for i in range(4): self.assertEqual(http_responses[i], acme_responses[i]) def test_mod_config(self): diff --git a/certbot-nginx/tests/test_log_util.py b/certbot-nginx/tests/test_log_util.py deleted file mode 100644 index 7aebf2151..000000000 --- a/certbot-nginx/tests/test_log_util.py +++ /dev/null @@ -1,125 +0,0 @@ -"""Backport for `TestCase.assertLogs()`. - -Most of the idea and code are from CPython implementation. -https://github.com/python/cpython/blob/b76518d43fb82ed9e5d27025d18c90a23d525c90/Lib/unittest/case.py -""" -import logging -import collections - -__all__ = ['AssertLogsMixin'] - -LoggingWatcher = collections.namedtuple('LoggingWatcher', ['records', 'output']) - - -class CapturingHandler(logging.Handler): - """ - A logging handler capturing all (raw and formatted) logging output. - """ - - def __init__(self): - super(CapturingHandler, self).__init__() - self.watcher = LoggingWatcher([], []) - - def flush(self): - pass - - def emit(self, record): - self.watcher.records.append(record) - self.watcher.output.append(self.format(record)) - - - -class AssertLogsContext(object): - """ - A context manager used to implement `TestCase.assertLogs()`. - """ - - LOGGING_FORMAT = '%(levelname)s:%(name)s:%(message)s' - - def __init__(self, test_case, logger_name, level): - self.test_case = test_case - - self.logger_name = logger_name - self.logger_states = None - self.logger = None - - if level: - # pylint: disable=protected-access,no-member - try: - # In Python 3.x - name_to_level = logging._nameToLevel # type: ignore - except AttributeError: - # In Python 2.7 - name_to_level = logging._levelNames # type: ignore - - self.level = name_to_level.get(level, level) - else: - self.level = logging.INFO - - self.watcher = None - - def _save_logger_states(self): - self.logger_states = (self.logger.handlers[:], self.logger.level, self.logger.propagate) - - def _restore_logger_states(self): - self.logger.handlers, self.logger.level, self.logger.propagate = self.logger_states - - def __enter__(self): - if isinstance(self.logger_name, logging.Logger): - self.logger = self.logger_name - else: - self.logger = logging.getLogger(self.logger_name) - - formatter = logging.Formatter(self.LOGGING_FORMAT) - - handler = CapturingHandler() - handler.setFormatter(formatter) - - self._save_logger_states() - self.logger.handlers = [handler] - self.logger.setLevel(self.level) - self.logger.propagate = False - - self.watcher = handler.watcher - return handler.watcher - - def __exit__(self, exc_type, exc_value, tb): - self._restore_logger_states() - - if exc_type is not None: - # let unexpected exceptions pass through - return - - if not self.watcher.records: - self._raiseFailure( - "no logs of level {} or higher triggered on {}" - .format(logging.getLevelName(self.level), self.logger.name)) - - def _raiseFailure(self, message): - message = self.test_case._formatMessage(None, message) # pylint: disable=protected-access - raise self.test_case.failureException(message) - - -class AssertLogsMixin(object): - """ - A mixin that implements `TestCase.assertLogs()`. - """ - - def assertLogs(self, logger=None, level=None): - """Fail unless a log message of level *level* or higher is emitted - on *logger_name* or its children. If omitted, *level* defaults to - INFO and *logger* defaults to the root logger. - This method must be used as a context manager, and will yield - a recording object with two attributes: `output` and `records`. - At the end of the context manager, the `output` attribute will - be a list of the matching formatted log messages and the - `records` attribute will be a list of the corresponding LogRecord - objects. - Example:: - with self.assertLogs('foo', level='INFO') as cm: - logging.getLogger('foo').info('first message') - logging.getLogger('foo.bar').error('second message') - self.assertEqual(cm.output, ['INFO:foo:first message', - 'ERROR:foo.bar:second message']) - """ - return AssertLogsContext(self, logger, level) diff --git a/certbot-nginx/tests/test_util.py b/certbot-nginx/tests/test_util.py index f545dc5bc..ee53e8e1e 100644 --- a/certbot-nginx/tests/test_util.py +++ b/certbot-nginx/tests/test_util.py @@ -17,10 +17,9 @@ from certbot.plugins import common from certbot.tests import util as test_util from certbot_nginx._internal import configurator from certbot_nginx._internal import nginxparser -import test_log_util -class NginxTest(test_log_util.AssertLogsMixin, test_util.ConfigTestCase): +class NginxTest(test_util.ConfigTestCase): def setUp(self): super(NginxTest, self).setUp() diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 10dda7d9d..3838a5ebe 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,7 +2,33 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). -## 1.12.0 - master +## 1.13.0 - master + +### Added + +* + +### Changed + +* CLI flags `--os-packages-only`, `--no-self-upgrade`, `--no-bootstrap` and `--no-permissions-check`, + which are related to certbot-auto, are deprecated and will be removed in a future release. +* Certbot no longer conditionally depends on an external mock module. Certbot's + test API will continue to use it if it is available for backwards + compatibility, however, this behavior has been deprecated and will be removed + in a future release. +* The acme library no longer depends on the `security` extras from `requests` + which was needed to support SNI in TLS requests when using old versions of + Python 2. +* Certbot and all of its components no longer depend on the library `six`. +* The update of certbot-auto itself is now disabled on all RHEL-like systems. + +### Fixed + +* + +More details about these changes can be found on our GitHub repo. + +## 1.12.0 - 2021-02-02 ### Added @@ -15,6 +41,11 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). every certificate in the chain. See [#8577](https://github.com/certbot/certbot/issues/8577). * Support for Python 2 has been removed. +* In previous releases, we caused certbot-auto to stop updating its Certbot + installation. In this release, we are beginning to disable updates to the + certbot-auto script itself. This release includes Amazon Linux users, and all + other systems that are not based on Debian or RHEL. We plan to make this + change to the certbot-auto script for all users in the coming months. ### Fixed diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index a196def66..be06b5803 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,3 +1,3 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.12.0.dev0' +__version__ = '1.13.0.dev0' diff --git a/certbot/certbot/_internal/account.py b/certbot/certbot/_internal/account.py index b4619beba..dbe111fbc 100644 --- a/certbot/certbot/_internal/account.py +++ b/certbot/certbot/_internal/account.py @@ -10,7 +10,6 @@ from cryptography.hazmat.primitives import serialization import josepy as jose import pyrfc3339 import pytz -import six from acme import fields as acme_fields from acme import messages @@ -101,7 +100,7 @@ class AccountMemoryStorage(interfaces.AccountStorage): self.accounts = initial_accounts if initial_accounts is not None else {} def find_all(self): - return list(six.itervalues(self.accounts)) + return list(self.accounts.values()) def save(self, account, client): if account.id in self.accounts: diff --git a/certbot/certbot/_internal/cli/__init__.py b/certbot/certbot/_internal/cli/__init__.py index e50cb338a..8d2f7c329 100644 --- a/certbot/certbot/_internal/cli/__init__.py +++ b/certbot/certbot/_internal/cli/__init__.py @@ -28,7 +28,8 @@ from certbot._internal.cli.cli_constants import ( ARGPARSE_PARAMS_TO_REMOVE, EXIT_ACTIONS, ZERO_ARG_ACTIONS, - VAR_MODIFIERS + VAR_MODIFIERS, + DEPRECATED_OPTIONS ) from certbot._internal.cli.cli_utils import ( @@ -248,27 +249,6 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): default=flag_default("duplicate"), help="Allow making a certificate lineage that duplicates an existing one " "(both can be renewed in parallel)") - helpful.add( - "automation", "--os-packages-only", action="store_true", - default=flag_default("os_packages_only"), - help="(certbot-auto only) install OS package dependencies and then stop") - helpful.add( - "automation", "--no-self-upgrade", action="store_true", - default=flag_default("no_self_upgrade"), - help="(certbot-auto only) prevent the certbot-auto script from" - " upgrading itself to newer released versions (default: Upgrade" - " automatically)") - helpful.add( - "automation", "--no-bootstrap", action="store_true", - default=flag_default("no_bootstrap"), - help="(certbot-auto only) prevent the certbot-auto script from" - " installing OS-level dependencies (default: Prompt to install " - " OS-wide dependencies, but exit if the user says 'No')") - helpful.add( - "automation", "--no-permissions-check", action="store_true", - default=flag_default("no_permissions_check"), - help="(certbot-auto only) skip the check on the file system" - " permissions of the certbot-auto script") helpful.add( ["automation", "renew", "certonly", "run"], "-q", "--quiet", dest="quiet", action="store_true", @@ -450,6 +430,12 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): default=flag_default("autorenew"), dest="autorenew", help="Disable auto renewal of certificates.") + # Deprecated arguments + helpful.add_deprecated_argument("--os-packages-only", 0) + helpful.add_deprecated_argument("--no-self-upgrade", 0) + helpful.add_deprecated_argument("--no-bootstrap", 0) + helpful.add_deprecated_argument("--no-permissions-check", 0) + # Populate the command line parameters for new style enhancements enhancements.populate_cli(helpful.add) @@ -471,6 +457,11 @@ def set_by_cli(var): (CLI or config file) including if the user explicitly set it to the default. Returns False if the variable was assigned a default value. """ + # We should probably never actually hit this code. But if we do, + # a deprecated option has logically never been set by the CLI. + if var in DEPRECATED_OPTIONS: + return False + detector = set_by_cli.detector # type: ignore if detector is None and helpful_parser is not None: # Setup on first run: `detector` is a weird version of config in which @@ -531,6 +522,9 @@ def option_was_set(option, value): :rtype: bool """ + # If an option is deprecated, it was effectively not set by the user. + if option in DEPRECATED_OPTIONS: + return False return set_by_cli(option) or not has_default_value(option, value) diff --git a/certbot/certbot/_internal/cli/cli_constants.py b/certbot/certbot/_internal/cli/cli_constants.py index 4bc84bfe7..bd25f9bee 100644 --- a/certbot/certbot/_internal/cli/cli_constants.py +++ b/certbot/certbot/_internal/cli/cli_constants.py @@ -105,3 +105,14 @@ VAR_MODIFIERS = {"account": {"server",}, "renew_hook": {"deploy_hook",}, "server": {"dry_run", "staging",}, "webroot_map": {"webroot_path",}} + +# This is a list of all CLI options that we have ever deprecated. It lets us +# opt out of the default detection, which can interact strangely with option +# deprecation. See https://github.com/certbot/certbot/issues/8540 for more info. +DEPRECATED_OPTIONS = { + "manual_public_ip_logging_ok", + "os_packages_only", + "no_self_upgrade", + "no_bootstrap", + "no_permissions_check", +} diff --git a/certbot/certbot/_internal/cli/helpful.py b/certbot/certbot/_internal/cli/helpful.py index 2cb506157..80afe5db4 100644 --- a/certbot/certbot/_internal/cli/helpful.py +++ b/certbot/certbot/_internal/cli/helpful.py @@ -7,7 +7,6 @@ import glob import sys import configargparse -import six import zope.component import zope.interface @@ -99,7 +98,7 @@ class HelpfulArgumentParser(object): if isinstance(help1, bool) and isinstance(help2, bool): self.help_arg = help1 or help2 else: - self.help_arg = help1 if isinstance(help1, six.string_types) else help2 + self.help_arg = help1 if isinstance(help1, str) else help2 short_usage = self._usage_string(plugins, self.help_arg) @@ -470,7 +469,7 @@ class HelpfulArgumentParser(object): may or may not be displayed as help topics. """ - for name, plugin_ep in six.iteritems(plugins): + for name, plugin_ep in plugins.items(): parser_or_group = self.add_group(name, description=plugin_ep.long_description) plugin_ep.plugin_cls.inject_parser_options(parser_or_group, name) diff --git a/certbot/certbot/_internal/configuration.py b/certbot/certbot/_internal/configuration.py index f1e85f9fe..1b5cf5da7 100644 --- a/certbot/certbot/_internal/configuration.py +++ b/certbot/certbot/_internal/configuration.py @@ -1,7 +1,7 @@ """Certbot user-supplied configuration.""" import copy +from urllib import parse -from six.moves.urllib import parse import zope.interface from certbot import errors diff --git a/certbot/certbot/_internal/plugins/disco.py b/certbot/certbot/_internal/plugins/disco.py index bed22b4ae..d19fdd3ef 100644 --- a/certbot/certbot/_internal/plugins/disco.py +++ b/certbot/certbot/_internal/plugins/disco.py @@ -3,9 +3,9 @@ import collections import itertools import logging import sys +from collections.abc import Mapping import pkg_resources -import six import zope.interface import zope.interface.verify @@ -15,12 +15,6 @@ from certbot import interfaces from certbot._internal import constants from certbot.compat import os -try: - # Python 3.3+ - from collections.abc import Mapping -except ImportError: # pragma: no cover - from collections import Mapping - logger = logging.getLogger(__name__) PREFIX_FREE_DISTRIBUTIONS = [ @@ -215,7 +209,7 @@ class PluginsRegistry(Mapping): # This prevents deadlock caused by plugins acquiring a lock # and ensures at least one concurrent Certbot instance will run # successfully. - self._plugins = collections.OrderedDict(sorted(six.iteritems(plugins))) + self._plugins = collections.OrderedDict(sorted(plugins.items())) @classmethod def find_all(cls): @@ -276,12 +270,12 @@ class PluginsRegistry(Mapping): def init(self, config): """Initialize all plugins in the registry.""" return [plugin_ep.init(config) for plugin_ep - in six.itervalues(self._plugins)] + in self._plugins.values()] def filter(self, pred): """Filter plugins based on predicate.""" return type(self)({name: plugin_ep for name, plugin_ep - in six.iteritems(self._plugins) if pred(plugin_ep)}) + in self._plugins.items() if pred(plugin_ep)}) def visible(self): """Filter plugins based on visibility.""" @@ -297,7 +291,7 @@ class PluginsRegistry(Mapping): def prepare(self): """Prepare all plugins in the registry.""" - return [plugin_ep.prepare() for plugin_ep in six.itervalues(self._plugins)] + return [plugin_ep.prepare() for plugin_ep in self._plugins.values()] def available(self): """Filter plugins based on availability.""" @@ -319,7 +313,7 @@ class PluginsRegistry(Mapping): """ # use list instead of set because PluginEntryPoint is not hashable - candidates = [plugin_ep for plugin_ep in six.itervalues(self._plugins) + candidates = [plugin_ep for plugin_ep in self._plugins.values() if plugin_ep.initialized and plugin_ep.init() is plugin] assert len(candidates) <= 1 if candidates: @@ -329,9 +323,9 @@ class PluginsRegistry(Mapping): def __repr__(self): return "{0}({1})".format( self.__class__.__name__, ','.join( - repr(p_ep) for p_ep in six.itervalues(self._plugins))) + repr(p_ep) for p_ep in self._plugins.values())) def __str__(self): if not self._plugins: return "No plugins" - return "\n\n".join(str(p_ep) for p_ep in six.itervalues(self._plugins)) + return "\n\n".join(str(p_ep) for p_ep in self._plugins.values()) diff --git a/certbot/certbot/_internal/plugins/selection.py b/certbot/certbot/_internal/plugins/selection.py index b4ece7b15..7ed174803 100644 --- a/certbot/certbot/_internal/plugins/selection.py +++ b/certbot/certbot/_internal/plugins/selection.py @@ -4,7 +4,6 @@ from __future__ import print_function import logging from typing import Optional, Tuple -import six import zope.component from certbot import errors @@ -110,7 +109,7 @@ def pick_plugin(config, default, plugins, question, ifaces): if len(prepared) > 1: logger.debug("Multiple candidate plugins: %s", prepared) - plugin_ep = choose_plugin(list(six.itervalues(prepared)), question) + plugin_ep = choose_plugin(list(prepared.values()), question) if plugin_ep is None: return None return plugin_ep.init() diff --git a/certbot/certbot/_internal/plugins/standalone.py b/certbot/certbot/_internal/plugins/standalone.py index bbb56178c..60c9558cb 100644 --- a/certbot/certbot/_internal/plugins/standalone.py +++ b/certbot/certbot/_internal/plugins/standalone.py @@ -6,7 +6,6 @@ import socket from socket import errno as socket_errors # type: ignore import OpenSSL # pylint: disable=unused-import -import six import zope.interface from acme import challenges @@ -183,7 +182,7 @@ class Authenticator(common.Plugin): for achall in achalls: if achall in server_achalls: server_achalls.remove(achall) - for port, servers in six.iteritems(self.servers.running()): + for port, servers in self.servers.running().items(): if not self.served[servers]: self.servers.stop(port) diff --git a/certbot/certbot/_internal/plugins/webroot.py b/certbot/certbot/_internal/plugins/webroot.py index 88e02998d..8789db604 100644 --- a/certbot/certbot/_internal/plugins/webroot.py +++ b/certbot/certbot/_internal/plugins/webroot.py @@ -4,7 +4,6 @@ import collections import json import logging -import six import zope.component import zope.interface @@ -92,7 +91,7 @@ to serve all files under specified web root ({0}).""" for achall in achalls: self.conf("map").setdefault(achall.domain, webroot_path) else: - known_webroots = list(set(six.itervalues(self.conf("map")))) + known_webroots = list(set(self.conf("map").values())) for achall in achalls: if achall.domain not in self.conf("map"): new_webroot = self._prompt_for_webroot(achall.domain, @@ -242,7 +241,7 @@ class _WebrootMapAction(argparse.Action): """Action class for parsing webroot_map.""" def __call__(self, parser, namespace, webroot_map, option_string=None): - for domains, webroot_path in six.iteritems(json.loads(webroot_map)): + for domains, webroot_path in json.loads(webroot_map).items(): webroot_path = _validate_webroot(webroot_path) namespace.webroot_map.update( (d, webroot_path) for d in cli.add_domains(namespace, domains)) diff --git a/certbot/certbot/_internal/renewal.py b/certbot/certbot/_internal/renewal.py index 3a550d355..9fe9cb546 100644 --- a/certbot/certbot/_internal/renewal.py +++ b/certbot/certbot/_internal/renewal.py @@ -13,7 +13,6 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import ec, rsa from cryptography.hazmat.primitives.serialization import load_pem_private_key import OpenSSL -import six import zope.component from acme.magic_typing import List @@ -85,6 +84,7 @@ def _reconstitute(config, full_path): return None # Now restore specific values along with their data types, if # those elements are present. + renewalparams = _remove_deprecated_config_elements(renewalparams) try: restore_required_config_elements(config, renewalparams) _restore_plugin_configs(config, renewalparams) @@ -119,7 +119,7 @@ def _restore_webroot_config(config, renewalparams): # see https://github.com/certbot/certbot/pull/7095 if "webroot_path" in renewalparams and not cli.set_by_cli("webroot_path"): wp = renewalparams["webroot_path"] - if isinstance(wp, six.string_types): # prior to 0.1.0, webroot_path was a string + if isinstance(wp, str): # prior to 0.1.0, webroot_path was a string wp = [wp] config.webroot_path = wp @@ -154,7 +154,7 @@ def _restore_plugin_configs(config, renewalparams): for plugin_prefix in set(plugin_prefixes): plugin_prefix = plugin_prefix.replace('-', '_') - for config_item, config_value in six.iteritems(renewalparams): + for config_item, config_value in renewalparams.items(): if config_item.startswith(plugin_prefix + "_") and not cli.set_by_cli(config_item): # Values None, True, and False need to be treated specially, # As their types aren't handled correctly by configobj @@ -179,15 +179,28 @@ def restore_required_config_elements(config, renewalparams): required_items = itertools.chain( (("pref_challs", _restore_pref_challs),), - six.moves.zip(BOOL_CONFIG_ITEMS, itertools.repeat(_restore_bool)), - six.moves.zip(INT_CONFIG_ITEMS, itertools.repeat(_restore_int)), - six.moves.zip(STR_CONFIG_ITEMS, itertools.repeat(_restore_str))) + zip(BOOL_CONFIG_ITEMS, itertools.repeat(_restore_bool)), + zip(INT_CONFIG_ITEMS, itertools.repeat(_restore_int)), + zip(STR_CONFIG_ITEMS, itertools.repeat(_restore_str))) for item_name, restore_func in required_items: if item_name in renewalparams and not cli.set_by_cli(item_name): value = restore_func(item_name, renewalparams[item_name]) setattr(config, item_name, value) +def _remove_deprecated_config_elements(renewalparams): + """Removes deprecated config options from the parsed renewalparams. + + :param dict renewalparams: list of parsed renewalparams + + :returns: list of renewalparams with deprecated config options removed + :rtype: dict + + """ + return {option_name: v for (option_name, v) in renewalparams.items() + if option_name not in cli.DEPRECATED_OPTIONS} + + def _restore_pref_challs(unused_name, value): """Restores preferred challenges from a renewal config file. @@ -206,7 +219,7 @@ def _restore_pref_challs(unused_name, value): # If pref_challs has only one element, configobj saves the value # with a trailing comma so it's parsed as a list. If this comma is # removed by the user, the value is parsed as a str. - value = [value] if isinstance(value, six.string_types) else value + value = [value] if isinstance(value, str) else value return cli.parse_preferred_challenges(value) diff --git a/certbot/certbot/_internal/reporter.py b/certbot/certbot/_internal/reporter.py index d781f3d9d..64c0fbd6d 100644 --- a/certbot/certbot/_internal/reporter.py +++ b/certbot/certbot/_internal/reporter.py @@ -3,10 +3,10 @@ from __future__ import print_function import collections import logging +import queue import sys import textwrap -from six.moves import queue # type: ignore import zope.interface from certbot import interfaces diff --git a/certbot/certbot/_internal/storage.py b/certbot/certbot/_internal/storage.py index ff58313e5..690567a17 100644 --- a/certbot/certbot/_internal/storage.py +++ b/certbot/certbot/_internal/storage.py @@ -9,7 +9,6 @@ import stat import configobj import parsedatetime import pytz -import six from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey from cryptography.hazmat.primitives.serialization import load_pem_private_key @@ -275,7 +274,7 @@ def relevant_values(all_values): rv = dict( (option, value) - for option, value in six.iteritems(all_values) + for option, value in all_values.items() if _relevant(namespaces, option) and cli.option_was_set(option, value)) # We always save the server value to help with forward compatibility # and behavioral consistency when versions of Certbot with different diff --git a/certbot/certbot/crypto_util.py b/certbot/certbot/crypto_util.py index edd4f9eb3..f67d95d97 100644 --- a/certbot/certbot/crypto_util.py +++ b/certbot/certbot/crypto_util.py @@ -22,7 +22,6 @@ from OpenSSL import crypto from OpenSSL import SSL # type: ignore import pyrfc3339 -import six import zope.component from acme import crypto_util as acme_crypto_util @@ -215,7 +214,7 @@ def make_key(bits=1024, key_type="rsa", elliptic_curve=None): except TypeError: raise errors.Error("Unsupported elliptic curve: {}".format(elliptic_curve)) except UnsupportedAlgorithm as e: - raise six.raise_from(e, errors.Error(str(e))) + raise e from errors.Error(str(e)) _key_pem = _key.private_bytes( encoding=Encoding.PEM, format=PrivateFormat.TraditionalOpenSSL, @@ -492,14 +491,9 @@ def _notAfterBefore(cert_path, method): reformatted_timestamp = [timestamp[0:4], b"-", timestamp[4:6], b"-", timestamp[6:8], b"T", timestamp[8:10], b":", timestamp[10:12], b":", timestamp[12:]] - # pyrfc3339 always uses the type `str`. This means that in Python 2, it - # expects str/bytes and in Python 3 it expects its str type or the Python 2 - # equivalent of the type unicode. + # pyrfc3339 always uses the type `str` timestamp_bytes = b"".join(reformatted_timestamp) - if six.PY3: - timestamp_str = timestamp_bytes.decode('ascii') - else: - timestamp_str = timestamp_bytes + timestamp_str = timestamp_bytes.decode('ascii') return pyrfc3339.parse(timestamp_str) diff --git a/certbot/certbot/display/util.py b/certbot/certbot/display/util.py index c48454637..9da981892 100644 --- a/certbot/certbot/display/util.py +++ b/certbot/certbot/display/util.py @@ -71,7 +71,7 @@ def _wrap_lines(msg): def input_with_timeout(prompt=None, timeout=36000.0): """Get user input with a timeout. - Behaves the same as six.moves.input, however, an error is raised if + Behaves the same as the builtin input, however, an error is raised if a user doesn't answer after timeout seconds. The default timeout value was chosen to place it just under 12 hours for users following our advice and running Certbot twice a day. @@ -85,7 +85,7 @@ def input_with_timeout(prompt=None, timeout=36000.0): :raises errors.Error if no answer is given before the timeout """ - # use of sys.stdin and sys.stdout to mimic six.moves.input based on + # use of sys.stdin and sys.stdout to mimic the builtin input based on # https://github.com/python/cpython/blob/baf7bb30a02aabde260143136bdf5b3738a1d409/Lib/getpass.py#L129 if prompt: sys.stdout.write(prompt) diff --git a/certbot/certbot/interfaces.py b/certbot/certbot/interfaces.py index 28c6f2ac1..ddbee8ddc 100644 --- a/certbot/certbot/interfaces.py +++ b/certbot/certbot/interfaces.py @@ -1,14 +1,12 @@ """Certbot client interfaces.""" import abc -import six import zope.interface # pylint: disable=no-self-argument,no-method-argument,inherit-non-class -@six.add_metaclass(abc.ABCMeta) -class AccountStorage(object): +class AccountStorage(object, metaclass=abc.ABCMeta): """Accounts storage interface.""" @abc.abstractmethod @@ -547,8 +545,7 @@ class IReporter(zope.interface.Interface): """Prints messages to the user and clears the message queue.""" -@six.add_metaclass(abc.ABCMeta) -class RenewableCert(object): +class RenewableCert(object, metaclass=abc.ABCMeta): """Interface to a certificate lineage.""" @abc.abstractproperty @@ -613,8 +610,7 @@ class RenewableCert(object): # an update during the run or install subcommand, it should do so when # :func:`IInstaller.deploy_cert` is called. -@six.add_metaclass(abc.ABCMeta) -class GenericUpdater(object): +class GenericUpdater(object, metaclass=abc.ABCMeta): """Interface for update types not currently specified by Certbot. This class allows plugins to perform types of updates that Certbot hasn't @@ -646,8 +642,7 @@ class GenericUpdater(object): """ -@six.add_metaclass(abc.ABCMeta) -class RenewDeployer(object): +class RenewDeployer(object, metaclass=abc.ABCMeta): """Interface for update types run when a lineage is renewed This class allows plugins to perform types of updates that need to run at diff --git a/certbot/certbot/plugins/dns_test_common.py b/certbot/certbot/plugins/dns_test_common.py index d5044d336..a3a26a7a1 100644 --- a/certbot/certbot/plugins/dns_test_common.py +++ b/certbot/certbot/plugins/dns_test_common.py @@ -6,7 +6,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock # type: ignore -import six from acme import challenges from certbot import achallenges @@ -31,7 +30,7 @@ class BaseAuthenticatorTest(object): challb=acme_util.DNS01, domain=DOMAIN, account_key=KEY) def test_more_info(self): - self.assertTrue(isinstance(self.auth.more_info(), six.string_types)) # pylint: disable=no-member + self.assertTrue(isinstance(self.auth.more_info(), str)) # pylint: disable=no-member def test_get_chall_pref(self): self.assertEqual(self.auth.get_chall_pref(None), [challenges.DNS01]) # pylint: disable=no-member diff --git a/certbot/certbot/plugins/enhancements.py b/certbot/certbot/plugins/enhancements.py index 4abce2d2f..e674c32a2 100644 --- a/certbot/certbot/plugins/enhancements.py +++ b/certbot/certbot/plugins/enhancements.py @@ -1,8 +1,6 @@ """New interface style Certbot enhancements""" import abc -import six - from acme.magic_typing import Any from acme.magic_typing import Dict from acme.magic_typing import List @@ -91,8 +89,7 @@ def populate_cli(add): help=enh["cli_help"]) -@six.add_metaclass(abc.ABCMeta) -class AutoHSTSEnhancement(object): +class AutoHSTSEnhancement(object, metaclass=abc.ABCMeta): """ Enhancement interface that installer plugins can implement in order to provide functionality that configures the software to have a diff --git a/certbot/certbot/reverter.py b/certbot/certbot/reverter.py index 58e1216b7..be9d78a11 100644 --- a/certbot/certbot/reverter.py +++ b/certbot/certbot/reverter.py @@ -7,7 +7,6 @@ import sys import time import traceback -import six from certbot import errors from certbot import util @@ -518,7 +517,7 @@ class Reverter(object): # It is possible save checkpoints faster than 1 per second resulting in # collisions in the naming convention. - for _ in six.moves.range(2): + for _ in range(2): timestamp = self._checkpoint_timestamp() final_dir = os.path.join(self.config.backup_dir, timestamp) try: diff --git a/certbot/certbot/tests/acme_util.py b/certbot/certbot/tests/acme_util.py index f4a20ea86..49ca88bf5 100644 --- a/certbot/certbot/tests/acme_util.py +++ b/certbot/certbot/tests/acme_util.py @@ -2,7 +2,6 @@ import datetime import josepy as jose -import six from acme import challenges from acme import messages @@ -69,7 +68,7 @@ def gen_authzr(authz_status, domain, challs, statuses, combos=True): """ challbs = tuple( chall_to_challb(chall, status) - for chall, status in six.moves.zip(challs, statuses) + for chall, status in zip(challs, statuses) ) authz_kwargs = { "identifier": messages.Identifier( diff --git a/certbot/certbot/tests/testdata/sample-renewal-deprecated-option.conf b/certbot/certbot/tests/testdata/sample-renewal-deprecated-option.conf new file mode 100644 index 000000000..2b777d3de --- /dev/null +++ b/certbot/certbot/tests/testdata/sample-renewal-deprecated-option.conf @@ -0,0 +1,14 @@ +# renew_before_expiry = 30 days +version = 1.11.0 +archive_dir = MAGICDIR/live/sample-renewal-deprecated-option +cert = MAGICDIR/live/sample-renewal-deprecated-option/cert.pem +privkey = MAGICDIR/live/sample-renewal-deprecated-option/privkey.pem +chain = MAGICDIR/live/sample-renewal-deprecated-option/chain.pem +fullchain = MAGICDIR/live/sample-renewal-deprecated-option/fullchain.pem + +# Options used in the renewal process +[renewalparams] +account = ffffffffffffffffffffffffffffffff +authenticator = nginx +installer = nginx +manual_public_ip_logging_ok = None diff --git a/certbot/certbot/tests/util.py b/certbot/certbot/tests/util.py index b9d5caa08..558bfbed3 100644 --- a/certbot/certbot/tests/util.py +++ b/certbot/certbot/tests/util.py @@ -1,4 +1,6 @@ """Test utilities.""" +from importlib import reload as reload_module +import io import logging from multiprocessing import Event from multiprocessing import Process @@ -6,18 +8,13 @@ import shutil import sys import tempfile import unittest +import warnings from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization import josepy as jose -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock # type: ignore import OpenSSL import pkg_resources -import six -from six.moves import reload_module from certbot import interfaces from certbot import util @@ -29,6 +26,18 @@ from certbot.compat import filesystem from certbot.compat import os from certbot.display import util as display_util +try: + import mock + warnings.warn( + "The external mock module is being used for backwards compatibility " + "since it is available, however, future versions of Certbot's tests will " + "use unittest.mock. Be sure to update your code accordingly.", + PendingDeprecationWarning + ) +except ImportError: # pragma: no cover + from unittest import mock # type: ignore + + def vector_path(*names): """Path to a test vector.""" @@ -170,7 +179,7 @@ def patch_get_utility_with_stdout(target='zope.component.getUtility', :rtype: mock.MagicMock """ - stdout = stdout if stdout else six.StringIO() + stdout = stdout if stdout else io.StringIO() freezable_mock = _create_get_utility_mock_with_stdout(stdout) return mock.patch(target, new=freezable_mock) diff --git a/certbot/certbot/util.py b/certbot/certbot/util.py index 8db5ab34a..7bbc02f5f 100644 --- a/certbot/certbot/util.py +++ b/certbot/certbot/util.py @@ -15,7 +15,6 @@ import subprocess import sys import configargparse -import six from acme.magic_typing import Text from acme.magic_typing import Tuple @@ -153,7 +152,7 @@ def lock_dir_until_exit(dir_path): def _release_locks(): - for dir_lock in six.itervalues(_LOCKS): + for dir_lock in _LOCKS.values(): try: dir_lock.release() except: # pylint: disable=bare-except @@ -517,7 +516,7 @@ def enforce_domain_sanity(domain): """ # Unicode try: - if isinstance(domain, six.binary_type): + if isinstance(domain, bytes): domain = domain.decode('utf-8') domain.encode('ascii') except UnicodeError: @@ -579,7 +578,7 @@ def is_wildcard_domain(domain): """ wildcard_marker = b"*." # type: Union[Text, bytes] - if isinstance(domain, six.text_type): + if isinstance(domain, str): wildcard_marker = u"*." return domain.startswith(wildcard_marker) diff --git a/certbot/docs/cli-help.txt b/certbot/docs/cli-help.txt index 4ba70587f..4482ea439 100644 --- a/certbot/docs/cli-help.txt +++ b/certbot/docs/cli-help.txt @@ -99,9 +99,9 @@ optional arguments: before submitting to CA (default: False) --preferred-chain PREFERRED_CHAIN If the CA offers multiple certificate chains, prefer - the chain with an issuer matching this Subject Common - Name. If no match, the default offered chain will be - used. (default: None) + the chain whose topmost certificate was issued from + this Subject Common Name. If no match, the default + offered chain will be used. (default: None) --preferred-challenges PREF_CHALLS A sorted, comma delimited list of the preferred challenge to use during authorization with the most @@ -118,7 +118,7 @@ optional arguments: case, and to know when to deprecate support for past Python versions and flags. If you wish to hide this information from the Let's Encrypt server, set this to - "". (default: CertbotACMEClient/1.11.0 + "". (default: CertbotACMEClient/1.12.0 (certbot(-auto); OS_NAME OS_VERSION) Authenticator/XXX Installer/YYY (SUBCOMMAND; flags: FLAGS) Py/major.minor.patchlevel). The flags encoded in the diff --git a/certbot/docs/conf.py b/certbot/docs/conf.py index 52820b69d..254bd3edd 100644 --- a/certbot/docs/conf.py +++ b/certbot/docs/conf.py @@ -97,7 +97,6 @@ language = None # directories to ignore when looking for source files. exclude_patterns = [ '_build', - 'man', 'challenges.rst', 'ciphers.rst' ] diff --git a/certbot/docs/contributing.rst b/certbot/docs/contributing.rst index ab07823f5..def2c7fcd 100644 --- a/certbot/docs/contributing.rst +++ b/certbot/docs/contributing.rst @@ -56,18 +56,18 @@ Set up the Python virtual environment that will host your Certbot local instance .. code-block:: shell cd certbot - python tools/venv3.py + python tools/venv.py .. note:: You may need to repeat this when Certbot's dependencies change or when a new plugin is introduced. You can now run the copy of Certbot from git either by executing -``venv3/bin/certbot``, or by activating the virtual environment. You can do the +``venv/bin/certbot``, or by activating the virtual environment. You can do the latter by running: .. code-block:: shell - source venv3/bin/activate + source venv/bin/activate After running this command, ``certbot`` and development tools like ``ipdb``, ``ipython``, ``pytest``, and ``tox`` are available in the shell where you ran @@ -169,7 +169,7 @@ To do so you need: - Docker installed, and a user with access to the Docker client, - an available `local copy`_ of Certbot. -The virtual environment set up with `python tools/venv3.py` contains two CLI tools +The virtual environment set up with `python tools/venv.py` contains two CLI tools that can be used once the virtual environment is activated: .. code-block:: shell @@ -197,8 +197,8 @@ using an HTTP-01 challenge on a machine with Python 3: .. code-block:: shell - python tools/venv3.py - source venv3/bin/activate + python tools/venv.py + source venv/bin/activate run_acme_server & certbot_test certonly --standalone -d test.example.com # To stop Pebble, launch `fg` to get back the background job, then press CTRL+C diff --git a/certbot/docs/install.rst b/certbot/docs/install.rst index 4366080e0..8ae1c82f2 100644 --- a/certbot/docs/install.rst +++ b/certbot/docs/install.rst @@ -191,7 +191,7 @@ Optionally to install the Certbot Apache plugin, you can use: .. code-block:: shell - sudo apt-get install python-certbot-apache + sudo apt-get install python3-certbot-apache **Fedora** diff --git a/certbot/docs/man/certbot.rst b/certbot/docs/man/certbot.rst index d03f3eed4..2f25504b0 100644 --- a/certbot/docs/man/certbot.rst +++ b/certbot/docs/man/certbot.rst @@ -1 +1,3 @@ +:orphan: + .. literalinclude:: ../cli-help.txt diff --git a/certbot/examples/cli.ini b/certbot/examples/cli.ini index dfb1d6fff..8471558ee 100644 --- a/certbot/examples/cli.ini +++ b/certbot/examples/cli.ini @@ -24,3 +24,11 @@ rsa-key-size = 4096 # path to the public_html / webroot folder being served by your web server. # authenticator = webroot # webroot-path = /usr/share/nginx/html + +# Uncomment to automatically agree to the terms of service of the ACME server +# agree-tos = true + +# An example of using an alternate ACME server that uses EAB credentials +# server = https://acme.sectigo.com/v2/InCommonRSAOV +# eab-kid = somestringofstuffwithoutquotes +# eab-hmac-key = yaddayaddahexhexnotquoted diff --git a/certbot/setup.py b/certbot/setup.py index e1c86308e..8b2874f20 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -31,9 +31,9 @@ meta = dict(re.findall(r"""__([a-z]+)__ = '([^']+)""", read_file(init_fn))) readme = read_file(os.path.join(here, 'README.rst')) version = meta['version'] -# This package relies on PyOpenSSL, requests, and six, however, it isn't -# specified here to avoid masking the more specific request requirements in -# acme. See https://github.com/pypa/pip/issues/988 for more info. +# This package relies on PyOpenSSL and requests, however, it isn't specified +# here to avoid masking the more specific request requirements in acme. See +# https://github.com/pypa/pip/issues/988 for more info. install_requires = [ 'acme>=1.8.0', # We technically need ConfigArgParse 0.10.0 for Python 2.6 support, but @@ -72,16 +72,14 @@ elif os.name == 'nt': # setuptools, pywin32 will not be specified as a dependency. install_requires.append(pywin32_req) -if setuptools_known_environment_markers: - install_requires.append('mock ; python_version < "3.3"') -elif 'bdist_wheel' in sys.argv[1:]: - raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' - 'of setuptools. Version 36.2+ of setuptools is required.') -elif sys.version_info < (3,3): - install_requires.append('mock') - dev_extras = [ + 'astroid', + 'azure-devops', 'coverage', + 'ipdb', + 'mypy', + 'PyGithub', + 'pylint', 'pytest', 'pytest-cov', 'pytest-xdist', @@ -90,15 +88,6 @@ dev_extras = [ 'wheel', ] -dev3_extras = [ - 'astroid', - 'azure-devops', - 'ipdb', - 'mypy', - 'PyGithub', - 'pylint', -] - docs_extras = [ # If you have Sphinx<1.5.1, you need docutils<0.13.1 # https://github.com/sphinx-doc/sphinx/issues/3212 @@ -144,7 +133,6 @@ setup( install_requires=install_requires, extras_require={ 'dev': dev_extras, - 'dev3': dev3_extras, 'docs': docs_extras, }, diff --git a/certbot/tests/account_test.py b/certbot/tests/account_test.py index f9c218cd3..d0448a1db 100644 --- a/certbot/tests/account_test.py +++ b/certbot/tests/account_test.py @@ -276,14 +276,14 @@ class AccountFileStorageTest(test_util.ConfigTestCase): self.storage.save(self.acc, self.mock_client) mock_open = mock.mock_open() mock_open.side_effect = IOError - with mock.patch("six.moves.builtins.open", mock_open): + with mock.patch("builtins.open", mock_open): self.assertRaises( errors.AccountStorageError, self.storage.load, self.acc.id) def test_save_ioerrors(self): mock_open = mock.mock_open() mock_open.side_effect = IOError # TODO: [None, None, IOError] - with mock.patch("six.moves.builtins.open", mock_open): + with mock.patch("builtins.open", mock_open): self.assertRaises( errors.AccountStorageError, self.storage.save, self.acc, self.mock_client) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index e65ec32ec..fca2b3e3e 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -1,16 +1,11 @@ """Tests for certbot._internal.cli.""" import argparse import copy +from importlib import reload as reload_module +import io import tempfile import unittest -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock -import six -from six.moves import reload_module # pylint: disable=import-error - from acme import challenges from certbot import errors from certbot._internal import cli @@ -21,6 +16,12 @@ from certbot.compat import os import certbot.tests.util as test_util from certbot.tests.util import TempDirTestCase +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + + PLUGINS = disco.PluginsRegistry.find_all() @@ -91,7 +92,7 @@ class ParseTest(unittest.TestCase): def _help_output(self, args): "Run a command, and return the output string for scrutiny" - output = six.StringIO() + output = io.StringIO() def write_msg(message, *args, **kwargs): # pylint: disable=missing-docstring,unused-argument output.write(message) @@ -479,10 +480,6 @@ class ParseTest(unittest.TestCase): for topic in ['all', 'plugins', 'dns-route53']: self.assertFalse('certbot-route53:auth' in self._help_output([help_flag, topic])) - def test_no_permissions_check_accepted(self): - namespace = self.parse(["--no-permissions-check"]) - self.assertTrue(namespace.no_permissions_check) - class DefaultTest(unittest.TestCase): """Tests for certbot._internal.cli._Default.""" diff --git a/certbot/tests/display/completer_test.py b/certbot/tests/display/completer_test.py index 0852ab175..8ae6290bf 100644 --- a/certbot/tests/display/completer_test.py +++ b/certbot/tests/display/completer_test.py @@ -3,19 +3,20 @@ try: import readline # pylint: disable=import-error except ImportError: import certbot._internal.display.dummy_readline as readline # type: ignore +from importlib import reload as reload_module import string import sys import unittest +from certbot.compat import filesystem # pylint: disable=ungrouped-imports +from certbot.compat import os # pylint: disable=ungrouped-imports +import certbot.tests.util as test_util # pylint: disable=ungrouped-imports + try: import mock except ImportError: # pragma: no cover from unittest import mock -from six.moves import reload_module # pylint: disable=import-error -from certbot.compat import filesystem # pylint: disable=ungrouped-imports -from certbot.compat import os # pylint: disable=ungrouped-imports -import certbot.tests.util as test_util # pylint: disable=ungrouped-imports class CompleterTest(test_util.TempDirTestCase): diff --git a/certbot/tests/display/util_test.py b/certbot/tests/display/util_test.py index 1b22d3422..30b33bbc9 100644 --- a/certbot/tests/display/util_test.py +++ b/certbot/tests/display/util_test.py @@ -1,20 +1,22 @@ """Test :mod:`certbot.display.util`.""" import inspect +import io import socket import tempfile import unittest -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock -import six from certbot import errors from certbot import interfaces from certbot.display import util as display_util import certbot.tests.util as test_util +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + + CHOICES = [("First", "Description1"), ("Second", "Description2")] TAGS = ["tag1", "tag2", "tag3"] TAGS_CHOICES = [("1", "tag1"), ("2", "tag2"), ("3", "tag3")] @@ -34,7 +36,7 @@ class InputWithTimeoutTest(unittest.TestCase): def test_input(self, prompt=None): expected = "foo bar" - stdin = six.StringIO(expected + "\n") + stdin = io.StringIO(expected + "\n") with mock.patch("certbot.compat.misc.select.select") as mock_select: mock_select.return_value = ([stdin], [], [],) self.assertEqual(self._call(prompt), expected) @@ -328,11 +330,7 @@ class FileOutputDisplayTest(unittest.TestCase): # Every IDisplay method implemented by FileDisplay must take # force_interactive to prevent workflow regressions. for name in interfaces.IDisplay.names(): - if six.PY2: - getargspec = inspect.getargspec - else: - getargspec = inspect.getfullargspec - arg_spec = getargspec(getattr(self.displayer, name)) # pylint: disable=deprecated-method + arg_spec = inspect.getfullargspec(getattr(self.displayer, name)) self.assertTrue("force_interactive" in arg_spec.args) @@ -402,12 +400,8 @@ class NoninteractiveDisplayTest(unittest.TestCase): for name in interfaces.IDisplay.names(): # pylint: disable=E1120 method = getattr(self.displayer, name) # asserts method accepts arbitrary keyword arguments - if six.PY2: - result = inspect.getargspec(method).keywords # pylint:deprecated-method - self.assertFalse(result is None) - else: - result = inspect.getfullargspec(method).varkw - self.assertFalse(result is None) + result = inspect.getfullargspec(method).varkw + self.assertFalse(result is None) class SeparateListInputTest(unittest.TestCase): diff --git a/certbot/tests/log_test.py b/certbot/tests/log_test.py index 76764e61b..088faa0fb 100644 --- a/certbot/tests/log_test.py +++ b/certbot/tests/log_test.py @@ -1,15 +1,11 @@ """Tests for certbot._internal.log.""" +import io import logging import logging.handlers import sys import time import unittest -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock -import six from acme import messages from certbot import errors @@ -19,6 +15,12 @@ from certbot.compat import filesystem from certbot.compat import os from certbot.tests import util as test_util +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + + class PreArgParseSetupTest(unittest.TestCase): """Tests for certbot._internal.log.pre_arg_parse_setup.""" @@ -75,7 +77,7 @@ class PostArgParseSetupTest(test_util.ConfigTestCase): self.devnull = open(os.devnull, 'w') from certbot._internal.log import ColoredStreamHandler - self.stream_handler = ColoredStreamHandler(six.StringIO()) + self.stream_handler = ColoredStreamHandler(io.StringIO()) from certbot._internal.log import MemoryHandler, TempHandler self.temp_handler = TempHandler() self.temp_path = self.temp_handler.path @@ -179,7 +181,7 @@ class ColoredStreamHandlerTest(unittest.TestCase): """Tests for certbot._internal.log.ColoredStreamHandler""" def setUp(self): - self.stream = six.StringIO() + self.stream = io.StringIO() self.stream.isatty = lambda: True self.logger = logging.getLogger() self.logger.setLevel(logging.DEBUG) @@ -213,7 +215,7 @@ class MemoryHandlerTest(unittest.TestCase): self.logger = logging.getLogger(__name__) self.logger.setLevel(logging.DEBUG) self.msg = 'hi there' - self.stream = six.StringIO() + self.stream = io.StringIO() self.stream_handler = logging.StreamHandler(self.stream) from certbot._internal.log import MemoryHandler @@ -238,7 +240,7 @@ class MemoryHandlerTest(unittest.TestCase): def test_target_reset(self): self._test_log_debug() - new_stream = six.StringIO() + new_stream = io.StringIO() new_stream_handler = logging.StreamHandler(new_stream) self.handler.setTarget(new_stream_handler) self.handler.flush(force=True) @@ -325,7 +327,7 @@ class PostArgParseExceptHookTest(unittest.TestCase): def test_acme_error(self): # Get an arbitrary error code - acme_code = next(six.iterkeys(messages.ERROR_CODES)) + acme_code = next(iter(messages.ERROR_CODES)) def get_acme_error(msg): """Wraps ACME errors so the constructor takes only a msg.""" @@ -349,7 +351,7 @@ class PostArgParseExceptHookTest(unittest.TestCase): def _test_common(self, error_type, debug): """Returns the mocked logger and stderr output.""" - mock_err = six.StringIO() + mock_err = io.StringIO() def write_err(*args, **unused_kwargs): """Write error to mock_err.""" diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index aaab5e313..badec5bd3 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -4,6 +4,8 @@ from __future__ import print_function import datetime +from importlib import reload as reload_module +import io import itertools import json import shutil @@ -13,13 +15,7 @@ import traceback import unittest import josepy as jose -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock import pytz -import six -from six.moves import reload_module # pylint: disable=import-error from certbot import crypto_util from certbot import errors @@ -39,6 +35,12 @@ from certbot.compat import os from certbot.plugins import enhancements import certbot.tests.util as test_util +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + + CERT_PATH = test_util.vector_path('cert_512.pem') CERT = test_util.vector_path('cert_512.pem') @@ -598,7 +600,7 @@ class MainTest(test_util.ConfigTestCase): "Run the client with output streams mocked out" args = self.standard_args + args - toy_stdout = stdout if stdout else six.StringIO() + toy_stdout = stdout if stdout else io.StringIO() with mock.patch('certbot._internal.main.sys.stdout', new=toy_stdout): with mock.patch('certbot._internal.main.sys.stderr') as stderr: with mock.patch("certbot.util.atexit"): @@ -611,8 +613,8 @@ class MainTest(test_util.ConfigTestCase): self.assertEqual(1, mock_run.call_count) def test_version_string_program_name(self): - toy_out = six.StringIO() - toy_err = six.StringIO() + toy_out = io.StringIO() + toy_err = io.StringIO() with mock.patch('certbot._internal.main.sys.stdout', new=toy_out): with mock.patch('certbot._internal.main.sys.stderr', new=toy_err): try: @@ -820,7 +822,7 @@ class MainTest(test_util.ConfigTestCase): flags = ['--init', '--prepare', '--authenticators', '--installers'] for args in itertools.chain( *(itertools.combinations(flags, r) - for r in six.moves.range(len(flags)))): + for r in range(len(flags)))): self._call(['plugins'] + list(args)) @mock.patch('certbot._internal.main.plugins_disco') @@ -829,7 +831,7 @@ class MainTest(test_util.ConfigTestCase): ifaces = [] # type: List[interfaces.IPlugin] plugins = mock_disco.PluginsRegistry.find_all() - stdout = six.StringIO() + stdout = io.StringIO() with test_util.patch_get_utility_with_stdout(stdout=stdout): _, stdout, _, _ = self._call(['plugins'], stdout) @@ -849,7 +851,7 @@ class MainTest(test_util.ConfigTestCase): _, _, _ = directory, mode, strict raise errors.Error() - stdout = six.StringIO() + stdout = io.StringIO() with mock.patch('certbot.util.set_up_core_dir') as mock_set_up_core_dir: with test_util.patch_get_utility_with_stdout(stdout=stdout): mock_set_up_core_dir.side_effect = throw_error @@ -866,7 +868,7 @@ class MainTest(test_util.ConfigTestCase): ifaces = [] # type: List[interfaces.IPlugin] plugins = mock_disco.PluginsRegistry.find_all() - stdout = six.StringIO() + stdout = io.StringIO() with test_util.patch_get_utility_with_stdout(stdout=stdout): _, stdout, _, _ = self._call(['plugins', '--init'], stdout) @@ -884,7 +886,7 @@ class MainTest(test_util.ConfigTestCase): ifaces = [] # type: List[interfaces.IPlugin] plugins = mock_disco.PluginsRegistry.find_all() - stdout = six.StringIO() + stdout = io.StringIO() with test_util.patch_get_utility_with_stdout(stdout=stdout): _, stdout, _, _ = self._call(['plugins', '--init', '--prepare'], stdout) @@ -1033,7 +1035,7 @@ class MainTest(test_util.ConfigTestCase): mock_certr = mock.MagicMock() mock_key = mock.MagicMock(pem='pem_key') mock_client = mock.MagicMock() - stdout = six.StringIO() + stdout = io.StringIO() mock_client.obtain_certificate.return_value = (mock_certr, 'chain', mock_key, 'csr') diff --git a/certbot/tests/plugins/disco_test.py b/certbot/tests/plugins/disco_test.py index ed13544de..a97de24b9 100644 --- a/certbot/tests/plugins/disco_test.py +++ b/certbot/tests/plugins/disco_test.py @@ -8,7 +8,6 @@ try: except ImportError: # pragma: no cover from unittest import mock import pkg_resources -import six import zope.interface from certbot import errors @@ -56,7 +55,7 @@ class PluginEntryPointTest(unittest.TestCase): EP_SA: "sa", } - for entry_point, name in six.iteritems(names): + for entry_point, name in names.items(): self.assertEqual( name, PluginEntryPoint.entry_point_to_plugin_name(entry_point, with_prefix=False)) @@ -70,7 +69,7 @@ class PluginEntryPointTest(unittest.TestCase): self.ep3: "p3:ep3", } - for entry_point, name in six.iteritems(names): + for entry_point, name in names.items(): self.assertEqual( name, PluginEntryPoint.entry_point_to_plugin_name(entry_point, with_prefix=True)) diff --git a/certbot/tests/plugins/manual_test.py b/certbot/tests/plugins/manual_test.py index 7318783fd..f3c580517 100644 --- a/certbot/tests/plugins/manual_test.py +++ b/certbot/tests/plugins/manual_test.py @@ -6,7 +6,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock -import six from acme import challenges from certbot import errors @@ -53,7 +52,7 @@ class AuthenticatorTest(test_util.TempDirTestCase): self.assertRaises(errors.HookCommandNotFound, self.auth.prepare) def test_more_info(self): - self.assertTrue(isinstance(self.auth.more_info(), six.string_types)) + self.assertTrue(isinstance(self.auth.more_info(), str)) def test_get_chall_pref(self): self.assertEqual(self.auth.get_chall_pref('example.org'), diff --git a/certbot/tests/plugins/null_test.py b/certbot/tests/plugins/null_test.py index 47708e340..dad5b270a 100644 --- a/certbot/tests/plugins/null_test.py +++ b/certbot/tests/plugins/null_test.py @@ -5,7 +5,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock -import six class InstallerTest(unittest.TestCase): @@ -16,7 +15,7 @@ class InstallerTest(unittest.TestCase): self.installer = Installer(config=mock.MagicMock(), name="null") def test_it(self): - self.assertTrue(isinstance(self.installer.more_info(), six.string_types)) + self.assertTrue(isinstance(self.installer.more_info(), str)) self.assertEqual([], self.installer.get_all_names()) self.assertEqual([], self.installer.supported_enhancements()) diff --git a/certbot/tests/plugins/standalone_test.py b/certbot/tests/plugins/standalone_test.py index 751b9d943..596cee622 100644 --- a/certbot/tests/plugins/standalone_test.py +++ b/certbot/tests/plugins/standalone_test.py @@ -10,7 +10,6 @@ try: except ImportError: # pragma: no cover from unittest import mock import OpenSSL.crypto # pylint: disable=unused-import -import six from acme import challenges from acme import standalone as acme_standalone # pylint: disable=unused-import @@ -91,7 +90,7 @@ class AuthenticatorTest(unittest.TestCase): self.auth.servers = mock.MagicMock() def test_more_info(self): - self.assertTrue(isinstance(self.auth.more_info(), six.string_types)) + self.assertTrue(isinstance(self.auth.more_info(), str)) def test_get_chall_pref(self): self.assertEqual(self.auth.get_chall_pref(domain=None), diff --git a/certbot/tests/plugins/storage_test.py b/certbot/tests/plugins/storage_test.py index 4b0d1da83..2999d306e 100644 --- a/certbot/tests/plugins/storage_test.py +++ b/certbot/tests/plugins/storage_test.py @@ -33,7 +33,7 @@ class PluginStorageTest(test_util.ConfigTestCase): mock_open.side_effect = IOError self.plugin.storage.storagepath = os.path.join(self.config.config_dir, ".pluginstorage.json") - with mock.patch("six.moves.builtins.open", mock_open): + with mock.patch("builtins.open", mock_open): with mock.patch('certbot.compat.os.path.isfile', return_value=True): with mock.patch("certbot.reverter.util"): self.assertRaises(errors.PluginStorageError, diff --git a/certbot/tests/plugins/webroot_test.py b/certbot/tests/plugins/webroot_test.py index e57e09eae..e6fbd8e88 100644 --- a/certbot/tests/plugins/webroot_test.py +++ b/certbot/tests/plugins/webroot_test.py @@ -14,7 +14,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock -import six from acme import challenges from certbot import achallenges @@ -59,7 +58,7 @@ class AuthenticatorTest(unittest.TestCase): def test_more_info(self): more_info = self.auth.more_info() - self.assertTrue(isinstance(more_info, six.string_types)) + self.assertTrue(isinstance(more_info, str)) self.assertTrue(self.path in more_info) def test_add_parser_arguments(self): @@ -83,7 +82,7 @@ class AuthenticatorTest(unittest.TestCase): self.assertTrue(self.achall.domain in call[0][0]) self.assertTrue(all( webroot in call[0][1] - for webroot in six.itervalues(self.config.webroot_map))) + for webroot in self.config.webroot_map.values())) self.assertEqual(self.config.webroot_map[self.achall.domain], self.path) @@ -100,7 +99,7 @@ class AuthenticatorTest(unittest.TestCase): self.assertTrue(self.achall.domain in call[0][0]) self.assertTrue(all( webroot in call[0][1] - for webroot in six.itervalues(self.config.webroot_map))) + for webroot in self.config.webroot_map.values())) @test_util.patch_get_utility() def test_new_webroot(self, mock_get_utility): diff --git a/certbot/tests/renewal_test.py b/certbot/tests/renewal_test.py index 4af8c6e7f..7c9c53fb4 100644 --- a/certbot/tests/renewal_test.py +++ b/certbot/tests/renewal_test.py @@ -1,4 +1,6 @@ """Tests for certbot._internal.renewal""" +import copy + import unittest try: @@ -98,6 +100,23 @@ class RenewalTest(test_util.ConfigTestCase): assert self.config.elliptic_curve == 'secp256r1' + @test_util.patch_get_utility() + @mock.patch('certbot._internal.renewal.cli.set_by_cli') + def test_remove_deprecated_config_elements(self, mock_set_by_cli, unused_mock_get_utility): + mock_set_by_cli.return_value = False + config = configuration.NamespaceConfig(self.config) + config.certname = "sample-renewal-deprecated-option" + + rc_path = test_util.make_lineage( + self.config.config_dir, 'sample-renewal-deprecated-option.conf') + + from certbot._internal import renewal + lineage_config = copy.deepcopy(self.config) + renewal_candidate = renewal._reconstitute(lineage_config, rc_path) + # This means that manual_public_ip_logging_ok was not modified in the config based on its + # value in the renewal conf file + self.assertTrue(isinstance(lineage_config.manual_public_ip_logging_ok, mock.MagicMock)) + class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase): """Tests for certbot._internal.renewal.restore_required_config_elements.""" diff --git a/certbot/tests/reporter_test.py b/certbot/tests/reporter_test.py index 7d03f1821..7a37f782e 100644 --- a/certbot/tests/reporter_test.py +++ b/certbot/tests/reporter_test.py @@ -1,12 +1,13 @@ """Tests for certbot._internal.reporter.""" +import io import sys import unittest + try: import mock except ImportError: # pragma: no cover from unittest import mock -import six class ReporterTest(unittest.TestCase): @@ -16,7 +17,7 @@ class ReporterTest(unittest.TestCase): self.reporter = reporter.Reporter(mock.MagicMock(quiet=False)) self.old_stdout = sys.stdout # type: ignore - sys.stdout = six.StringIO() + sys.stdout = io.StringIO() def tearDown(self): sys.stdout = self.old_stdout diff --git a/certbot/tests/reverter_test.py b/certbot/tests/reverter_test.py index d67aa431a..af01a9a1b 100644 --- a/certbot/tests/reverter_test.py +++ b/certbot/tests/reverter_test.py @@ -9,7 +9,6 @@ try: import mock except ImportError: # pragma: no cover from unittest import mock -import six from certbot import errors from certbot.compat import os @@ -156,7 +155,7 @@ class ReverterCheckpointLocalTest(test_util.ConfigTestCase): act_coms = get_undo_commands(self.config.temp_checkpoint_dir) - for a_com, com in six.moves.zip(act_coms, coms): + for a_com, com in zip(act_coms, coms): self.assertEqual(a_com, com) def test_bad_register_undo_command(self): diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index 9ae26532f..abd496c8d 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -11,7 +11,6 @@ try: except ImportError: # pragma: no cover from unittest import mock import pytz -import six import certbot from certbot import errors @@ -77,6 +76,17 @@ class RelevantValuesTest(unittest.TestCase): self.assertEqual(self._call(self.values), expected_relevant_values) + @mock.patch("certbot._internal.cli.set_by_cli") + def test_deprecated_item(self, unused_mock_set_by_cli): + # deprecated items should never be relevant to store + expected_relevant_values = self.values.copy() + self.values["manual_public_ip_logging_ok"] = None + self.assertEqual(self._call(self.values), expected_relevant_values) + self.values["manual_public_ip_logging_ok"] = True + self.assertEqual(self._call(self.values), expected_relevant_values) + self.values["manual_public_ip_logging_ok"] = False + self.assertEqual(self._call(self.values), expected_relevant_values) + class BaseRenewableCertTest(test_util.ConfigTestCase): """Base class for setting up Renewable Cert tests. @@ -275,7 +285,7 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertEqual(self.test_rc.current_version("cert"), None) def test_latest_and_next_versions(self): - for ver in six.moves.range(1, 6): + for ver in range(1, 6): for kind in ALL_FOUR: self._write_out_kind(kind, ver) self.assertEqual(self.test_rc.latest_common_version(), 5) @@ -315,7 +325,7 @@ class RenewableCertTests(BaseRenewableCertTest): def test_update_link_to(self): - for ver in six.moves.range(1, 6): + for ver in range(1, 6): for kind in ALL_FOUR: self._write_out_kind(kind, ver) self.assertEqual(ver, self.test_rc.current_version(kind)) @@ -342,12 +352,12 @@ class RenewableCertTests(BaseRenewableCertTest): os.path.basename(self.test_rc.version("cert", 8))) def test_update_all_links_to_success(self): - for ver in six.moves.range(1, 6): + for ver in range(1, 6): for kind in ALL_FOUR: self._write_out_kind(kind, ver) self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(self.test_rc.latest_common_version(), 5) - for ver in six.moves.range(1, 6): + for ver in range(1, 6): self.test_rc.update_all_links_to(ver) for kind in ALL_FOUR: self.assertEqual(ver, self.test_rc.current_version(kind)) @@ -385,11 +395,11 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertEqual(self.test_rc.current_version(kind), 11) def test_has_pending_deployment(self): - for ver in six.moves.range(1, 6): + for ver in range(1, 6): for kind in ALL_FOUR: self._write_out_kind(kind, ver) self.assertEqual(ver, self.test_rc.current_version(kind)) - for ver in six.moves.range(1, 6): + for ver in range(1, 6): self.test_rc.update_all_links_to(ver) for kind in ALL_FOUR: self.assertEqual(ver, self.test_rc.current_version(kind)) @@ -487,7 +497,7 @@ class RenewableCertTests(BaseRenewableCertTest): # (to avoid instantiating parser) mock_rv.side_effect = lambda x: x - for ver in six.moves.range(1, 6): + for ver in range(1, 6): for kind in ALL_FOUR: self._write_out_kind(kind, ver) self.test_rc.update_all_links_to(3) @@ -518,7 +528,7 @@ class RenewableCertTests(BaseRenewableCertTest): self.test_rc.version("privkey", i)))) for kind in ALL_FOUR: - self.assertEqual(self.test_rc.available_versions(kind), list(six.moves.range(1, 9))) + self.assertEqual(self.test_rc.available_versions(kind), list(range(1, 9))) self.assertEqual(self.test_rc.current_version(kind), 3) # Test updating from latest version rather than old version self.test_rc.update_all_links_to(8) @@ -527,7 +537,7 @@ class RenewableCertTests(BaseRenewableCertTest): b'attempt', self.config)) for kind in ALL_FOUR: self.assertEqual(self.test_rc.available_versions(kind), - list(six.moves.range(1, 10))) + list(range(1, 10))) self.assertEqual(self.test_rc.current_version(kind), 8) with open(self.test_rc.version("fullchain", 9)) as f: self.assertEqual(f.read(), "last" + "attempt") diff --git a/certbot/tests/util_test.py b/certbot/tests/util_test.py index 7b510fbb6..18947c342 100644 --- a/certbot/tests/util_test.py +++ b/certbot/tests/util_test.py @@ -1,21 +1,22 @@ """Tests for certbot.util.""" import argparse import errno +from importlib import reload as reload_module +import io import sys import unittest -try: - import mock -except ImportError: # pragma: no cover - from unittest import mock -import six -from six.moves import reload_module # pylint: disable=import-error - from certbot import errors from certbot.compat import filesystem from certbot.compat import os import certbot.tests.util as test_util +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + + class EnvNoSnapForExternalCallsTest(unittest.TestCase): """Tests for certbot.util.env_no_snap_for_external_calls.""" @@ -265,11 +266,11 @@ class UniqueLineageNameTest(test_util.TempDirTestCase): def test_multiple(self): items = [] - for _ in six.moves.range(10): + for _ in range(10): items.append(self._call("wow")) f, name = items[-1] self.assertTrue(isinstance(f, file_type)) - self.assertTrue(isinstance(name, six.string_types)) + self.assertTrue(isinstance(name, str)) self.assertTrue("wow-0009.conf" in name) for f, _ in items: f.close() @@ -361,7 +362,7 @@ class AddDeprecatedArgumentTest(unittest.TestCase): def test_help(self): self._call("--old-option", 2) - stdout = six.StringIO() + stdout = io.StringIO() with mock.patch("sys.stdout", new=stdout): try: self.parser.parse_args(["-h"]) diff --git a/letsencrypt-auto b/letsencrypt-auto index e8012439a..002fd5ffc 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then fi VENV_BIN="$VENV_PATH/bin" BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt" -LE_AUTO_VERSION="1.11.0" +LE_AUTO_VERSION="1.12.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -803,6 +803,7 @@ if [ -f /etc/debian_version ]; then elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/redhat-release ]; then DEPRECATED_OS=1 # Run DeterminePythonVersion to decide on the basis of available Python versions @@ -863,22 +864,31 @@ elif [ -f /etc/redhat-release ]; then LE_PYTHON="$prev_le_python" elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/arch-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/manjaro-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/gentoo-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq FreeBSD ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq Darwin ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 else DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 fi # We handle this case after determining the normal bootstrap version to allow @@ -1107,7 +1117,9 @@ if [ "$1" = "--le-auto-phase2" ]; then fi if [ -f "$VENV_BIN/letsencrypt" -a "$INSTALL_ONLY" != 1 ]; then - error "Certbot will no longer receive updates." + error "certbot-auto and its Certbot installation will no longer receive updates." + error "You will not receive any bug fixes including those fixing server compatibility" + error "or security problems." error "Please visit https://certbot.eff.org/ to check for other alternatives." "$VENV_BIN/letsencrypt" "$@" exit 0 @@ -1475,18 +1487,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.11.0 \ - --hash=sha256:b7faa66c40a1ce5a31bfc8668d8feb5d2db6f7af9e791079a6d95c77b6593bf4 \ - --hash=sha256:6b0ce04e55379aff0a47f873fa05c084538ad0f4a9b79f33108dbb0a7a668b43 -acme==1.11.0 \ - --hash=sha256:77d6ce61b155315d7d7031489bbd245c0ea42c0453a04d4304393414e741a56d \ - --hash=sha256:092eb09a074a935da4c10f66cb8634ffb2cc2d2cc1035d2998d608996efab924 -certbot-apache==1.11.0 \ - --hash=sha256:ea7ac88733aad91a89c700289effda2a0c0658778da1ae2c54a0aefaee351285 \ - --hash=sha256:3ed001427ec0b49324f2b9af7170fa6e6e88948fa51c3678b07bf17f8138863d -certbot-nginx==1.11.0 \ - --hash=sha256:79de69782a1199e577787ff9790dee02a44aac17dbecd6a7287593030842a306 \ - --hash=sha256:9afe611f99a78b8898941b8ad7bdcf7f3c2b6e0fce27125268f7c713e64b34ee +certbot==1.12.0 \ + --hash=sha256:f4bb3da5391e4a28e9a2e52ab54986171c0864feff17eaaaca6729a1d4c433a6 \ + --hash=sha256:5ee738773479bcb7794e43fedd2415acc0969b75bdd2a21f451e3bff9d99df59 +acme==1.12.0 \ + --hash=sha256:ca4ad044429f1b8b670b958e5c7ea38159def9d601f4af2359355993918c3317 \ + --hash=sha256:aa363474d50e9fdda27acb8b1aa7efb26fecc5650e02039a0de3a3f0e696c2f2 +certbot-apache==1.12.0 \ + --hash=sha256:38899f6fa08799de9535795d919acf968f288d7208909baf7733f9a763c15227 \ + --hash=sha256:e5679b40d99bd241f4fcd9fe44b73e6e25ccc969a617131ff6ebc90d562a49f2 +certbot-nginx==1.12.0 \ + --hash=sha256:332cd70067bbcf6db52a002650ffa4844d0bd9780279d662aa6725b43f776c14 \ + --hash=sha256:3fb6a55290d37ad466681a89a85ceca4c4026fdd8702f3010b87a74266a6fe7b UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index 524293e31..aba5f1140 100644 --- a/letsencrypt-auto-source/certbot-auto.asc +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl/0pwwACgkQTRfJlc2X -dfL4eQf+MyI6XGuG9jKbfRRfYWNjc3B4nxjvpeaOys6ZNIFoI5sElR/8siv6lexc -iDZ0h6PkIfh4NkIOQJQqgGP885P4aPZBg1mOTnssa6u3+1R3QRb/L/QcppysQZnf -Jve+94Zpkz1r2pF8KI4mZYDl5iN01TrMlQLddEeWOzY1tzoEVBq19KBEUwnk8awt -WOxKfhITFPbU2jyR5O4przDJLGsqG6WC6etCbmWYnb/he3pWa70ITsv2a1RCoTDf -EsBb5QVa3SEw+NT3jyE9P3FothSQZyvsYojd6/B4/bwZarWwqh1mTMz55U2rJl87 -XpjglPXfhrv/s5oWNWthXTpz+11xvA== -=nhC8 +iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAmAZorcACgkQTRfJlc2X +dfI6Ogf+LFASyH9sgTV1k9hs1zbmO3CxyE9QQs1JLXpoKOQ1tKv+v+kpt+lJ005g +rielyRSssXtZSyfLchCSBh6qaEBodoOcz8RS2z7rDnR9jKOJv252Buh2oSa3KPmn +WPjRmB3zVXnhq/XmPKQTnoflUlBg+MtZuZXt0Fvu8rvQB+RY3AUfB5Xs83nxJNj4 +W9qNpZYl0sJWWiydr23bEk35MJSt62sKDvyqIVjUfgDfXHmauOpg0foz2xS6XP8i +Ke66GUKaQ1ap2BTucwVT0hieXiQZpxx1PitUeEOjOH9PUfrAxyFlQ0XQaVlqoBhc +YM3nzJw9yf12b+XCUvMzHyQmDA5vdQ== +=AUGt -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 4ff1ddae9..224abaf01 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then fi VENV_BIN="$VENV_PATH/bin" BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt" -LE_AUTO_VERSION="1.12.0.dev0" +LE_AUTO_VERSION="1.13.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -803,8 +803,10 @@ if [ -f /etc/debian_version ]; then elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/redhat-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 # Run DeterminePythonVersion to decide on the basis of available Python versions # whether to use 2.x or 3.x on RedHat-like systems. # Then, revert LE_PYTHON to its previous state. @@ -863,22 +865,31 @@ elif [ -f /etc/redhat-release ]; then LE_PYTHON="$prev_le_python" elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/arch-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/manjaro-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/gentoo-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq FreeBSD ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq Darwin ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 else DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 fi # We handle this case after determining the normal bootstrap version to allow @@ -1107,7 +1118,9 @@ if [ "$1" = "--le-auto-phase2" ]; then fi if [ -f "$VENV_BIN/letsencrypt" -a "$INSTALL_ONLY" != 1 ]; then - error "Certbot will no longer receive updates." + error "certbot-auto and its Certbot installation will no longer receive updates." + error "You will not receive any bug fixes including those fixing server compatibility" + error "or security problems." error "Please visit https://certbot.eff.org/ to check for other alternatives." "$VENV_BIN/letsencrypt" "$@" exit 0 @@ -1475,18 +1488,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.11.0 \ - --hash=sha256:b7faa66c40a1ce5a31bfc8668d8feb5d2db6f7af9e791079a6d95c77b6593bf4 \ - --hash=sha256:6b0ce04e55379aff0a47f873fa05c084538ad0f4a9b79f33108dbb0a7a668b43 -acme==1.11.0 \ - --hash=sha256:77d6ce61b155315d7d7031489bbd245c0ea42c0453a04d4304393414e741a56d \ - --hash=sha256:092eb09a074a935da4c10f66cb8634ffb2cc2d2cc1035d2998d608996efab924 -certbot-apache==1.11.0 \ - --hash=sha256:ea7ac88733aad91a89c700289effda2a0c0658778da1ae2c54a0aefaee351285 \ - --hash=sha256:3ed001427ec0b49324f2b9af7170fa6e6e88948fa51c3678b07bf17f8138863d -certbot-nginx==1.11.0 \ - --hash=sha256:79de69782a1199e577787ff9790dee02a44aac17dbecd6a7287593030842a306 \ - --hash=sha256:9afe611f99a78b8898941b8ad7bdcf7f3c2b6e0fce27125268f7c713e64b34ee +certbot==1.12.0 \ + --hash=sha256:f4bb3da5391e4a28e9a2e52ab54986171c0864feff17eaaaca6729a1d4c433a6 \ + --hash=sha256:5ee738773479bcb7794e43fedd2415acc0969b75bdd2a21f451e3bff9d99df59 +acme==1.12.0 \ + --hash=sha256:ca4ad044429f1b8b670b958e5c7ea38159def9d601f4af2359355993918c3317 \ + --hash=sha256:aa363474d50e9fdda27acb8b1aa7efb26fecc5650e02039a0de3a3f0e696c2f2 +certbot-apache==1.12.0 \ + --hash=sha256:38899f6fa08799de9535795d919acf968f288d7208909baf7733f9a763c15227 \ + --hash=sha256:e5679b40d99bd241f4fcd9fe44b73e6e25ccc969a617131ff6ebc90d562a49f2 +certbot-nginx==1.12.0 \ + --hash=sha256:332cd70067bbcf6db52a002650ffa4844d0bd9780279d662aa6725b43f776c14 \ + --hash=sha256:3fb6a55290d37ad466681a89a85ceca4c4026fdd8702f3010b87a74266a6fe7b UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index 3674e3a78..ac143de51 100644 Binary files a/letsencrypt-auto-source/letsencrypt-auto.sig and b/letsencrypt-auto-source/letsencrypt-auto.sig differ diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index bc27469fb..70b75176e 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -325,8 +325,10 @@ if [ -f /etc/debian_version ]; then elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/redhat-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 # Run DeterminePythonVersion to decide on the basis of available Python versions # whether to use 2.x or 3.x on RedHat-like systems. # Then, revert LE_PYTHON to its previous state. @@ -385,22 +387,31 @@ elif [ -f /etc/redhat-release ]; then LE_PYTHON="$prev_le_python" elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/arch-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/manjaro-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/gentoo-release ]; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq FreeBSD ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif uname | grep -iq Darwin ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 else DEPRECATED_OS=1 + NO_SELF_UPGRADE=1 fi # We handle this case after determining the normal bootstrap version to allow @@ -521,7 +532,9 @@ if [ "$1" = "--le-auto-phase2" ]; then fi if [ -f "$VENV_BIN/letsencrypt" -a "$INSTALL_ONLY" != 1 ]; then - error "Certbot will no longer receive updates." + error "certbot-auto and its Certbot installation will no longer receive updates." + error "You will not receive any bug fixes including those fixing server compatibility" + error "or security problems." error "Please visit https://certbot.eff.org/ to check for other alternatives." "$VENV_BIN/letsencrypt" "$@" exit 0 diff --git a/letsencrypt-auto-source/pieces/certbot-requirements.txt b/letsencrypt-auto-source/pieces/certbot-requirements.txt index 67ec23be3..4d4c91a5d 100644 --- a/letsencrypt-auto-source/pieces/certbot-requirements.txt +++ b/letsencrypt-auto-source/pieces/certbot-requirements.txt @@ -1,12 +1,12 @@ -certbot==1.11.0 \ - --hash=sha256:b7faa66c40a1ce5a31bfc8668d8feb5d2db6f7af9e791079a6d95c77b6593bf4 \ - --hash=sha256:6b0ce04e55379aff0a47f873fa05c084538ad0f4a9b79f33108dbb0a7a668b43 -acme==1.11.0 \ - --hash=sha256:77d6ce61b155315d7d7031489bbd245c0ea42c0453a04d4304393414e741a56d \ - --hash=sha256:092eb09a074a935da4c10f66cb8634ffb2cc2d2cc1035d2998d608996efab924 -certbot-apache==1.11.0 \ - --hash=sha256:ea7ac88733aad91a89c700289effda2a0c0658778da1ae2c54a0aefaee351285 \ - --hash=sha256:3ed001427ec0b49324f2b9af7170fa6e6e88948fa51c3678b07bf17f8138863d -certbot-nginx==1.11.0 \ - --hash=sha256:79de69782a1199e577787ff9790dee02a44aac17dbecd6a7287593030842a306 \ - --hash=sha256:9afe611f99a78b8898941b8ad7bdcf7f3c2b6e0fce27125268f7c713e64b34ee +certbot==1.12.0 \ + --hash=sha256:f4bb3da5391e4a28e9a2e52ab54986171c0864feff17eaaaca6729a1d4c433a6 \ + --hash=sha256:5ee738773479bcb7794e43fedd2415acc0969b75bdd2a21f451e3bff9d99df59 +acme==1.12.0 \ + --hash=sha256:ca4ad044429f1b8b670b958e5c7ea38159def9d601f4af2359355993918c3317 \ + --hash=sha256:aa363474d50e9fdda27acb8b1aa7efb26fecc5650e02039a0de3a3f0e696c2f2 +certbot-apache==1.12.0 \ + --hash=sha256:38899f6fa08799de9535795d919acf968f288d7208909baf7733f9a763c15227 \ + --hash=sha256:e5679b40d99bd241f4fcd9fe44b73e6e25ccc969a617131ff6ebc90d562a49f2 +certbot-nginx==1.12.0 \ + --hash=sha256:332cd70067bbcf6db52a002650ffa4844d0bd9780279d662aa6725b43f776c14 \ + --hash=sha256:3fb6a55290d37ad466681a89a85ceca4c4026fdd8702f3010b87a74266a6fe7b diff --git a/pytest.ini b/pytest.ini index 16aa9a193..d7fe53494 100644 --- a/pytest.ini +++ b/pytest.ini @@ -2,8 +2,6 @@ # settings we want to also change there must be added to the release script # directly. [pytest] -# In general, all warnings are treated as errors. Here are the exceptions: -# 1- decodestring: https://github.com/rthalley/dnspython/issues/338 # Warnings being triggered by our plugins using deprecated features in # acme/certbot should be fixed by having our plugins no longer using the # deprecated code rather than adding them to the list of ignored warnings here. @@ -13,4 +11,3 @@ # we release breaking changes. filterwarnings = error - ignore:decodestring:DeprecationWarning diff --git a/tests/letstest/multitester.py b/tests/letstest/multitester.py index 5ad1d8c15..83a92e6dc 100644 --- a/tests/letstest/multitester.py +++ b/tests/letstest/multitester.py @@ -39,11 +39,11 @@ import socket import sys import time import traceback +import urllib.error as urllib_error +import urllib.request as urllib_request import boto3 from botocore.exceptions import ClientError -from six.moves.urllib import error as urllib_error -from six.moves.urllib import request as urllib_request import yaml from fabric import Config diff --git a/tests/letstest/scripts/set_python_envvars.sh b/tests/letstest/scripts/set_python_envvars.sh deleted file mode 100755 index 668444209..000000000 --- a/tests/letstest/scripts/set_python_envvars.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -# This is a simple script that can be sourced to set Python environment -# variables for use in Certbot's letstest test farm tests. - -# Some distros like Fedora may only have an executable named python3 installed. -if command -v python; then - PYTHON_NAME="python" - VENV_SCRIPT="tools/venv.py" - VENV_PATH="venv" -else - # We could check for "python2" here, however, the addition of "python3" - # only systems is what necessitated this change so checking for "python2" - # isn't necessary. - PYTHON_NAME="python3" - VENV_PATH="venv3" - VENV_SCRIPT="tools/venv3.py" -fi diff --git a/tests/letstest/scripts/test_apache2.sh b/tests/letstest/scripts/test_apache2.sh index 247191610..77dc35f1e 100755 --- a/tests/letstest/scripts/test_apache2.sh +++ b/tests/letstest/scripts/test_apache2.sh @@ -64,7 +64,7 @@ if [ $? -ne 0 ] ; then exit 1 fi -tools/venv3.py -e acme[dev] -e certbot[dev,docs] -e certbot-apache -e certbot-ci +tools/venv.py -e acme[dev] -e certbot[dev,docs] -e certbot-apache -e certbot-ci PEBBLE_LOGS="acme_server.log" PEBBLE_URL="https://localhost:14000/dir" # We configure Pebble to use port 80 for http-01 validation rather than an @@ -73,7 +73,7 @@ PEBBLE_URL="https://localhost:14000/dir" # and closer to the default configuration on various OSes. # 2) As of writing this, Certbot's Apache plugin requires there to be an # existing virtual host for the port used for http-01 validation. -venv3/bin/run_acme_server --http-01-port 80 > "${PEBBLE_LOGS}" 2>&1 & +venv/bin/run_acme_server --http-01-port 80 > "${PEBBLE_LOGS}" 2>&1 & DumpPebbleLogs() { if [ -f "${PEBBLE_LOGS}" ] ; then @@ -96,7 +96,7 @@ if ! curl --insecure "${PEBBLE_URL}" 2>/dev/null; then exit 1 fi -sudo "venv3/bin/certbot" -v --debug --text --agree-tos --no-verify-ssl \ +sudo "venv/bin/certbot" -v --debug --text --agree-tos --no-verify-ssl \ --renew-by-default --redirect --register-unsafely-without-email \ --domain "${PUBLIC_HOSTNAME}" --server "${PEBBLE_URL}" if [ $? -ne 0 ] ; then @@ -113,7 +113,7 @@ elif [ "$OS_TYPE" = "centos" ]; then fi OPENSSL_VERSION=$(strings "$MOD_SSL_LOCATION" | egrep -o -m1 '^OpenSSL ([0-9]\.[^ ]+) ' | tail -c +9) APACHE_VERSION=$(sudo $APACHE_NAME -v | egrep -o 'Apache/([0-9]\.[^ ]+)' | tail -c +8) -"venv3/bin/python" tests/letstest/scripts/test_openssl_version.py "$OPENSSL_VERSION" "$APACHE_VERSION" +"venv/bin/python" tests/letstest/scripts/test_openssl_version.py "$OPENSSL_VERSION" "$APACHE_VERSION" if [ $? -ne 0 ] ; then FAIL=1 fi @@ -121,7 +121,7 @@ fi if [ "$OS_TYPE" = "ubuntu" ] ; then export SERVER="${PEBBLE_URL}" - "venv3/bin/tox" -e apacheconftest + "venv/bin/tox" -e apacheconftest else echo Not running hackish apache tests on $OS_TYPE fi diff --git a/tests/letstest/scripts/test_leauto_upgrades.sh b/tests/letstest/scripts/test_leauto_upgrades.sh index c599623cb..407a865f2 100755 --- a/tests/letstest/scripts/test_leauto_upgrades.sh +++ b/tests/letstest/scripts/test_leauto_upgrades.sh @@ -33,19 +33,22 @@ if ! ./letsencrypt-auto -v --debug --version --no-self-upgrade 2>&1 | tail -n1 | exit 1 fi -# This script sets the environment variables PYTHON_NAME, VENV_PATH, and -# VENV_SCRIPT based on the version of Python available on the system. For -# instance, Fedora uses Python 3 and Python 2 is not installed. -. tests/letstest/scripts/set_python_envvars.sh +if command -v python; then + PYTHON_NAME="python" +else + PYTHON_NAME="python3" +fi # Now that python and openssl have been installed, we can set up a fake server # to provide a new version of letsencrypt-auto. First, we start the server and # directory to be served. MY_TEMP_DIR=$(mktemp -d) PORT_FILE="$MY_TEMP_DIR/port" +LOG_FILE="$MY_TEMP_DIR/log" SERVER_PATH=$("$PYTHON_NAME" tools/readlink.py tools/simple_http_server.py) cd "$MY_TEMP_DIR" -"$PYTHON_NAME" "$SERVER_PATH" 0 > $PORT_FILE & +# We set PYTHONUNBUFFERED to disable buffering of output to LOG_FILE +PYTHONUNBUFFERED=1 "$PYTHON_NAME" "$SERVER_PATH" 0 > $PORT_FILE 2> "$LOG_FILE" & SERVER_PID=$! trap 'kill "$SERVER_PID" && rm -rf "$MY_TEMP_DIR"' EXIT cd ~- @@ -119,3 +122,48 @@ if ! diff letsencrypt-auto letsencrypt-auto-source/letsencrypt-auto ; then echo letsencrypt-auto and letsencrypt-auto-source/letsencrypt-auto differ exit 1 fi + +# Now let's test if letsencrypt-auto still tries to upgrade to a new version. +# Regardless of the OS, versions of the script with development version numbers +# ending in .dev0 will not upgrade. See +# https://github.com/certbot/certbot/blob/bdfb9f19c4086a60ef010d2431768850c26d838a/certbot-auto#L1947-L1948. +# In order to test the process of different OSes setting NO_SELF_UPGRADE as +# part of the script's deprecation, we make use of the fact that +# letsencrypt-auto should still attempt to fetch the version number from PyPI +# even if it has a development version number unless NO_SELF_UPGRADE is set in +# which case all of that logic should be skipped. +# +# First we make a copy of the current server logs. +PREVIOUS_LOG_FILE="$MY_TEMP_DIR/previous-log" +cp "$LOG_FILE" "$PREVIOUS_LOG_FILE" + +# Next we run letsencrypt-auto and make sure there were no problems checking +# for updates, the Certbot install still works, the version number is what +# we expect, and it prints a message about not receiving updates. +if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python" ; then + echo "Had problems checking for updates!" + exit 1 +fi +if ! ./letsencrypt-auto -v --debug --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then + echo unexpected certbot version found + exit 1 +fi +if ! ./letsencrypt-auto -v --debug --version 2>&1 | grep "will no longer receive updates" ; then + echo script did not print warning about not receiving updates! + exit 1 +fi + +# Finally, we check if our local server received more requests. Over time, +# we'll move more and more OSes into this case until it this is the expected +# behavior on all systems. +if [ -f /etc/redhat-release ]; then + if ! diff "$LOG_FILE" "$PREVIOUS_LOG_FILE" ; then + echo our local server received unexpected requests + exit 1 + fi +else + if diff "$LOG_FILE" "$PREVIOUS_LOG_FILE" ; then + echo our local server did not receive the requests we expected + exit 1 + fi +fi diff --git a/tests/letstest/scripts/test_sdists.sh b/tests/letstest/scripts/test_sdists.sh index a038caff6..aa12d5610 100755 --- a/tests/letstest/scripts/test_sdists.sh +++ b/tests/letstest/scripts/test_sdists.sh @@ -3,7 +3,7 @@ cd letsencrypt BOOTSTRAP_SCRIPT="tests/letstest/scripts/bootstrap_os_packages.sh" -VENV_PATH=venv3 +VENV_PATH=venv # install OS packages sudo $BOOTSTRAP_SCRIPT @@ -18,7 +18,7 @@ python3 tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirem # marker that'd normally prevent it from being installed, and this package is # not needed for any OS tested here. sed -i '/enum34/d' requirements.txt -CERTBOT_PIP_NO_BINARY=:all: tools/venv3.py --requirement requirements.txt +CERTBOT_PIP_NO_BINARY=:all: tools/venv.py --requirement requirements.txt . "$VENV_PATH/bin/activate" # pytest is needed to run tests on some of our packages so we install a pinned version here. tools/pip_install.py pytest diff --git a/tests/letstest/scripts/test_tests.sh b/tests/letstest/scripts/test_tests.sh index f07e3b78e..858fc1f18 100755 --- a/tests/letstest/scripts/test_tests.sh +++ b/tests/letstest/scripts/test_tests.sh @@ -9,9 +9,9 @@ LE_AUTO="$REPO_ROOT/letsencrypt-auto-source/letsencrypt-auto" LE_AUTO="$LE_AUTO --debug --no-self-upgrade --non-interactive" MODULES="acme certbot certbot-apache certbot-nginx" PIP_INSTALL="tools/pip_install.py" -VENV_NAME=venv3 +VENV_NAME=venv BOOTSTRAP_SCRIPT="$REPO_ROOT/tests/letstest/scripts/bootstrap_os_packages.sh" -VENV_SCRIPT="tools/venv3.py" +VENV_SCRIPT="tools/venv.py" sudo $BOOTSTRAP_SCRIPT diff --git a/tools/_venv_common.py b/tools/_venv_common.py deleted file mode 100644 index 58c05ed09..000000000 --- a/tools/_venv_common.py +++ /dev/null @@ -1,244 +0,0 @@ -#!/usr/bin/env python -"""Aids in creating a developer virtual environment for Certbot. - -When this module is run as a script, it takes the arguments that should -be passed to pip to install the Certbot packages as command line -arguments. The virtual environment will be created with the name "venv" -in the current working directory and will use the default version of -Python for the virtualenv executable in your PATH. You can change the -name of the virtual environment by setting the environment variable -VENV_NAME. -""" - -from __future__ import print_function - -from distutils.version import LooseVersion -import glob -import os -import re -import shutil -import subprocess -import sys -import time - -REQUIREMENTS = [ - '-e acme[dev]', - '-e certbot[dev,docs]', - '-e certbot-apache', - '-e certbot-dns-cloudflare', - '-e certbot-dns-cloudxns', - '-e certbot-dns-digitalocean', - '-e certbot-dns-dnsimple', - '-e certbot-dns-dnsmadeeasy', - '-e certbot-dns-gehirn', - '-e certbot-dns-google', - '-e certbot-dns-linode', - '-e certbot-dns-luadns', - '-e certbot-dns-nsone', - '-e certbot-dns-ovh', - '-e certbot-dns-rfc2136', - '-e certbot-dns-route53', - '-e certbot-dns-sakuracloud', - '-e certbot-nginx', - '-e certbot-compatibility-test', - '-e certbot-ci', -] - -VERSION_PATTERN = re.compile(r'^(\d+)\.(\d+).*$') - - -class PythonExecutableNotFoundError(Exception): - pass - - -def find_python_executable(python_major): - # type: (int) -> str - """ - Find the relevant python executable that is of the given python major version. - Will test, in decreasing priority order: - - * the current Python interpreter - * 'pythonX' executable in PATH (with X the given major version) if available - * 'python' executable in PATH if available - * Windows Python launcher 'py' executable in PATH if available - - Incompatible python versions for Certbot will be evicted (e.g. Python 3 - versions less than 3.6). - - :param int python_major: the Python major version to target (2 or 3) - :rtype: str - :return: the relevant python executable path - :raise RuntimeError: if no relevant python executable path could be found - """ - python_executable_path = None - - # First try, current python executable - if _check_version('{0}.{1}.{2}'.format( - sys.version_info[0], sys.version_info[1], sys.version_info[2]), python_major): - return sys.executable - - # Second try, with python executables in path - versions_to_test = ['2.7', '2', ''] if python_major == 2 else ['3', ''] - for one_version in versions_to_test: - try: - one_python = 'python{0}'.format(one_version) - output = subprocess.check_output([one_python, '--version'], - universal_newlines=True, stderr=subprocess.STDOUT) - if _check_version(output.strip().split()[1], python_major): - return subprocess.check_output([one_python, '-c', - 'import sys; sys.stdout.write(sys.executable);'], - universal_newlines=True) - except (subprocess.CalledProcessError, OSError): - pass - - # Last try, with Windows Python launcher - try: - env_arg = '-{0}'.format(python_major) - output_version = subprocess.check_output(['py', env_arg, '--version'], - universal_newlines=True, stderr=subprocess.STDOUT) - if _check_version(output_version.strip().split()[1], python_major): - return subprocess.check_output(['py', env_arg, '-c', - 'import sys; sys.stdout.write(sys.executable);'], - universal_newlines=True) - except (subprocess.CalledProcessError, OSError): - pass - - if not python_executable_path: - raise RuntimeError('Error, no compatible Python {0} executable for Certbot could be found.' - .format(python_major)) - - -def _check_version(version_str, major_version): - search = VERSION_PATTERN.search(version_str) - - if not search: - return False - - version = (int(search.group(1)), int(search.group(2))) - - minimal_version_supported = (2, 7) - if major_version == 3: - minimal_version_supported = (3, 6) - - if version >= minimal_version_supported: - return True - - print('Incompatible python version for Certbot found: {0}'.format(version_str)) - return False - - -def subprocess_with_print(cmd, env=None, shell=False): - if env is None: - env = os.environ - print('+ {0}'.format(subprocess.list2cmdline(cmd)) if isinstance(cmd, list) else cmd) - subprocess.check_call(cmd, env=env, shell=shell) - - -def subprocess_output_with_print(cmd, env=None, shell=False): - if env is None: - env = os.environ - print('+ {0}'.format(subprocess.list2cmdline(cmd)) if isinstance(cmd, list) else cmd) - return subprocess.check_output(cmd, env=env, shell=shell) - - -def get_venv_python_path(venv_path): - python_linux = os.path.join(venv_path, 'bin/python') - if os.path.isfile(python_linux): - return os.path.abspath(python_linux) - python_windows = os.path.join(venv_path, 'Scripts\\python.exe') - if os.path.isfile(python_windows): - return os.path.abspath(python_windows) - - raise ValueError(( - 'Error, could not find python executable in venv path {0}: is it a valid venv ?' - .format(venv_path))) - - -def prepare_venv_path(venv_name): - """Determines the venv path and prepares it for use. - - This function cleans up any Python eggs in the current working directory - and ensures the venv path is available for use. The path used is the - VENV_NAME environment variable if it is set and venv_name otherwise. If - there is already a directory at the desired path, the existing directory is - renamed by appending a timestamp to the directory name. - - :param str venv_name: The name or path at where the virtual - environment should be created if VENV_NAME isn't set. - - :returns: path where the virtual environment should be created - :rtype: str - - """ - for path in glob.glob('*.egg-info'): - if os.path.isdir(path): - shutil.rmtree(path) - else: - os.remove(path) - - env_venv_name = os.environ.get('VENV_NAME') - if env_venv_name: - print('Creating venv at {0}' - ' as specified in VENV_NAME'.format(env_venv_name)) - venv_name = env_venv_name - - if os.path.isdir(venv_name): - os.rename(venv_name, '{0}.{1}.bak'.format(venv_name, int(time.time()))) - - return venv_name - - -def install_packages(venv_name, pip_args): - """Installs packages in the given venv. - - :param str venv_name: The name or path at where the virtual - environment should be created. - :param pip_args: Command line arguments that should be given to - pip to install packages - :type pip_args: `list` of `str` - - """ - # Using the python executable from venv, we ensure to execute following commands in this venv. - py_venv = get_venv_python_path(venv_name) - subprocess_with_print([py_venv, os.path.abspath('tools/pipstrap.py')]) - # We only use this value during pip install because: - # 1) We're really only adding it for installing cryptography, which happens here, and - # 2) There are issues with calling it along with VIRTUALENV_NO_DOWNLOAD, which applies at the - # steps above, not during pip install. - env_pip_no_binary = os.environ.get('CERTBOT_PIP_NO_BINARY') - if env_pip_no_binary: - # Check OpenSSL version. If it's too low, don't apply the env variable. - openssl_version_string = str(subprocess_output_with_print(['openssl', 'version'])) - matches = re.findall(r'OpenSSL ([^ ]+) ', openssl_version_string) - if not matches: - print('Could not find OpenSSL version, not setting PIP_NO_BINARY.') - else: - openssl_version = matches[0] - - if LooseVersion(openssl_version) >= LooseVersion('1.0.2'): - print('Setting PIP_NO_BINARY to {0}' - ' as specified in CERTBOT_PIP_NO_BINARY'.format(env_pip_no_binary)) - os.environ['PIP_NO_BINARY'] = env_pip_no_binary - else: - print('Not setting PIP_NO_BINARY, as OpenSSL version is too old.') - command = [py_venv, os.path.abspath('tools/pip_install.py')] - command.extend(pip_args) - subprocess_with_print(command) - if 'PIP_NO_BINARY' in os.environ: - del os.environ['PIP_NO_BINARY'] - - if os.path.isdir(os.path.join(venv_name, 'bin')): - # Linux/OSX specific - print('-------------------------------------------------------------------') - print('Please run the following command to activate developer environment:') - print('source {0}/bin/activate'.format(venv_name)) - print('-------------------------------------------------------------------') - elif os.path.isdir(os.path.join(venv_name, 'Scripts')): - # Windows specific - print('---------------------------------------------------------------------------') - print('Please run one of the following commands to activate developer environment:') - print('{0}\\Scripts\\activate.bat (for Batch)'.format(venv_name)) - print('.\\{0}\\Scripts\\Activate.ps1 (for Powershell)'.format(venv_name)) - print('---------------------------------------------------------------------------') - else: - raise ValueError('Error, directory {0} is not a valid venv.'.format(venv_name)) diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index 1aabf6eeb..f6528f396 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -47,7 +47,7 @@ pyparsing==2.2.0 apacheconfig==0.3.2 cloudflare==1.5.1 python-digitalocean==1.11 -requests[security]==2.6.0 +requests==2.6.0 # Ubuntu Xenial constraints # Ubuntu Xenial only has versions of Python which we do not support available diff --git a/tools/venv.py b/tools/venv.py index f99386eff..9f7488008 100755 --- a/tools/venv.py +++ b/tools/venv.py @@ -1,36 +1,261 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Developer virtualenv setup for Certbot client -import os -import sys +"""Aids in creating a developer virtual environment for Certbot. -import _venv_common +When this module is run as a script, it takes the arguments that should +be passed to pip to install the Certbot packages as command line +arguments. If no arguments are provided, all Certbot packages and their +development dependencies are installed. The virtual environment will be +created with the name "venv" in the current working directory. You can +change the name of the virtual environment by setting the environment +variable VENV_NAME. + +""" + +from __future__ import print_function + +from distutils.version import LooseVersion +import glob +import os +import re +import shutil +import subprocess +import sys +import time + +REQUIREMENTS = [ + '-e acme[dev]', + '-e certbot[dev,docs]', + '-e certbot-apache', + '-e certbot-dns-cloudflare', + '-e certbot-dns-cloudxns', + '-e certbot-dns-digitalocean', + '-e certbot-dns-dnsimple', + '-e certbot-dns-dnsmadeeasy', + '-e certbot-dns-gehirn', + '-e certbot-dns-google', + '-e certbot-dns-linode', + '-e certbot-dns-luadns', + '-e certbot-dns-nsone', + '-e certbot-dns-ovh', + '-e certbot-dns-rfc2136', + '-e certbot-dns-route53', + '-e certbot-dns-sakuracloud', + '-e certbot-nginx', + '-e certbot-compatibility-test', + '-e certbot-ci', +] + +VERSION_PATTERN = re.compile(r'^(\d+)\.(\d+).*$') + + +class PythonExecutableNotFoundError(Exception): + pass + + +def find_python_executable() -> str: + """ + Find the relevant python executable that is of the given python major version. + Will test, in decreasing priority order: + + * the current Python interpreter + * 'pythonX' executable in PATH (with X the given major version) if available + * 'python' executable in PATH if available + * Windows Python launcher 'py' executable in PATH if available + + Incompatible python versions for Certbot will be evicted (e.g. Python 3 + versions less than 3.6). + + :rtype: str + :return: the relevant python executable path + :raise RuntimeError: if no relevant python executable path could be found + """ + python_executable_path = None + + # First try, current python executable + if _check_version('{0}.{1}.{2}'.format( + sys.version_info[0], sys.version_info[1], sys.version_info[2])): + return sys.executable + + # Second try, with python executables in path + for one_version in ('3', '',): + try: + one_python = 'python{0}'.format(one_version) + output = subprocess.check_output([one_python, '--version'], + universal_newlines=True, stderr=subprocess.STDOUT) + if _check_version(output.strip().split()[1]): + return subprocess.check_output([one_python, '-c', + 'import sys; sys.stdout.write(sys.executable);'], + universal_newlines=True) + except (subprocess.CalledProcessError, OSError): + pass + + # Last try, with Windows Python launcher + try: + output_version = subprocess.check_output(['py', '-3', '--version'], + universal_newlines=True, stderr=subprocess.STDOUT) + if _check_version(output_version.strip().split()[1]): + return subprocess.check_output(['py', env_arg, '-c', + 'import sys; sys.stdout.write(sys.executable);'], + universal_newlines=True) + except (subprocess.CalledProcessError, OSError): + pass + + if not python_executable_path: + raise RuntimeError('Error, no compatible Python executable for Certbot could be found.') + + +def _check_version(version_str): + search = VERSION_PATTERN.search(version_str) + + if not search: + return False + + version = (int(search.group(1)), int(search.group(2))) + + if version >= (3, 6): + return True + + print('Incompatible python version for Certbot found: {0}'.format(version_str)) + return False + + +def subprocess_with_print(cmd, env=None, shell=False): + if env is None: + env = os.environ + print('+ {0}'.format(subprocess.list2cmdline(cmd)) if isinstance(cmd, list) else cmd) + subprocess.check_call(cmd, env=env, shell=shell) + + +def subprocess_output_with_print(cmd, env=None, shell=False): + if env is None: + env = os.environ + print('+ {0}'.format(subprocess.list2cmdline(cmd)) if isinstance(cmd, list) else cmd) + return subprocess.check_output(cmd, env=env, shell=shell) + + +def get_venv_python_path(venv_path): + python_linux = os.path.join(venv_path, 'bin/python') + if os.path.isfile(python_linux): + return os.path.abspath(python_linux) + python_windows = os.path.join(venv_path, 'Scripts\\python.exe') + if os.path.isfile(python_windows): + return os.path.abspath(python_windows) + + raise ValueError(( + 'Error, could not find python executable in venv path {0}: is it a valid venv ?' + .format(venv_path))) + + +def prepare_venv_path(venv_name): + """Determines the venv path and prepares it for use. + + This function cleans up any Python eggs in the current working directory + and ensures the venv path is available for use. The path used is the + VENV_NAME environment variable if it is set and venv_name otherwise. If + there is already a directory at the desired path, the existing directory is + renamed by appending a timestamp to the directory name. + + :param str venv_name: The name or path at where the virtual + environment should be created if VENV_NAME isn't set. + + :returns: path where the virtual environment should be created + :rtype: str + + """ + for path in glob.glob('*.egg-info'): + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.remove(path) + + env_venv_name = os.environ.get('VENV_NAME') + if env_venv_name: + print('Creating venv at {0}' + ' as specified in VENV_NAME'.format(env_venv_name)) + venv_name = env_venv_name + + if os.path.isdir(venv_name): + os.rename(venv_name, '{0}.{1}.bak'.format(venv_name, int(time.time()))) + + return venv_name + + +def install_packages(venv_name, pip_args): + """Installs packages in the given venv. + + :param str venv_name: The name or path at where the virtual + environment should be created. + :param pip_args: Command line arguments that should be given to + pip to install packages + :type pip_args: `list` of `str` + + """ + # Using the python executable from venv, we ensure to execute following commands in this venv. + py_venv = get_venv_python_path(venv_name) + subprocess_with_print([py_venv, os.path.abspath('tools/pipstrap.py')]) + # We only use this value during pip install because: + # 1) We're really only adding it for installing cryptography, which happens here, and + # 2) There are issues with calling it along with VIRTUALENV_NO_DOWNLOAD, which applies at the + # steps above, not during pip install. + env_pip_no_binary = os.environ.get('CERTBOT_PIP_NO_BINARY') + if env_pip_no_binary: + # Check OpenSSL version. If it's too low, don't apply the env variable. + openssl_version_string = str(subprocess_output_with_print(['openssl', 'version'])) + matches = re.findall(r'OpenSSL ([^ ]+) ', openssl_version_string) + if not matches: + print('Could not find OpenSSL version, not setting PIP_NO_BINARY.') + else: + openssl_version = matches[0] + + if LooseVersion(openssl_version) >= LooseVersion('1.0.2'): + print('Setting PIP_NO_BINARY to {0}' + ' as specified in CERTBOT_PIP_NO_BINARY'.format(env_pip_no_binary)) + os.environ['PIP_NO_BINARY'] = env_pip_no_binary + else: + print('Not setting PIP_NO_BINARY, as OpenSSL version is too old.') + command = [py_venv, os.path.abspath('tools/pip_install.py')] + command.extend(pip_args) + subprocess_with_print(command) + if 'PIP_NO_BINARY' in os.environ: + del os.environ['PIP_NO_BINARY'] + + if os.path.isdir(os.path.join(venv_name, 'bin')): + # Linux/OSX specific + print('-------------------------------------------------------------------') + print('Please run the following command to activate developer environment:') + print('source {0}/bin/activate'.format(venv_name)) + print('-------------------------------------------------------------------') + elif os.path.isdir(os.path.join(venv_name, 'Scripts')): + # Windows specific + print('---------------------------------------------------------------------------') + print('Please run one of the following commands to activate developer environment:') + print('{0}\\Scripts\\activate.bat (for Batch)'.format(venv_name)) + print('.\\{0}\\Scripts\\Activate.ps1 (for Powershell)'.format(venv_name)) + print('---------------------------------------------------------------------------') + else: + raise ValueError('Error, directory {0} is not a valid venv.'.format(venv_name)) def create_venv(venv_path): - """Create a Python 2 virtual environment at venv_path. + """Create a Python virtual environment at venv_path. :param str venv_path: path where the venv should be created """ - python2 = _venv_common.find_python_executable(2) - command = [sys.executable, '-m', 'virtualenv', '--python', python2, venv_path] - - environ = os.environ.copy() - environ['VIRTUALENV_NO_DOWNLOAD'] = '1' - _venv_common.subprocess_with_print(command, environ) + python = find_python_executable() + command = [python, '-m', 'venv', venv_path] + subprocess_with_print(command) def main(pip_args=None): - if os.name == 'nt': - raise ValueError('Certbot for Windows is not supported on Python 2.x.') - - venv_path = _venv_common.prepare_venv_path('venv') + venv_path = prepare_venv_path('venv') create_venv(venv_path) if not pip_args: - pip_args = _venv_common.REQUIREMENTS + pip_args = REQUIREMENTS - _venv_common.install_packages(venv_path, pip_args) + install_packages(venv_path, pip_args) if __name__ == '__main__': diff --git a/tools/venv3.py b/tools/venv3.py deleted file mode 100755 index 7ead82bd5..000000000 --- a/tools/venv3.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -# Developer virtualenv setup for Certbot client -import sys - -import _venv_common - - -def create_venv(venv_path): - """Create a Python 3 virtual environment at venv_path. - - :param str venv_path: path where the venv should be created - - """ - python3 = _venv_common.find_python_executable(3) - command = [python3, '-m', 'venv', venv_path] - _venv_common.subprocess_with_print(command) - - -def main(pip_args=None): - venv_path = _venv_common.prepare_venv_path('venv3') - create_venv(venv_path) - - if not pip_args: - pip_args = _venv_common.REQUIREMENTS + ['-e certbot[dev3]'] - - _venv_common.install_packages(venv_path, pip_args) - - -if __name__ == '__main__': - main(sys.argv[1:]) diff --git a/tox.ini b/tox.ini index 94cd305aa..9f63b897c 100644 --- a/tox.ini +++ b/tox.ini @@ -137,6 +137,11 @@ commands = setenv = {[testenv:oldest]setenv} +[testenv:external-mock] +commands = + python {toxinidir}/tools/pip_install.py mock + {[base]install_and_test} {[base]all_packages} + [testenv:lint] basepython = python3 # separating into multiple invocations disables cross package @@ -144,14 +149,12 @@ basepython = python3 # continue, but tox return code will reflect previous error commands = {[base]install_packages} - {[base]pip_install} certbot[dev3] python -m pylint --reports=n --rcfile=.pylintrc {[base]source_paths} [testenv:mypy] basepython = python3 commands = {[base]install_packages} - {[base]pip_install} certbot[dev3] mypy {[base]source_paths} [testenv:apacheconftest]