diff --git a/.pep8 b/.pep8 new file mode 100644 index 000000000..22045d3d3 --- /dev/null +++ b/.pep8 @@ -0,0 +1,4 @@ +[pep8] +# E265 block comment should start with '# ' +# E501 line too long (X > 79 characters) +ignore = E265,E501 diff --git a/.pylintrc b/.pylintrc index d954b2658..4d370eb3c 100644 --- a/.pylintrc +++ b/.pylintrc @@ -218,7 +218,7 @@ ignore-long-lines=^\s*(# )??$ single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled -no-space-check=trailing-comma,dict-separator +no-space-check=trailing-comma # Maximum number of lines in a module max-module-lines=1250 diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index 81d48a6fa..c9a5ad5a2 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -136,7 +136,7 @@ class SimpleHTTPResponseTest(unittest.TestCase): jose.JWS.sign(payload=bad_resource.json_dumps().encode('utf-8'), alg=jose.RS256, key=account_key) for bad_resource in (resource.update(tls=True), - resource.update(token=b'x'*20)) + resource.update(token=(b'x' * 20))) ) for validation in validations: self.assertFalse(self.resp_http.check_validation( @@ -320,7 +320,7 @@ class DVSNIResponseTest(unittest.TestCase): def test_simple_verify_wrong_token(self): msg = self.msg.update(validation=jose.JWS.sign( - payload=self.chall.update(token=b'b'*20).json_dumps().encode(), + payload=self.chall.update(token=(b'b' * 20)).json_dumps().encode(), key=self.key, alg=jose.RS256)) self.assertFalse(msg.simple_verify( self.chall, self.domain, self.key.public_key())) @@ -350,9 +350,9 @@ class RecoveryContactTest(unittest.TestCase): contact='c********n@example.com') self.jmsg = { 'type': 'recoveryContact', - 'activationURL' : 'https://example.ca/sendrecovery/a5bd99383fb0', - 'successURL' : 'https://example.ca/confirmrecovery/bb1b9928932', - 'contact' : 'c********n@example.com', + 'activationURL': 'https://example.ca/sendrecovery/a5bd99383fb0', + 'successURL': 'https://example.ca/confirmrecovery/bb1b9928932', + 'contact': 'c********n@example.com', } def test_to_partial_json(self): diff --git a/acme/acme/client_test.py b/acme/acme/client_test.py index 06c0a2313..622a38c70 100644 --- a/acme/acme/client_test.py +++ b/acme/acme/client_test.py @@ -390,11 +390,14 @@ class ClientNetworkTest(unittest.TestCase): # pylint: disable=missing-docstring def __init__(self, value): self.value = value + def to_partial_json(self): return {'foo': self.value} + @classmethod def from_json(cls, value): pass # pragma: no cover + # pylint: disable=protected-access jws_dump = self.net._wrap_in_jws( MockJSONDeSerializable('foo'), nonce=b'Tg') @@ -498,6 +501,7 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase): self.all_nonces = [jose.b64encode(b'Nonce'), jose.b64encode(b'Nonce2')] self.available_nonces = self.all_nonces[:] + def send_request(*args, **kwargs): # pylint: disable=unused-argument,missing-docstring if self.available_nonces: diff --git a/acme/acme/jose/json_util.py b/acme/acme/jose/json_util.py index 51d55ebd9..7b95e3fce 100644 --- a/acme/acme/jose/json_util.py +++ b/acme/acme/jose/json_util.py @@ -307,6 +307,7 @@ def encode_b64jose(data): # b64encode produces ASCII characters only return b64.b64encode(data).decode('ascii') + def decode_b64jose(data, size=None, minimum=False): """Decode JOSE Base-64 field. @@ -324,13 +325,14 @@ def decode_b64jose(data, size=None, minimum=False): except error_cls as error: raise errors.DeserializationError(error) - if size is not None and ((not minimum and len(decoded) != size) - or (minimum and len(decoded) < size)): + if size is not None and ((not minimum and len(decoded) != size) or + (minimum and len(decoded) < size)): raise errors.DeserializationError( "Expected at least or exactly {0} bytes".format(size)) return decoded + def encode_hex16(value): """Hexlify. @@ -340,6 +342,7 @@ def encode_hex16(value): """ return binascii.hexlify(value).decode() + def decode_hex16(value, size=None, minimum=False): """Decode hexlified field. @@ -352,8 +355,8 @@ def decode_hex16(value, size=None, minimum=False): """ value = value.encode() - if size is not None and ((not minimum and len(value) != size * 2) - or (minimum and len(value) < size * 2)): + if size is not None and ((not minimum and len(value) != size * 2) or + (minimum and len(value) < size * 2)): raise errors.DeserializationError() error_cls = TypeError if six.PY2 else binascii.Error try: @@ -361,6 +364,7 @@ def decode_hex16(value, size=None, minimum=False): except error_cls as error: raise errors.DeserializationError(error) + def encode_cert(cert): """Encode certificate as JOSE Base-64 DER. @@ -371,6 +375,7 @@ def encode_cert(cert): return encode_b64jose(OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_ASN1, cert)) + def decode_cert(b64der): """Decode JOSE Base-64 DER-encoded certificate. @@ -384,6 +389,7 @@ def decode_cert(b64der): except OpenSSL.crypto.Error as error: raise errors.DeserializationError(error) + def encode_csr(csr): """Encode CSR as JOSE Base-64 DER. @@ -394,6 +400,7 @@ def encode_csr(csr): return encode_b64jose(OpenSSL.crypto.dump_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, csr)) + def decode_csr(b64der): """Decode JOSE Base-64 DER-encoded CSR. diff --git a/acme/acme/jose/json_util_test.py b/acme/acme/jose/json_util_test.py index 313282e67..a055f3bf7 100644 --- a/acme/acme/jose/json_util_test.py +++ b/acme/acme/jose/json_util_test.py @@ -52,6 +52,7 @@ class FieldTest(unittest.TestCase): # pylint: disable=missing-docstring def to_partial_json(self): return 'foo' # pragma: no cover + @classmethod def from_json(cls, jobj): pass # pragma: no cover @@ -93,14 +94,18 @@ class JSONObjectWithFieldsMetaTest(unittest.TestCase): self.field2 = Field('Baz2') # pylint: disable=invalid-name,missing-docstring,too-few-public-methods # pylint: disable=blacklisted-name + @six.add_metaclass(JSONObjectWithFieldsMeta) class A(object): __slots__ = ('bar',) baz = self.field + class B(A): pass + class C(A): baz = self.field2 + self.a_cls = A self.b_cls = B self.c_cls = C diff --git a/acme/acme/jose/jwa.py b/acme/acme/jose/jwa.py index 0c84905df..4ce5ca3f5 100644 --- a/acme/acme/jose/jwa.py +++ b/acme/acme/jose/jwa.py @@ -21,7 +21,7 @@ from acme.jose import jwk logger = logging.getLogger(__name__) -class JWA(interfaces.JSONDeSerializable): # pylint: disable=abstract-method +class JWA(interfaces.JSONDeSerializable): # pylint: disable=abstract-method # pylint: disable=too-few-public-methods # for some reason disable=abstract-method has to be on the line # above... @@ -159,7 +159,7 @@ class _JWAES(JWASignature): # pylint: disable=abstract-class-not-used def sign(self, key, msg): # pragma: no cover raise NotImplementedError() - def verify(self, key, msg, sig): # pragma: no cover + def verify(self, key, msg, sig): # pragma: no cover raise NotImplementedError() diff --git a/acme/acme/jose/jwk.py b/acme/acme/jose/jwk.py index d9b903eb0..7a976f189 100644 --- a/acme/acme/jose/jwk.py +++ b/acme/acme/jose/jwk.py @@ -231,7 +231,7 @@ class JWKRSA(JWK): 'n': numbers.n, 'e': numbers.e, } - else: # rsa.RSAPrivateKey + else: # rsa.RSAPrivateKey private = self.key.private_numbers() public = self.key.public_key().public_numbers() params = { diff --git a/acme/acme/jose/jws.py b/acme/acme/jose/jws.py index bd55b1a5a..61a3b5aea 100644 --- a/acme/acme/jose/jws.py +++ b/acme/acme/jose/jws.py @@ -294,10 +294,10 @@ class JWS(json_util.JSONObjectWithFields): # ... it must be in protected return ( - b64.b64encode(self.signature.protected.encode('utf-8')) - + b'.' + - b64.b64encode(self.payload) - + b'.' + + b64.b64encode(self.signature.protected.encode('utf-8')) + + b'.' + + b64.b64encode(self.payload) + + b'.' + b64.b64encode(self.signature.signature)) @classmethod @@ -345,6 +345,7 @@ class JWS(json_util.JSONObjectWithFields): signatures=tuple(cls.signature_cls.from_json(sig) for sig in jobj['signatures'])) + class CLI(object): """JWS CLI.""" diff --git a/acme/acme/messages.py b/acme/acme/messages.py index 1a7463fba..02ae24c8f 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -265,17 +265,20 @@ class Registration(ResourceBody): """All emails found in the ``contact`` field.""" return self._filter_contact(self.email_prefix) + @Directory.register class NewRegistration(Registration): """New registration.""" resource_type = 'new-reg' resource = fields.Resource(resource_type) + class UpdateRegistration(Registration): """Update registration.""" resource_type = 'reg' resource = fields.Resource(resource_type) + class RegistrationResource(ResourceWithURI): """Registration Resource. @@ -378,12 +381,14 @@ class Authorization(ResourceBody): return tuple(tuple(self.challenges[idx] for idx in combo) for combo in self.combinations) + @Directory.register class NewAuthorization(Authorization): """New authorization.""" resource_type = 'new-authz' resource = fields.Resource(resource_type) + class AuthorizationResource(ResourceWithURI): """Authorization Resource. diff --git a/acme/acme/messages_test.py b/acme/acme/messages_test.py index c0aafe2e1..3e334fb1f 100644 --- a/acme/acme/messages_test.py +++ b/acme/acme/messages_test.py @@ -60,6 +60,7 @@ class ConstantTest(unittest.TestCase): def setUp(self): from acme.messages import _Constant + class MockConstant(_Constant): # pylint: disable=missing-docstring POSSIBLE_NAMES = {} @@ -250,7 +251,6 @@ class ChallengeBodyTest(unittest.TestCase): 'detail': 'Unable to communicate with DNS server', } - def test_to_partial_json(self): self.assertEqual(self.jobj_to, self.challb.to_partial_json()) diff --git a/acme/acme/test_util.py b/acme/acme/test_util.py index 3579727d4..c9c076d27 100644 --- a/acme/acme/test_util.py +++ b/acme/acme/test_util.py @@ -20,12 +20,14 @@ def vector_path(*names): return pkg_resources.resource_filename( __name__, os.path.join('testdata', *names)) + def load_vector(*names): """Load contents of a test vector.""" # luckily, resource_string opens file in binary mode return pkg_resources.resource_string( __name__, os.path.join('testdata', *names)) + def _guess_loader(filename, loader_pem, loader_der): _, ext = os.path.splitext(filename) if ext.lower() == '.pem': @@ -35,6 +37,7 @@ def _guess_loader(filename, loader_pem, loader_der): else: # pragma: no cover raise ValueError("Loader could not be recognized based on extension") + def load_cert(*names): """Load certificate.""" loader = _guess_loader( @@ -42,6 +45,7 @@ def load_cert(*names): return jose.ComparableX509(OpenSSL.crypto.load_certificate( loader, load_vector(*names))) + def load_csr(*names): """Load certificate request.""" loader = _guess_loader( @@ -49,6 +53,7 @@ def load_csr(*names): return jose.ComparableX509(OpenSSL.crypto.load_certificate_request( loader, load_vector(*names))) + def load_rsa_private_key(*names): """Load RSA private key.""" loader = _guess_loader(names[-1], serialization.load_pem_private_key, @@ -56,6 +61,7 @@ def load_rsa_private_key(*names): return jose.ComparableRSAKey(loader( load_vector(*names), password=None, backend=default_backend())) + def load_pyopenssl_private_key(*names): """Load pyOpenSSL private key.""" loader = _guess_loader( diff --git a/letsencrypt-apache/letsencrypt_apache/configurator.py b/letsencrypt-apache/letsencrypt_apache/configurator.py index 7e9ab9541..f301de8b9 100644 --- a/letsencrypt-apache/letsencrypt_apache/configurator.py +++ b/letsencrypt-apache/letsencrypt_apache/configurator.py @@ -84,7 +84,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): description = "Apache Web Server - Alpha" - @classmethod def add_parser_arguments(cls, add): add("ctl", default=constants.CLI_DEFAULTS["ctl"], @@ -283,7 +282,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): self.assoc[target_name] = vhost return vhost - def _find_best_vhost(self, target_name): """Finds the best vhost for a target_name. @@ -582,7 +580,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): ssl_vhost = self._create_vhost(vh_p) self.vhosts.append(ssl_vhost) - # NOTE: Searches through Augeas seem to ruin changes to directives # The configuration must also be saved before being searched # for the new directives; For these reasons... this is tacked @@ -793,7 +790,6 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): raise errors.PluginError( "Let's Encrypt has already enabled redirection") - def _create_redirect_vhost(self, ssl_vhost): """Creates an http_vhost specifically to redirect for the ssl_vhost. @@ -996,9 +992,9 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): """ # Support Debian specific setup - if (not os.path.isdir(os.path.join(self.parser.root, "mods-available")) - or not os.path.isdir( - os.path.join(self.parser.root, "mods-enabled"))): + avail_path = os.path.join(self.parser.root, "mods-available") + enabled_path = os.path.join(self.parser.root, "mods-enabled") + if not os.path.isdir(avail_path) or not os.path.isdir(enabled_path): raise errors.NotSupportedError( "Unsupported directory layout. You may try to enable mod %s " "and try again." % mod_name) diff --git a/letsencrypt-apache/letsencrypt_apache/obj.py b/letsencrypt-apache/letsencrypt_apache/obj.py index 8cd2378a4..58a6c740e 100644 --- a/letsencrypt-apache/letsencrypt_apache/obj.py +++ b/letsencrypt-apache/letsencrypt_apache/obj.py @@ -14,8 +14,8 @@ class Addr(common.Addr): """ if isinstance(other, self.__class__): return ((self.tup == other.tup) or - (self.tup[0] == other.tup[0] - and self.is_wildcard() and other.is_wildcard())) + (self.tup[0] == other.tup[0] and + self.is_wildcard() and other.is_wildcard())) return False def __ne__(self, other): diff --git a/letsencrypt-apache/letsencrypt_apache/parser.py b/letsencrypt-apache/letsencrypt_apache/parser.py index da3fc97e7..d7dc3c422 100644 --- a/letsencrypt-apache/letsencrypt_apache/parser.py +++ b/letsencrypt-apache/letsencrypt_apache/parser.py @@ -195,8 +195,7 @@ class ApacheParser(object): self.aug.set(nvh_path + "/arg", args[0]) else: for i, arg in enumerate(args): - self.aug.set("%s/arg[%d]" % (nvh_path, i+1), arg) - + self.aug.set("%s/arg[%d]" % (nvh_path, i + 1), arg) def _get_ifmod(self, aug_conf_path, mod): """Returns the path to and creates one if it doesn't exist. @@ -568,7 +567,7 @@ def case_i(string): :param str string: string to make case i regex """ - return "".join(["["+c.upper()+c.lower()+"]" + return "".join(["[" + c.upper() + c.lower() + "]" if c.isalpha() else c for c in re.escape(string)]) diff --git a/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py b/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py index 406b6c39e..e7bd03cc5 100644 --- a/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py +++ b/letsencrypt-apache/letsencrypt_apache/tests/complex_parsing_test.py @@ -56,7 +56,6 @@ class ComplexParserTest(util.ParserTest): self.assertRaises( errors.PluginError, self.parser.get_arg, matches[0]) - def test_basic_ifdefine(self): self.assertEqual(len(self.parser.find_dir("VAR_DIRECTIVE")), 2) self.assertEqual(len(self.parser.find_dir("INVALID_VAR_DIRECTIVE")), 0) @@ -71,7 +70,6 @@ class ComplexParserTest(util.ParserTest): self.assertEqual( len(self.parser.find_dir("INVALID_NESTED_DIRECTIVE")), 0) - def test_load_modules(self): """If only first is found, there is bad variable parsing.""" self.assertTrue("status_module" in self.parser.modules) diff --git a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py index 71599bd1d..026594a8f 100644 --- a/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py +++ b/letsencrypt-apache/letsencrypt_apache/tests/configurator_test.py @@ -551,6 +551,7 @@ class TwoVhost80Test(util.ApacheTest): self.assertRaises( errors.PluginError, self.config.enhance, "letsencrypt.demo", "redirect") + def test_unknown_rewrite2(self): # Skip the enable mod self.config.parser.modules.add("rewrite_module") diff --git a/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py b/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py index ce234bff7..d2e4dec14 100644 --- a/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py +++ b/letsencrypt-apache/letsencrypt_apache/tests/parser_test.py @@ -143,7 +143,7 @@ class BasicParserTest(util.ParserTest): 'Group: name="www-data" id=33 not_used\n' ) expected_vars = {"TEST": "", "U_MICH": "", "TLS": "443", - "example_path":"Documents/path"} + "example_path": "Documents/path"} self.parser.update_runtime_variables("ctl") self.assertEqual(self.parser.variables, expected_vars) diff --git a/letsencrypt-apache/setup.py b/letsencrypt-apache/setup.py index 39f4b68e1..5ecb071c7 100644 --- a/letsencrypt-apache/setup.py +++ b/letsencrypt-apache/setup.py @@ -18,7 +18,7 @@ setup( entry_points={ 'letsencrypt.plugins': [ 'apache = letsencrypt_apache.configurator:ApacheConfigurator', - ], + ], }, include_package_data=True, ) diff --git a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/apache24.py b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/apache24.py index 2ffc44976..3cc6fdf8e 100644 --- a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/apache24.py +++ b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/apache/apache24.py @@ -11,7 +11,7 @@ from letsencrypt_compatibility_test.configurators.apache import common as apache # config uses mod_heartbeat or mod_heartmonitor (which aren't installed and # therefore the config won't be loaded), I believe this isn't a problem # http://httpd.apache.org/docs/2.4/mod/mod_watchdog.html -STATIC_MODULES = {"core", "so", "http", "mpm_event", "watchdog",} +STATIC_MODULES = set(["core", "so", "http", "mpm_event", "watchdog"]) SHARED_MODULES = { @@ -31,7 +31,7 @@ SHARED_MODULES = { "session_cookie", "session_crypto", "session_dbd", "setenvif", "slotmem_shm", "socache_dbm", "socache_memcache", "socache_shmcb", "speling", "ssl", "status", "substitute", "unique_id", "userdir", - "vhost_alias",} + "vhost_alias"} class Proxy(apache_common.Proxy): diff --git a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/common.py b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/common.py index 65f14bbe9..7c5e5dfcb 100644 --- a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/common.py +++ b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/configurators/common.py @@ -72,11 +72,10 @@ class Proxy(object): logger.debug(line) host_config = docker.utils.create_host_config( - binds={ - self._temp_dir : {"bind" : self._temp_dir, "mode" : "rw"}}, + binds={self._temp_dir: {"bind": self._temp_dir, "mode": "rw"}}, port_bindings={ - 80 : ("127.0.0.1", self.http_port), - 443 : ("127.0.0.1", self.https_port)},) + 80: ("127.0.0.1", self.http_port), + 443: ("127.0.0.1", self.https_port)},) container = self._docker_client.create_container( image_name, command, ports=[80, 443], volumes=self._temp_dir, host_config=host_config) diff --git a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/test_driver.py b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/test_driver.py index eac2278bb..b91322c3c 100644 --- a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/test_driver.py +++ b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/test_driver.py @@ -30,7 +30,7 @@ tests that the plugin supports are performed. """ -PLUGINS = {"apache" : apache24.Proxy} +PLUGINS = {"apache": apache24.Proxy} logger = logging.getLogger(__name__) @@ -191,7 +191,7 @@ def test_enhancements(plugin, domains): success = True for domain in domains: verify = functools.partial(validator.Validator().redirect, "localhost", - plugin.http_port, headers={"Host" : domain}) + plugin.http_port, headers={"Host": domain}) if not _try_until_true(verify): logger.error("Improper redirect for domain %s", domain) success = False diff --git a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/util.py b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/util.py index 03b15d217..43070cf03 100644 --- a/letsencrypt-compatibility-test/letsencrypt_compatibility_test/util.py +++ b/letsencrypt-compatibility-test/letsencrypt_compatibility_test/util.py @@ -34,7 +34,7 @@ def create_le_config(parent_dir): os.mkdir(config["work_dir"]) os.mkdir(config["logs_dir"]) - return argparse.Namespace(**config) # pylint: disable=star-args + return argparse.Namespace(**config) # pylint: disable=star-args def extract_configs(configs, parent_dir): diff --git a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py index 814b5f15e..2926a43d0 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py +++ b/letsencrypt-nginx/letsencrypt_nginx/nginxparser.py @@ -7,6 +7,7 @@ from pyparsing import ( from pyparsing import stringEnd from pyparsing import restOfLine + class RawNginxParser(object): # pylint: disable=expression-not-assigned """A class that parses nginx configuration with pyparsing.""" @@ -32,10 +33,10 @@ class RawNginxParser(object): block = Forward() block << Group( - (Group(key + location_statement) ^ Group(if_statement)) - + left_bracket - + Group(ZeroOrMore(Group(comment | assignment) | block)) - + right_bracket) + (Group(key + location_statement) ^ Group(if_statement)) + + left_bracket + + Group(ZeroOrMore(Group(comment | assignment) | block)) + + right_bracket) script = OneOrMore(Group(comment | assignment) ^ block) + stringEnd diff --git a/letsencrypt-nginx/letsencrypt_nginx/tests/dvsni_test.py b/letsencrypt-nginx/letsencrypt_nginx/tests/dvsni_test.py index a164397b6..a09bebba2 100644 --- a/letsencrypt-nginx/letsencrypt_nginx/tests/dvsni_test.py +++ b/letsencrypt-nginx/letsencrypt_nginx/tests/dvsni_test.py @@ -41,7 +41,6 @@ class DvsniPerformTest(util.NginxTest): domain="www.example.org", account_key=account_key), ] - def setUp(self): super(DvsniPerformTest, self).setUp() diff --git a/letsencrypt-nginx/setup.py b/letsencrypt-nginx/setup.py index 4a7123528..30dfa584f 100644 --- a/letsencrypt-nginx/setup.py +++ b/letsencrypt-nginx/setup.py @@ -18,7 +18,7 @@ setup( entry_points={ 'letsencrypt.plugins': [ 'nginx = letsencrypt_nginx.configurator:NginxConfigurator', - ], + ], }, include_package_data=True, ) diff --git a/letsencrypt/auth_handler.py b/letsencrypt/auth_handler.py index 894510191..6498a5c19 100644 --- a/letsencrypt/auth_handler.py +++ b/letsencrypt/auth_handler.py @@ -244,7 +244,7 @@ class AuthHandler(object): """ for authzr_challb in authzr.body.challenges: - if type(authzr_challb.chall) is type(achall.challb.chall): + if type(authzr_challb.chall) is type(achall.challb.chall): # noqa return authzr_challb raise errors.AuthorizationError( "Target challenge not found in authorization resource") @@ -493,26 +493,27 @@ _ERROR_HELP_COMMON = ( _ERROR_HELP = { - "connection" : + "connection": _ERROR_HELP_COMMON + " Additionally, please check that your computer " "has publicly routable IP address and no firewalls are preventing the " "server from communicating with the client.", - "dnssec" : + "dnssec": _ERROR_HELP_COMMON + " Additionally, if you have DNSSEC enabled for " "your domain, please ensure the signature is valid.", - "malformed" : + "malformed": "To fix these errors, please make sure that you did not provide any " "invalid information to the client and try running Let's Encrypt " "again.", - "serverInternal" : + "serverInternal": "Unfortunately, an error on the ACME server prevented you from completing " "authorization. Please try again later.", - "tls" : + "tls": _ERROR_HELP_COMMON + " Additionally, please check that you have an up " "to date TLS configuration that allows the server to communicate with " "the Let's Encrypt client.", - "unauthorized" : _ERROR_HELP_COMMON, - "unknownHost" : _ERROR_HELP_COMMON,} + "unauthorized": _ERROR_HELP_COMMON, + "unknownHost": _ERROR_HELP_COMMON, +} def _report_failed_challs(failed_achalls): diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py index bb04bc3d6..0e7211a81 100644 --- a/letsencrypt/cli.py +++ b/letsencrypt/cli.py @@ -73,7 +73,7 @@ Choice of server for authentication/installation: More detailed help: - -h, --help [topic] print this message, or detailed help on a topic; + -h, --help [topic] print this message, or detailed help on a topic; the available topics are: all, apache, automation, nginx, paths, security, testing, or any of the @@ -342,6 +342,7 @@ class SilentParser(object): # pylint: disable=too-few-public-methods """ def __init__(self, parser): self.parser = parser + def add_argument(self, *args, **kwargs): """Wrap, but silence help""" kwargs["help"] = argparse.SUPPRESS @@ -370,14 +371,14 @@ class HelpfulArgumentParser(object): default_config_files=flag_default("config_files")) # This is the only way to turn off overly verbose config flag documentation - self.parser._add_config_file_help = False # pylint: disable=protected-access + self.parser._add_config_file_help = False # pylint: disable=protected-access self.silent_parser = SilentParser(self.parser) help1 = self.prescan_for_flag("-h", self.help_topics) help2 = self.prescan_for_flag("--help", self.help_topics) assert max(True, "a") == "a", "Gravity changed direction" help_arg = max(help1, help2) - if help_arg == True: + if help_arg: # just --help with no topic; avoid argparse altogether print USAGE sys.exit(0) @@ -554,6 +555,7 @@ def create_parser(plugins, args): def _create_subparsers(helpful): subparsers = helpful.parser.add_subparsers(metavar="SUBCOMMAND") + def add_subparser(name, func): # pylint: disable=missing-docstring subparser = subparsers.add_parser( name, help=func.__doc__.splitlines()[0], description=func.__doc__) @@ -711,7 +713,7 @@ def _handle_exception(exc_type, exc_value, trace, args): with open(logfile, "w") as logfd: traceback.print_exception( exc_type, exc_value, trace, file=logfd) - except: # pylint: disable=bare-except + except: # pylint: disable=bare-except sys.exit("".join( traceback.format_exception(exc_type, exc_value, trace))) diff --git a/letsencrypt/client.py b/letsencrypt/client.py index e5cdc81c9..a5261bd26 100644 --- a/letsencrypt/client.py +++ b/letsencrypt/client.py @@ -279,8 +279,8 @@ class Client(object): :param .RenewableCert cert: Newly issued certificate """ - if ("autorenew" not in cert.configuration - or cert.configuration.as_bool("autorenew")): + if ("autorenew" not in cert.configuration or + cert.configuration.as_bool("autorenew")): if ("autodeploy" not in cert.configuration or cert.configuration.as_bool("autodeploy")): msg = "Automatic renewal and deployment has " diff --git a/letsencrypt/configuration.py b/letsencrypt/configuration.py index c7c780535..6f3ece9fd 100644 --- a/letsencrypt/configuration.py +++ b/letsencrypt/configuration.py @@ -45,7 +45,7 @@ class NamespaceConfig(object): return (parsed.netloc + parsed.path).replace('/', os.path.sep) @property - def accounts_dir(self): #pylint: disable=missing-docstring + def accounts_dir(self): # pylint: disable=missing-docstring return os.path.join( self.namespace.config_dir, constants.ACCOUNTS_DIR, self.server_path) diff --git a/letsencrypt/crypto_util.py b/letsencrypt/crypto_util.py index 279330f0c..1d807fcd9 100644 --- a/letsencrypt/crypto_util.py +++ b/letsencrypt/crypto_util.py @@ -205,6 +205,7 @@ def _pyopenssl_load(data, method, types=( raise errors.Error("Unable to load: {0}".format(",".join( str(error) for error in openssl_errors))) + def pyopenssl_load_certificate(data): """Load PEM/DER certificate. diff --git a/letsencrypt/display/ops.py b/letsencrypt/display/ops.py index 8083bef08..955c6cbab 100644 --- a/letsencrypt/display/ops.py +++ b/letsencrypt/display/ops.py @@ -25,8 +25,8 @@ def choose_plugin(prepared, question): :rtype: `~.PluginEntryPoint` """ - opts = [plugin_ep.description_with_name - + (" [Misconfigured]" if plugin_ep.misconfigured else "") + opts = [plugin_ep.description_with_name + + (" [Misconfigured]" if plugin_ep.misconfigured else "") for plugin_ep in prepared] while True: diff --git a/letsencrypt/display/util.py b/letsencrypt/display/util.py index de3e829fe..0e9c76e38 100644 --- a/letsencrypt/display/util.py +++ b/letsencrypt/display/util.py @@ -76,7 +76,7 @@ class NcursesDisplay(object): "help_label": help_label, "width": self.width, "height": self.height, - "menu_height": self.height-6, + "menu_height": self.height - 6, } # Can accept either tuples or just the actual choices @@ -315,7 +315,7 @@ class FileDisplay(object): if index < 1 or index > len(tags): return [] # Transform indices to appropriate tags - return [tags[index-1] for index in indices] + return [tags[index - 1] for index in indices] def _print_menu(self, message, choices): """Print a menu on the screen. diff --git a/letsencrypt/errors.py b/letsencrypt/errors.py index b15728c39..ba0601d29 100644 --- a/letsencrypt/errors.py +++ b/letsencrypt/errors.py @@ -73,6 +73,7 @@ class NoInstallationError(PluginError): class MisconfigurationError(PluginError): """Let's Encrypt Misconfiguration error.""" + class NotSupportedError(PluginError): """Let's Encrypt Plugin function not supported error.""" diff --git a/letsencrypt/interfaces.py b/letsencrypt/interfaces.py index 3dee1b1ea..5db92b368 100644 --- a/letsencrypt/interfaces.py +++ b/letsencrypt/interfaces.py @@ -439,7 +439,6 @@ class IValidator(zope.interface.Interface): """ - def hsts(name): """Verify HSTS header is enabled diff --git a/letsencrypt/le_util.py b/letsencrypt/le_util.py index f8c911d99..194a80201 100644 --- a/letsencrypt/le_util.py +++ b/letsencrypt/le_util.py @@ -196,6 +196,8 @@ def safely_remove(path): # start with a period or have two consecutive periods <- this needs to # be done in addition to the regex EMAIL_REGEX = re.compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+$") + + def safe_email(email): """Scrub email address before using it.""" if EMAIL_REGEX.match(email) is not None: diff --git a/letsencrypt/plugins/common.py b/letsencrypt/plugins/common.py index bef8b4d81..59598a35e 100644 --- a/letsencrypt/plugins/common.py +++ b/letsencrypt/plugins/common.py @@ -18,6 +18,7 @@ def option_namespace(name): """ArgumentParser options namespace (prefix of all options).""" return name + "-" + def dest_namespace(name): """ArgumentParser dest namespace (prefix of all destinations).""" return name.replace("-", "_") + "_" @@ -86,6 +87,7 @@ class Plugin(object): # other + class Addr(object): r"""Represents an virtual host address. diff --git a/letsencrypt/plugins/disco_test.py b/letsencrypt/plugins/disco_test.py index 56808c7da..41699d1ef 100644 --- a/letsencrypt/plugins/disco_test.py +++ b/letsencrypt/plugins/disco_test.py @@ -101,6 +101,7 @@ class PluginEntryPointTest(unittest.TestCase): with mock.patch("letsencrypt.plugins." "disco.zope.interface") as mock_zope: mock_zope.exceptions = exceptions + def verify_object(iface, obj): # pylint: disable=missing-docstring assert obj is plugin assert iface is iface1 or iface is iface2 or iface is iface3 diff --git a/letsencrypt/plugins/manual_test.py b/letsencrypt/plugins/manual_test.py index 21acc274c..2d7c3e1e4 100644 --- a/letsencrypt/plugins/manual_test.py +++ b/letsencrypt/plugins/manual_test.py @@ -80,8 +80,7 @@ $(command -v python2 || command -v python2.7 || command -v python2.6) -c \\ "import BaseHTTPServer, SimpleHTTPServer; \\ SimpleHTTPServer.SimpleHTTPRequestHandler.extensions_map = {\'\': \'application/jose+json\'}; \\ s = BaseHTTPServer.HTTPServer((\'\', 4430), SimpleHTTPServer.SimpleHTTPRequestHandler); \\ -s.serve_forever()" -""") +s.serve_forever()" \n""") #self.assertTrue(validation in message) mock_verify.return_value = False diff --git a/letsencrypt/plugins/standalone/tests/authenticator_test.py b/letsencrypt/plugins/standalone/tests/authenticator_test.py index bae20ac4d..7ff2c03e1 100644 --- a/letsencrypt/plugins/standalone/tests/authenticator_test.py +++ b/letsencrypt/plugins/standalone/tests/authenticator_test.py @@ -321,10 +321,8 @@ class PerformTest(unittest.TestCase): self.authenticator.already_listening = mock.Mock(return_value=False) result = self.authenticator.perform(self.achalls) self.assertEqual(len(self.authenticator.tasks), 2) - self.assertTrue( - self.authenticator.tasks.has_key(self.achall1.token)) - self.assertTrue( - self.authenticator.tasks.has_key(self.achall2.token)) + self.assertTrue(self.achall1.token in self.authenticator.tasks) + self.assertTrue(self.achall2.token in self.authenticator.tasks) self.assertTrue(isinstance(result, list)) self.assertEqual(len(result), 3) self.assertTrue(isinstance(result[0], challenges.ChallengeResponse)) @@ -340,10 +338,8 @@ class PerformTest(unittest.TestCase): self.authenticator.already_listening = mock.Mock(return_value=False) result = self.authenticator.perform(self.achalls) self.assertEqual(len(self.authenticator.tasks), 2) - self.assertTrue( - self.authenticator.tasks.has_key(self.achall1.token)) - self.assertTrue( - self.authenticator.tasks.has_key(self.achall2.token)) + self.assertTrue(self.achall1.token in self.authenticator.tasks) + self.assertTrue(self.achall2.token in self.authenticator.tasks) self.assertTrue(isinstance(result, list)) self.assertEqual(len(result), 3) self.assertEqual(result, [None, None, False]) diff --git a/letsencrypt/proof_of_possession.py b/letsencrypt/proof_of_possession.py index f13238c85..7928c60e7 100644 --- a/letsencrypt/proof_of_possession.py +++ b/letsencrypt/proof_of_possession.py @@ -17,7 +17,7 @@ from letsencrypt.display import util as display_util logger = logging.getLogger(__name__) -class ProofOfPossession(object): # pylint: disable=too-few-public-methods +class ProofOfPossession(object): # pylint: disable=too-few-public-methods """Proof of Possession Identifier Validation Challenge. Based on draft-barnes-acme, section 6.5. @@ -71,7 +71,7 @@ class ProofOfPossession(object): # pylint: disable=too-few-public-methods # If we get here, the key wasn't found return False - def _gen_response(self, achall, key_path): # pylint: disable=no-self-use + def _gen_response(self, achall, key_path): # pylint: disable=no-self-use """Create the response to the Proof of Possession Challenge. :param achall: Proof of Possession Challenge diff --git a/letsencrypt/storage.py b/letsencrypt/storage.py index e8b36d5cb..f40887835 100644 --- a/letsencrypt/storage.py +++ b/letsencrypt/storage.py @@ -486,8 +486,8 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes :rtype: bool """ - if ("autorenew" not in self.configuration - or self.configuration.as_bool("autorenew")): + if ("autorenew" not in self.configuration or + self.configuration.as_bool("autorenew")): # Consider whether to attempt to autorenew this cert now # Renewals on the basis of revocation @@ -603,7 +603,6 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes new_config.write() return cls(new_config, config, cli_config) - def save_successor(self, prior_version, new_cert, new_privkey, new_chain): """Save new cert and chain as a successor of a prior version. diff --git a/letsencrypt/tests/acme_util.py b/letsencrypt/tests/acme_util.py index 33bf605e0..235810435 100644 --- a/letsencrypt/tests/acme_util.py +++ b/letsencrypt/tests/acme_util.py @@ -30,7 +30,7 @@ POP = challenges.ProofOfPossession( "16d95b7b63f1972b980b14c20291f3c0d1855d95", "48b46570d9fc6358108af43ad1649484def0debf" ), - certs=(), # TODO + certs=(), # TODO subject_key_identifiers=("d0083162dcc4c8a23ecb8aecbd86120e56fd24e5"), serial_numbers=(34234239832, 23993939911, 17), issuers=( diff --git a/letsencrypt/tests/auth_handler_test.py b/letsencrypt/tests/auth_handler_test.py index 486b55a20..ed29ead25 100644 --- a/letsencrypt/tests/auth_handler_test.py +++ b/letsencrypt/tests/auth_handler_test.py @@ -37,7 +37,7 @@ class ChallengeFactoryTest(unittest.TestCase): self.dom = "test" self.handler.authzr[self.dom] = acme_util.gen_authzr( messages.STATUS_PENDING, self.dom, acme_util.CHALLENGES, - [messages.STATUS_PENDING]*6, False) + [messages.STATUS_PENDING] * 6, False) def test_all(self): cont_c, dv_c = self.handler._challenge_factory( @@ -163,7 +163,7 @@ class GetAuthorizationsTest(unittest.TestCase): messages.STATUS_VALID, dom, [challb.chall for challb in azr.body.challenges], - [messages.STATUS_VALID]*len(azr.body.challenges), + [messages.STATUS_VALID] * len(azr.body.challenges), azr.body.combinations) @@ -183,15 +183,15 @@ class PollChallengesTest(unittest.TestCase): self.doms = ["0", "1", "2"] self.handler.authzr[self.doms[0]] = acme_util.gen_authzr( messages.STATUS_PENDING, self.doms[0], - acme_util.DV_CHALLENGES, [messages.STATUS_PENDING]*3, False) + acme_util.DV_CHALLENGES, [messages.STATUS_PENDING] * 3, False) self.handler.authzr[self.doms[1]] = acme_util.gen_authzr( messages.STATUS_PENDING, self.doms[1], - acme_util.DV_CHALLENGES, [messages.STATUS_PENDING]*3, False) + acme_util.DV_CHALLENGES, [messages.STATUS_PENDING] * 3, False) self.handler.authzr[self.doms[2]] = acme_util.gen_authzr( messages.STATUS_PENDING, self.doms[2], - acme_util.DV_CHALLENGES, [messages.STATUS_PENDING]*3, False) + acme_util.DV_CHALLENGES, [messages.STATUS_PENDING] * 3, False) self.chall_update = {} for dom in self.doms: @@ -282,6 +282,7 @@ class PollChallengesTest(unittest.TestCase): ) return (new_authzr, "response") + class GenChallengePathTest(unittest.TestCase): """Tests for letsencrypt.auth_handler.gen_challenge_path. @@ -321,7 +322,7 @@ class GenChallengePathTest(unittest.TestCase): combos = acme_util.gen_combos(challbs) self.assertEqual(self._call(challbs, prefs, combos), (0, 2)) - # dumb_path() trivial test + # dumb_path() trivial test self.assertTrue(self._call(challbs, prefs, None)) def test_full_cont_server(self): @@ -427,26 +428,29 @@ class ReportFailedChallsTest(unittest.TestCase): from letsencrypt import achallenges kwargs = { - "chall" : acme_util.SIMPLE_HTTP, + "chall": acme_util.SIMPLE_HTTP, "uri": "uri", "status": messages.STATUS_INVALID, "error": messages.Error(typ="tls", detail="detail"), } self.simple_http = achallenges.SimpleHTTP( - challb=messages.ChallengeBody(**kwargs),# pylint: disable=star-args + # pylint: disable=star-args + challb=messages.ChallengeBody(**kwargs), domain="example.com", account_key="key") kwargs["chall"] = acme_util.DVSNI self.dvsni_same = achallenges.DVSNI( - challb=messages.ChallengeBody(**kwargs),# pylint: disable=star-args + # pylint: disable=star-args + challb=messages.ChallengeBody(**kwargs), domain="example.com", account_key="key") kwargs["error"] = messages.Error(typ="dnssec", detail="detail") self.dvsni_diff = achallenges.DVSNI( - challb=messages.ChallengeBody(**kwargs),# pylint: disable=star-args + # pylint: disable=star-args + challb=messages.ChallengeBody(**kwargs), domain="foo.bar", account_key="key") @@ -477,7 +481,7 @@ def gen_dom_authzr(domain, unused_new_authzr_uri, challs): """Generates new authzr for domains.""" return acme_util.gen_authzr( messages.STATUS_PENDING, domain, challs, - [messages.STATUS_PENDING]*len(challs)) + [messages.STATUS_PENDING] * len(challs)) if __name__ == "__main__": diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py index 613c3189b..312137666 100644 --- a/letsencrypt/tests/cli_test.py +++ b/letsencrypt/tests/cli_test.py @@ -60,7 +60,7 @@ class CLITest(unittest.TestCase): for args in itertools.chain( *(itertools.combinations(flags, r) for r in xrange(len(flags)))): - self._call(['plugins',] + list(args)) + self._call(['plugins'] + list(args)) @mock.patch("letsencrypt.cli.sys") def test_handle_exception(self, mock_sys): diff --git a/letsencrypt/tests/client_test.py b/letsencrypt/tests/client_test.py index df3a341a2..71921e007 100644 --- a/letsencrypt/tests/client_test.py +++ b/letsencrypt/tests/client_test.py @@ -166,7 +166,7 @@ class RollbackTest(unittest.TestCase): self.assertEqual(self.m_install().restart.call_count, 1) def test_no_installer(self): - self._call(1, None) # Just make sure no exceptions are raised + self._call(1, None) # Just make sure no exceptions are raised if __name__ == "__main__": diff --git a/letsencrypt/tests/continuity_auth_test.py b/letsencrypt/tests/continuity_auth_test.py index f8238a727..d80a1cfb4 100644 --- a/letsencrypt/tests/continuity_auth_test.py +++ b/letsencrypt/tests/continuity_auth_test.py @@ -35,7 +35,7 @@ class PerformTest(unittest.TestCase): self.assertRaises( errors.ContAuthError, self.auth.perform, [ achallenges.DVSNI( - challb=None, domain="0", account_key="invalid_key"),]) + challb=None, domain="0", account_key="invalid_key")]) def test_chall_pref(self): self.assertEqual( diff --git a/letsencrypt/tests/display/ops_test.py b/letsencrypt/tests/display/ops_test.py index fc4013bed..019139c35 100644 --- a/letsencrypt/tests/display/ops_test.py +++ b/letsencrypt/tests/display/ops_test.py @@ -250,6 +250,7 @@ class GenSSLLabURLs(unittest.TestCase): self.assertTrue("eff.org" in urls[0]) self.assertTrue("umich.edu" in urls[1]) + class GenHttpsNamesTest(unittest.TestCase): """Test _gen_https_names.""" def setUp(self): diff --git a/letsencrypt/tests/display/util_test.py b/letsencrypt/tests/display/util_test.py index 41075c9ce..001a9e578 100644 --- a/letsencrypt/tests/display/util_test.py +++ b/letsencrypt/tests/display/util_test.py @@ -35,7 +35,7 @@ class NcursesDisplayTest(unittest.TestCase): "help_label": "", "width": display_util.WIDTH, "height": display_util.HEIGHT, - "menu_height": display_util.HEIGHT-6, + "menu_height": display_util.HEIGHT - 6, } @mock.patch("letsencrypt.display.util.dialog.Dialog.msgbox") diff --git a/letsencrypt/tests/notify_test.py b/letsencrypt/tests/notify_test.py index 1ccfdbf87..60364fff8 100644 --- a/letsencrypt/tests/notify_test.py +++ b/letsencrypt/tests/notify_test.py @@ -1,9 +1,10 @@ """Tests for letsencrypt.notify.""" - -import mock import socket import unittest +import mock + + class NotifyTests(unittest.TestCase): """Tests for the notifier.""" diff --git a/letsencrypt/tests/proof_of_possession_test.py b/letsencrypt/tests/proof_of_possession_test.py index bfe3478d1..f2e7b2021 100644 --- a/letsencrypt/tests/proof_of_possession_test.py +++ b/letsencrypt/tests/proof_of_possession_test.py @@ -80,4 +80,4 @@ class ProofOfPossessionTest(unittest.TestCase): if __name__ == "__main__": - unittest.main() # pragma: no cover + unittest.main() # pragma: no cover diff --git a/letsencrypt/tests/renewer_test.py b/letsencrypt/tests/renewer_test.py index 1b58d9e0f..898dd406f 100644 --- a/letsencrypt/tests/renewer_test.py +++ b/letsencrypt/tests/renewer_test.py @@ -24,6 +24,7 @@ def unlink_all(rc_object): for kind in ALL_FOUR: os.unlink(getattr(rc_object, kind)) + def fill_with_sample_data(rc_object): """Put dummy data into all four files of this RenewableCert.""" for kind in ALL_FOUR: @@ -97,7 +98,7 @@ class RenewableCertTests(unittest.TestCase): self.assertRaises( errors.CertStorageError, storage.RenewableCert, config, defaults) - def test_consistent(self): # pylint: disable=too-many-statements + def test_consistent(self): # pylint: disable=too-many-statements oldcert = self.test_rc.cert self.test_rc.cert = "relative/path" # Absolute path for item requirement @@ -608,7 +609,6 @@ class RenewableCertTests(unittest.TestCase): # This should fail because the renewal itself appears to fail self.assertFalse(renewer.renew(self.test_rc, 1)) - @mock.patch("letsencrypt.renewer.notify") @mock.patch("letsencrypt.storage.RenewableCert") @mock.patch("letsencrypt.renewer.renew") diff --git a/letsencrypt/tests/validator_test.py b/letsencrypt/tests/validator_test.py index c02a7d865..c7416dc46 100644 --- a/letsencrypt/tests/validator_test.py +++ b/letsencrypt/tests/validator_test.py @@ -38,15 +38,15 @@ class ValidatorTest(unittest.TestCase): @mock.patch("letsencrypt.validator.requests.get") def test_succesful_redirect(self, mock_get_request): mock_get_request.return_value = create_response( - 301, {"location" : "https://test.com"}) + 301, {"location": "https://test.com"}) self.assertTrue(self.validator.redirect("test.com")) @mock.patch("letsencrypt.validator.requests.get") def test_redirect_with_headers(self, mock_get_request): mock_get_request.return_value = create_response( - 301, {"location" : "https://test.com"}) + 301, {"location": "https://test.com"}) self.assertTrue(self.validator.redirect( - "test.com", headers={"Host" : "test.com"})) + "test.com", headers={"Host": "test.com"})) @mock.patch("letsencrypt.validator.requests.get") def test_redirect_missing_location(self, mock_get_request): @@ -56,13 +56,13 @@ class ValidatorTest(unittest.TestCase): @mock.patch("letsencrypt.validator.requests.get") def test_redirect_wrong_status_code(self, mock_get_request): mock_get_request.return_value = create_response( - 201, {"location" : "https://test.com"}) + 201, {"location": "https://test.com"}) self.assertFalse(self.validator.redirect("test.com")) @mock.patch("letsencrypt.validator.requests.get") def test_redirect_wrong_redirect_code(self, mock_get_request): mock_get_request.return_value = create_response( - 303, {"location" : "https://test.com"}) + 303, {"location": "https://test.com"}) self.assertFalse(self.validator.redirect("test.com")) @mock.patch("letsencrypt.validator.requests.get") @@ -106,6 +106,7 @@ class ValidatorTest(unittest.TestCase): self.assertRaises( NotImplementedError, self.validator.ocsp_stapling, "test.com") + def create_response(status_code=200, headers=None): """Creates a requests.Response object for testing""" response = requests.Response() @@ -118,4 +119,4 @@ def create_response(status_code=200, headers=None): if __name__ == '__main__': - unittest.main() # pragma: no cover + unittest.main() # pragma: no cover diff --git a/letshelp-letsencrypt/letshelp_letsencrypt/apache.py b/letshelp-letsencrypt/letshelp_letsencrypt/apache.py index 3b3ab31e7..ac4e9b831 100755 --- a/letshelp-letsencrypt/letshelp_letsencrypt/apache.py +++ b/letshelp-letsencrypt/letshelp_letsencrypt/apache.py @@ -87,7 +87,7 @@ def copy_config(server_root, temp_dir): dir_len = len(os.path.dirname(server_root)) for config_path, config_dirs, config_files in os.walk(server_root): - temp_path = os.path.join(temp_dir, config_path[dir_len+1:]) + temp_path = os.path.join(temp_dir, config_path[dir_len + 1:]) os.mkdir(temp_path) copied_all = True @@ -151,7 +151,7 @@ def safe_config_file(config_file): empty_or_all_comments = False if line.startswith("-----BEGIN"): return False - elif not ":" in line: + elif ":" not in line: possible_password_file = False # If file isn't empty or commented out and could be a password file, # don't include it in selection. It is safe to include the file if @@ -234,9 +234,9 @@ def locate_config(apache_ctl): for line in output.splitlines(): # Relevant output lines are of the form: -D DIRECTIVE="VALUE" if "HTTPD_ROOT" in line: - server_root = line[line.find('"')+1:-1] + server_root = line[line.find('"') + 1:-1] elif "SERVER_CONFIG_FILE" in line: - config_file = line[line.find('"')+1:-1] + config_file = line[line.find('"') + 1:-1] if not (server_root and config_file): sys.exit("Unable to locate Apache configuration. Please run this " @@ -272,7 +272,7 @@ def get_args(): args.config_file = os.path.abspath(args.config_file) if args.config_file.startswith(args.server_root): - args.config_file = args.config_file[len(args.server_root)+1:] + args.config_file = args.config_file[len(args.server_root) + 1:] else: sys.exit("This script expects the Apache configuration file to be " "inside the server root") @@ -300,4 +300,4 @@ def main(): if __name__ == "__main__": - main() # pragma: no cover + main() # pragma: no cover diff --git a/letshelp-letsencrypt/letshelp_letsencrypt/apache_test.py b/letshelp-letsencrypt/letshelp_letsencrypt/apache_test.py index e1012797a..7ed1df760 100644 --- a/letshelp-letsencrypt/letshelp_letsencrypt/apache_test.py +++ b/letshelp-letsencrypt/letshelp_letsencrypt/apache_test.py @@ -141,7 +141,7 @@ class LetsHelpApacheTest(unittest.TestCase): @mock.patch(_MODULE_NAME + ".subprocess.Popen") def test_locate_config(self, mock_popen): mock_popen().communicate.side_effect = [ - OSError, ("bad_output", None), (_COMPILE_SETTINGS, None),] + OSError, ("bad_output", None), (_COMPILE_SETTINGS, None)] self.assertRaises( SystemExit, letshelp_le_apache.locate_config, "ctl") diff --git a/pep8.travis.sh b/pep8.travis.sh new file mode 100755 index 000000000..ccac0a435 --- /dev/null +++ b/pep8.travis.sh @@ -0,0 +1,12 @@ +#!/bin/sh +pep8 \ + setup.py \ + acme \ + letsencrypt \ + letsencrypt-apache \ + letsencrypt-nginx \ + letsencrypt-compatibility-test \ + letshelp-letsencrypt \ + || echo "PEP8 checking failed, but it's ignored in Travis" + +# echo exits with 0 diff --git a/setup.py b/setup.py index a07f70593..e72d7b231 100644 --- a/setup.py +++ b/setup.py @@ -68,6 +68,7 @@ testing_extras = [ 'coverage', 'nose', 'nosexcover', + 'pep8', 'tox', ] diff --git a/tox.ini b/tox.ini index e0314c509..83a3d07ec 100644 --- a/tox.ini +++ b/tox.ini @@ -47,6 +47,7 @@ basepython = python2.7 # continue, but tox return code will reflect previous error commands = pip install -r requirements.txt -e acme -e .[dev] -e letsencrypt-apache -e letsencrypt-nginx -e letsencrypt-compatibility-test -e letshelp-letsencrypt + ./pep8.travis.sh pylint --rcfile=.pylintrc letsencrypt pylint --rcfile=.pylintrc acme/acme pylint --rcfile=.pylintrc letsencrypt-apache/letsencrypt_apache