Skip to content

Commit

Permalink
Hardened type checking (#2698)
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea authored Jul 14, 2020
1 parent 755ba3c commit fbe61c0
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 75 deletions.
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ repos:
- flake8-absolute-import
- flake8-black>=0.1.1
- flake8-docstrings>=1.5.0
- flake8-mypy
language_version: python3
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.20.0
Expand Down
4 changes: 2 additions & 2 deletions molecule/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def __getitem__(self, i):
def get(self, key, default):
return self.__dict__.get(key, default)

def append(self, element):
def append(self, element) -> None:
self.__dict__[str(element)] = element
return super(UserListMap, self).append(element)
super(UserListMap, self).append(element)


@lru_cache()
Expand Down
5 changes: 3 additions & 2 deletions molecule/command/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import glob
import os
import shutil
from typing import Any, Callable

import click
from click_help_colors import HelpColorsCommand, HelpColorsGroup
Expand Down Expand Up @@ -229,8 +230,8 @@ def click_group_ex():
)


def click_command_ex():
def click_command_ex() -> Callable[[Callable[..., Any]], click.Command]:
"""Return extended version of click.command()."""
return click.command(
return click.command( # type: ignore
cls=HelpColorsCommand, help_headers_color="yellow", help_options_color="green"
)
2 changes: 1 addition & 1 deletion molecule/command/init/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
LOG = logger.get_logger(__name__)


@base.click_group_ex()
@base.click_group_ex() # type: ignore
def init(): # pragma: no cover
"""Initialize a new role or scenario."""

Expand Down
5 changes: 3 additions & 2 deletions molecule/command/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
import click
import tabulate

from molecule import logger, scenarios, status, util
from molecule import logger, scenarios, util
from molecule.command import base
from molecule.status import Status

LOG = logger.get_logger(__name__)

Expand Down Expand Up @@ -109,7 +110,7 @@ def list(ctx, scenario_name, format): # pragma: no cover
for scenario in s:
statuses.extend(base.execute_subcommand(scenario.config, subcommand))

headers = [util.title(name) for name in status.get_status()._fields]
headers = [util.title(name) for name in Status._fields]
if format == "simple" or format == "plain":
table_format = "simple"
if format == "plain":
Expand Down
11 changes: 5 additions & 6 deletions molecule/driver/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
import os

import molecule
from molecule import status

Status = status.get_status()
from molecule.status import Status


class Driver(object):
Expand All @@ -44,9 +42,9 @@ def __init__(self, config=None):
self._config = config
self._path = os.path.abspath(os.path.dirname(inspect.getfile(self.__class__)))

@property
@property # type: ignore
@abc.abstractmethod
def name(self) -> str: # pragma: no cover
def name(self): # pragma: no cover
"""
Name of the driver and returns a string.
Expand All @@ -55,7 +53,8 @@ def name(self) -> str: # pragma: no cover
pass

@name.setter # type: ignore
def name(self, value: str) -> None: # pragma: no cover
@abc.abstractmethod
def name(self, value): # pragma: no cover
"""
Driver name setter and returns None.
Expand Down
42 changes: 21 additions & 21 deletions molecule/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ansible.module_utils.parsing.convert_bool import boolean as to_bool


def should_do_markup():
def should_do_markup() -> bool:
"""Decide about use of ANSI colors."""
py_colors = os.environ.get("PY_COLORS", None)
if py_colors is not None:
Expand All @@ -40,7 +40,7 @@ def should_do_markup():
OUT = 101


class LogFilter(object):
class LogFilter(logging.Filter):
"""A custom log filter which excludes log messages above the logged level."""

def __init__(self, level):
Expand Down Expand Up @@ -83,7 +83,7 @@ def format(self, record):
return super(TrailingNewlineFormatter, self).format(record)


def get_logger(name=None):
def get_logger(name=None) -> logging.Logger:
"""
Build a logger with the given name and returns the logger.
Expand All @@ -93,7 +93,7 @@ def get_logger(name=None):
"""
logging.setLoggerClass(CustomLogger)

logger = logging.getLogger(name)
logger = logging.getLogger(name) # type: logging.Logger
logger.setLevel(logging.DEBUG)

logger.addHandler(_get_info_handler())
Expand All @@ -107,83 +107,83 @@ def get_logger(name=None):
return logger


def _get_info_handler():
def _get_info_handler() -> logging.StreamHandler:
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.INFO)
handler.addFilter(LogFilter(logging.INFO))
handler.addFilter(LogFilter(logging.INFO)) # type: ignore
handler.setFormatter(
TrailingNewlineFormatter("--> {}".format(cyan_text("%(message)s")))
)

return handler


def _get_out_handler():
def _get_out_handler() -> logging.StreamHandler:
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(OUT)
handler.addFilter(LogFilter(OUT))
handler.addFilter(LogFilter(OUT)) # type: ignore
handler.setFormatter(TrailingNewlineFormatter(" %(message)s"))

return handler


def _get_warn_handler():
def _get_warn_handler() -> logging.StreamHandler:
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.WARN)
handler.addFilter(LogFilter(logging.WARN))
handler.addFilter(LogFilter(logging.WARN)) # type: ignore
handler.setFormatter(TrailingNewlineFormatter(yellow_text("%(message)s")))

return handler


def _get_error_handler():
def _get_error_handler() -> logging.StreamHandler:
handler = logging.StreamHandler(sys.stderr)
handler.setLevel(logging.ERROR)
handler.addFilter(LogFilter(logging.ERROR))
handler.addFilter(LogFilter(logging.ERROR)) # type: ignore
handler.setFormatter(TrailingNewlineFormatter(red_text("%(message)s")))

return handler


def _get_critical_handler():
def _get_critical_handler() -> logging.StreamHandler:
handler = logging.StreamHandler(sys.stderr)
handler.setLevel(logging.CRITICAL)
handler.addFilter(LogFilter(logging.CRITICAL))
handler.addFilter(LogFilter(logging.CRITICAL)) # type: ignore
handler.setFormatter(TrailingNewlineFormatter(red_text("ERROR: %(message)s")))

return handler


def _get_success_handler():
def _get_success_handler() -> logging.StreamHandler:
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(SUCCESS)
handler.addFilter(LogFilter(SUCCESS))
handler.addFilter(LogFilter(SUCCESS)) # type: ignore
handler.setFormatter(TrailingNewlineFormatter(green_text("%(message)s")))

return handler


def red_text(msg):
def red_text(msg) -> str:
"""Add red markers."""
return color_text(colorama.Fore.RED, msg)


def yellow_text(msg):
def yellow_text(msg) -> str:
"""Add yellow markers."""
return color_text(colorama.Fore.YELLOW, msg)


def green_text(msg):
def green_text(msg) -> str:
"""Add green markers."""
return color_text(colorama.Fore.GREEN, msg)


def cyan_text(msg):
def cyan_text(msg) -> str:
"""Add cyan markers."""
return color_text(colorama.Fore.CYAN, msg)


def color_text(color, msg):
def color_text(color, msg) -> str:
"""Add color markers."""
if should_do_markup():
return "{}{}{}".format(color, msg, colorama.Style.RESET_ALL)
Expand Down
8 changes: 4 additions & 4 deletions molecule/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@
ENV_FILE = ".env.yml"


def _version_string():
def _version_string() -> str:

v = pkg_resources.parse_version(molecule.__version__)
color = "bright_yellow" if v.is_prerelease else "green"
color = "bright_yellow" if v.is_prerelease else "green" # type: ignore
msg = "molecule %s\n" % _colorize(molecule.__version__, color)
msg += _colorize(
" ansible==%s python==%s.%s"
Expand All @@ -61,7 +61,7 @@ def _version_string():
return msg


@click_group_ex()
@click_group_ex() # type: ignore
@click.option(
"--debug/--no-debug",
default=MOLECULE_DEBUG,
Expand All @@ -88,7 +88,7 @@ def _version_string():
)
@click.version_option(
prog_name="molecule", version=molecule.__version__, message=_version_string()
)
) # type: ignore
@click.pass_context
def main(ctx, debug, base_config, env_file): # pragma: no cover
"""
Expand Down
24 changes: 10 additions & 14 deletions molecule/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,15 @@
# DEALINGS IN THE SOFTWARE.
"""Status Module."""

import collections
from typing import NamedTuple


def get_status():
"""Return status."""
return collections.namedtuple(
"Status",
[
"instance_name",
"driver_name",
"provisioner_name",
"scenario_name",
"created",
"converged",
],
)
class Status(NamedTuple):
"""Scenario status information."""

instance_name: str
driver_name: str
provisioner_name: str
scenario_name: str
created: bool
converged: bool
18 changes: 9 additions & 9 deletions molecule/test/unit/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@

import pytest

from molecule import status
from molecule.status import Status


@pytest.fixture
def _instance():
s = status.get_status()

s.instance_name = None
s.driver_name = None
s.provisioner_name = None
s.scenario_name = None
s.created = None
s.converged = None
s = Status(
instance_name=None,
driver_name=None,
provisioner_name=None,
scenario_name=None,
created=None,
converged=None,
)

return s

Expand Down
4 changes: 2 additions & 2 deletions molecule/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def parallelize(platform):
return [parallelize(platform) for platform in config["platforms"]]


def find_vcs_root(test, dirs=(".git", ".hg", ".svn"), default=None):
def find_vcs_root(test, dirs=(".git", ".hg", ".svn"), default=None) -> str:
"""Return current repository root directory."""
prev, test = None, os.path.abspath(test)
while prev != test:
Expand All @@ -352,7 +352,7 @@ def find_vcs_root(test, dirs=(".git", ".hg", ".svn"), default=None):
return default


def lookup_config_file(filename):
def lookup_config_file(filename: str) -> str:
"""Return config file PATH."""
for path in [find_vcs_root(os.getcwd(), default="~"), "~"]:
f = os.path.expanduser("%s/%s" % (path, filename))
Expand Down
19 changes: 8 additions & 11 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@
python_version = 3.6
color_output = True
error_summary = True
# TODO(ssbarnea): Remove ignores below:
; disallow_untyped_calls=True
; warn_redundant_casts=True
disallow_untyped_calls=True
warn_redundant_casts=True

[mypy-ansiblelint.*]
ignore_missing_imports = True

[mypy-molecule.test]
ignore_errors = True

# 3rd party ignores
[mypy-ansible]
# 3rd party ignores, to remove once they add hints
[mypy-ansible.module_utils.parsing.convert_bool]
ignore_missing_imports = True

[mypy-ansible.*]
[mypy-ansible.release]
ignore_missing_imports = True

[mypy-cerberus.*]
Expand Down Expand Up @@ -46,6 +40,9 @@ ignore_missing_imports = True
[mypy-pytest]
ignore_missing_imports = True

[mypy-setuptools]
ignore_missing_imports = True

[mypy-sh]
ignore_missing_imports = True

Expand Down

0 comments on commit fbe61c0

Please sign in to comment.