Get mypy passing with check_untyped_defs everywhere (#6021)

* unchecked_typed_defs everywhere

* fix mypy for lock_test

* add magic_typing

* fix mypy in letshelp

* fix validator errors in compat test

* fix mypy for test_driver.py

* fix mypy in util.py

* delint
This commit is contained in:
Brad Warren 2018-05-21 20:23:21 -07:00 committed by ohemorange
parent 0d3a157525
commit c9a206ca89
9 changed files with 106 additions and 85 deletions

View file

@ -15,6 +15,7 @@ from six.moves import xrange # pylint: disable=import-error,redefined-builtin
from acme import challenges
from acme import crypto_util
from acme import messages
from acme.magic_typing import List, Tuple # pylint: disable=unused-import, no-name-in-module
from certbot import achallenges
from certbot import errors as le_errors
from certbot.tests import acme_util
@ -52,9 +53,8 @@ def test_authenticator(plugin, config, temp_dir):
try:
responses = plugin.perform(achalls)
except le_errors.Error as error:
logger.error("Performing challenges on %s caused an error:", config)
logger.exception(error)
except le_errors.Error:
logger.error("Performing challenges on %s caused an error:", config, exc_info=True)
return False
success = True
@ -82,9 +82,8 @@ def test_authenticator(plugin, config, temp_dir):
if success:
try:
plugin.cleanup(achalls)
except le_errors.Error as error:
logger.error("Challenge cleanup for %s caused an error:", config)
logger.exception(error)
except le_errors.Error:
logger.error("Challenge cleanup for %s caused an error:", config, exc_info=True)
success = False
if _dirs_are_unequal(config, backup):
@ -147,9 +146,8 @@ def test_deploy_cert(plugin, temp_dir, domains):
try:
plugin.deploy_cert(domain, cert_path, util.KEY_PATH, cert_path, cert_path)
plugin.save() # Needed by the Apache plugin
except le_errors.Error as error:
logger.error("**** Plugin failed to deploy certificate for %s:", domain)
logger.exception(error)
except le_errors.Error:
logger.error("**** Plugin failed to deploy certificate for %s:", domain, exc_info=True)
return False
if not _save_and_restart(plugin, "deployed"):
@ -179,7 +177,7 @@ def test_enhancements(plugin, domains):
"enhancements")
return False
domains_and_info = [(domain, []) for domain in domains]
domains_and_info = [(domain, []) for domain in domains] # type: List[Tuple[str, List[bool]]]
for domain, info in domains_and_info:
try:
@ -192,10 +190,9 @@ def test_enhancements(plugin, domains):
# Don't immediately fail because a redirect may already be enabled
logger.warning("*** Plugin failed to enable redirect for %s:", domain)
logger.warning("%s", error)
except le_errors.Error as error:
except le_errors.Error:
logger.error("*** An error occurred while enabling redirect for %s:",
domain)
logger.exception(error)
domain, exc_info=True)
if not _save_and_restart(plugin, "enhanced"):
return False
@ -222,9 +219,8 @@ def _save_and_restart(plugin, title=None):
plugin.save(title)
plugin.restart()
return True
except le_errors.Error as error:
logger.error("*** Plugin failed to save and restart server:")
logger.exception(error)
except le_errors.Error:
logger.error("*** Plugin failed to save and restart server:", exc_info=True)
return False
@ -232,9 +228,8 @@ def test_rollback(plugin, config, backup):
"""Tests the rollback checkpoints function"""
try:
plugin.rollback_checkpoints(1337)
except le_errors.Error as error:
logger.error("*** Plugin raised an exception during rollback:")
logger.exception(error)
except le_errors.Error:
logger.error("*** Plugin raised an exception during rollback:", exc_info=True)
return False
if _dirs_are_unequal(config, backup):
@ -263,21 +258,21 @@ def _dirs_are_unequal(dir1, dir2):
logger.error("The following files and directories are only "
"present in one directory")
if dircmp.left_only:
logger.error(dircmp.left_only)
logger.error(str(dircmp.left_only))
else:
logger.error(dircmp.right_only)
logger.error(str(dircmp.right_only))
return True
elif dircmp.common_funny or dircmp.funny_files:
logger.error("The following files and directories could not be "
"compared:")
if dircmp.common_funny:
logger.error(dircmp.common_funny)
logger.error(str(dircmp.common_funny))
else:
logger.error(dircmp.funny_files)
logger.error(str(dircmp.funny_files))
return True
elif dircmp.diff_files:
logger.error("The following files differ:")
logger.error(dircmp.diff_files)
logger.error(str(dircmp.diff_files))
return True
for subdir in dircmp.subdirs.itervalues():
@ -354,9 +349,8 @@ def main():
success = test_authenticator(plugin, config, temp_dir)
if success and args.install:
success = test_installer(args, plugin, config, temp_dir)
except errors.Error as error:
logger.error("Tests on %s raised:", config)
logger.exception(error)
except errors.Error:
logger.error("Tests on %s raised:", config, exc_info=True)
success = False
if success:

View file

@ -26,12 +26,12 @@ def create_le_config(parent_dir):
config = copy.deepcopy(constants.CLI_DEFAULTS)
le_dir = os.path.join(parent_dir, "certbot")
config["config_dir"] = os.path.join(le_dir, "config")
config["work_dir"] = os.path.join(le_dir, "work")
config["logs_dir"] = os.path.join(le_dir, "logs_dir")
os.makedirs(config["config_dir"])
os.mkdir(config["work_dir"])
os.mkdir(config["logs_dir"])
os.mkdir(le_dir)
for dir_name in ("config", "logs", "work"):
full_path = os.path.join(le_dir, dir_name)
os.mkdir(full_path)
full_name = dir_name + "_dir"
config[full_name] = full_path
config["domains"] = None

View file

@ -33,7 +33,7 @@ class Validator(object):
try:
presented_cert = crypto_util.probe_sni(name, host, port)
except acme_errors.Error as error:
logger.exception(error)
logger.exception(str(error))
return False
return presented_cert.digest("sha256") == cert.digest("sha256")
@ -86,8 +86,7 @@ class Validator(object):
return False
try:
_, max_age_value = max_age[0]
max_age_value = int(max_age_value)
max_age_value = int(max_age[0][1])
except ValueError:
logger.error("Server responded with invalid HSTS header field")
return False

View file

@ -16,6 +16,8 @@ import textwrap
import six
from letshelp_certbot.magic_typing import List # pylint: disable=unused-import, no-name-in-module
_DESCRIPTION = """
Let's Help is a simple script you can run to help out the Certbot
project. Since Certbot will support automatically configuring HTTPS on
@ -87,7 +89,8 @@ def copy_config(server_root, temp_dir):
:rtype: `tuple` of `list` of `str`
"""
copied_files, copied_dirs = [], []
copied_files = [] # type: List[str]
copied_dirs = [] # type: List[str]
dir_len = len(os.path.dirname(server_root))
for config_path, config_dirs, config_files in os.walk(server_root):

View file

@ -203,13 +203,19 @@ class LetsHelpApacheTest(unittest.TestCase):
tempdir_path, "config.tar.gz"))
tempdir = tar.next()
self.assertTrue(tempdir.isdir())
self.assertEqual(tempdir.name, ".")
if tempdir is None:
self.fail("Invalid tarball!") # pragma: no cover
else:
self.assertTrue(tempdir.isdir())
self.assertEqual(tempdir.name, ".")
testdir = tar.next()
self.assertTrue(testdir.isdir())
self.assertEqual(os.path.basename(testdir.name),
testdir_basename)
if testdir is None:
self.fail("Invalid tarball!") # pragma: no cover
else:
self.assertTrue(testdir.isdir())
self.assertEqual(os.path.basename(testdir.name),
testdir_basename)
self.assertEqual(tar.next(), None)

View file

@ -0,0 +1,16 @@
"""Shim class to not have to depend on typing module in prod."""
import sys
class TypingClass(object):
"""Ignore import errors by getting anything"""
def __getattr__(self, name):
return None
try:
# mypy doesn't respect modifying sys.modules
from typing import * # pylint: disable=wildcard-import, unused-wildcard-import
# pylint: disable=unused-import
from typing import Collection, IO # type: ignore
# pylint: enable=unused-import
except ImportError:
sys.modules[__name__] = TypingClass()

View file

@ -0,0 +1,41 @@
"""Tests for letshelp_certbot.magic_typing."""
import sys
import unittest
import mock
class MagicTypingTest(unittest.TestCase):
"""Tests for letshelp_certbot.magic_typing."""
def test_import_success(self):
try:
import typing as temp_typing
except ImportError: # pragma: no cover
temp_typing = None # pragma: no cover
typing_class_mock = mock.MagicMock()
text_mock = mock.MagicMock()
typing_class_mock.Text = text_mock
sys.modules['typing'] = typing_class_mock
if 'letshelp_certbot.magic_typing' in sys.modules:
del sys.modules['letshelp_certbot.magic_typing'] # pragma: no cover
from letshelp_certbot.magic_typing import Text # pylint: disable=no-name-in-module
self.assertEqual(Text, text_mock)
del sys.modules['letshelp_certbot.magic_typing']
sys.modules['typing'] = temp_typing
def test_import_failure(self):
try:
import typing as temp_typing
except ImportError: # pragma: no cover
temp_typing = None # pragma: no cover
sys.modules['typing'] = None
if 'letshelp_certbot.magic_typing' in sys.modules:
del sys.modules['letshelp_certbot.magic_typing'] # pragma: no cover
from letshelp_certbot.magic_typing import Text # pylint: disable=no-name-in-module
self.assertTrue(Text is None)
del sys.modules['letshelp_certbot.magic_typing']
sys.modules['typing'] = temp_typing
if __name__ == '__main__':
unittest.main() # pragma: no cover

View file

@ -1,48 +1,10 @@
[mypy]
python_version = 2.7
ignore_missing_imports = True
[mypy-acme.*]
check_untyped_defs = True
ignore_missing_imports = True
python_version = 2.7
[mypy-acme.magic_typing_test]
ignore_errors = True
[mypy-certbot.*]
check_untyped_defs = True
[mypy-certbot_apache.*]
check_untyped_defs = True
[mypy-certbot_dns_cloudflare.*]
check_untyped_defs = True
[mypy-certbot_dns_cloudxns.*]
check_untyped_defs = True
[mypy-certbot_dns_digitalocean.*]
check_untyped_defs = True
[mypy-certbot_dns_dnsimple.*]
check_untyped_defs = True
[mypy-certbot_dns_dnsmadeeasy.*]
check_untyped_defs = True
[mypy-certbot_dns_google.*]
check_untyped_defs = True
[mypy-certbot_dns_luadns.*]
check_untyped_defs = True
[mypy-certbot_dns_nsone.*]
check_untyped_defs = True
[mypy-certbot_dns_rfc2136.*]
check_untyped_defs = True
[mypy-certbot_dns_route53.*]
check_untyped_defs = True
[mypy-certbot_nginx.*]
check_untyped_defs = True
[mypy-letshelp_certbot.magic_typing_test]
ignore_errors = True

View file

@ -198,7 +198,7 @@ def report_failure(err_msg, out, err):
:param str err: stderr output
"""
logger.fatal(err_msg)
logger.critical(err_msg)
log_output(logging.INFO, out, err)
sys.exit(err_msg)