Skip to content

Commit

Permalink
Introduce more types
Browse files Browse the repository at this point in the history
  • Loading branch information
ssbarnea committed Jun 26, 2024
1 parent db97488 commit bd5cc07
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 26 deletions.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ source_pkgs = ["molecule"]

[tool.mypy]
cache_dir = "./.cache/.mypy"
# To ensure that calling `mypy .` produces desired results (vscode)
exclude = ["build"]
files = ["src", "tests"]
strict = true

Expand Down
54 changes: 42 additions & 12 deletions src/molecule/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@
import traceback

from collections import UserList
from typing import Any
from collections.abc import Hashable
from typing import Any, TypeVar, overload

import pluggy

from ansible_compat.ports import cache

from molecule.driver.base import Driver # noqa: F401
from molecule.verifier.base import Verifier # noqa: F401
from molecule.driver.base import Driver
from molecule.verifier.base import Verifier


LOG = logging.getLogger(__name__)
K = TypeVar("K", bound=Hashable)


class UserListMap(UserList): # type: ignore[type-arg]
class CustomListMap(UserList[K]):
"""A list where you can also access elements by their name.
Example:
Expand All @@ -26,20 +28,37 @@ class UserListMap(UserList): # type: ignore[type-arg]
foo.boo
"""

def __getitem__(self, i): # type: ignore[no-untyped-def] # noqa: ANN001, ANN204
@overload
def __getitem__(self, i: int) -> K:
"""Implement indexing."""
if isinstance(i, int):
return super().__getitem__(i)
return self.__dict__[i]

def get(self, key, default): # type: ignore[no-untyped-def] # noqa: ANN001, ANN201, D102
return self.__dict__.get(key, default)
@overload
def __getitem__(self, i: Any): # type: ignore[no-untyped-def]
return super().__getitem__(i)

def append(self, item) -> None: # type: ignore[no-untyped-def] # noqa: ANN001, D102
def get(self, key, default: K) -> K: # type: ignore[no-untyped-def] # noqa: ANN001
"""Returns a driver by name."""
result = self.__dict__.get(key, default)
# if not isinstance(result, K):
# msg = "Unable to retrieve driver."
# raise KeyError(msg)
return result

def append(self, item) -> None: # type: ignore[no-untyped-def] # noqa: ANN001
"""Add a new driver."""
self.__dict__[str(item)] = item
super().append(item)


class DriverListMap(CustomListMap[Driver]): ...


class VerifierListMap(CustomListMap[Verifier]): ...


class MoleculeRuntimeWarning(RuntimeWarning):
"""A runtime warning used by Molecule and its plugins."""

Expand All @@ -49,13 +68,13 @@ class IncompatibleMoleculeRuntimeWarning(MoleculeRuntimeWarning):


@cache
def drivers(config: Any | None = None) -> UserListMap: # noqa: ANN401
def drivers(config: Any | None = None) -> DriverListMap: # noqa: ANN401
"""Return list of active drivers.
Args:
config: plugin config
"""
plugins = UserListMap()
plugins = DriverListMap()
pm = pluggy.PluginManager("molecule.driver")
try:
pm.load_setuptools_entrypoints("molecule.driver")
Expand All @@ -73,9 +92,9 @@ def drivers(config: Any | None = None) -> UserListMap: # noqa: ANN401


@cache
def verifiers(config=None) -> UserListMap: # type: ignore[no-untyped-def] # noqa: ANN001
def verifiers(config=None) -> VerifierListMap: # type: ignore[no-untyped-def] # noqa: ANN001
"""Return list of active verifiers."""
plugins = UserListMap()
plugins = VerifierListMap()
pm = pluggy.PluginManager("molecule.verifier")
try:
pm.load_setuptools_entrypoints("molecule.verifier")
Expand All @@ -90,3 +109,14 @@ def verifiers(config=None) -> UserListMap: # type: ignore[no-untyped-def] # no
LOG.error("Failed to load %s driver: %s", pm.get_name(p), str(e)) # noqa: TRY400
plugins.sort()
return plugins


__all__ = (
"Driver",
"DriverListMap",
"IncompatibleMoleculeRuntimeWarning",
"MoleculeRuntimeWarning",
"Verifier",
"drivers",
"verifiers",
)
6 changes: 2 additions & 4 deletions src/molecule/command/drivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ def drivers(ctx, format): # type: ignore[no-untyped-def] # pragma: no cover #
"""List drivers."""
drivers = [] # pylint: disable=redefined-outer-name
for driver in api.drivers():
description = driver
if format != "plain":
description = driver
else:
description = str(driver)
if format == "plain":
description = f"{driver!s:16s}[logging.level.notset] {driver.title} Version {driver.version} from {driver.module} python module.)[/logging.level.notset]" # noqa: E501
drivers.append([driver, description])
console.print(description)
10 changes: 8 additions & 2 deletions src/molecule/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from molecule.model import schema_v3
from molecule.provisioner import ansible
from molecule.util import boolean
from molecule.verifier.base import Verifier


LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -257,8 +258,13 @@ def state(self): # type: ignore[no-untyped-def] # noqa: ANN201, D102
return state.State(self)

@cached_property
def verifier(self): # type: ignore[no-untyped-def] # noqa: ANN201, D102
return api.verifiers(self).get(self.config["verifier"]["name"], None) # type: ignore[no-untyped-call]
def verifier(self) -> Verifier:
"""Retrieve verifiers."""
name = self.config["verifier"]["name"]
if name not in api.verifiers(self):
msg = f"Unable to find '{name}' verifier driver."
raise RuntimeError(msg)
return api.verifiers(self).get(name)

def _get_driver_name(self): # type: ignore[no-untyped-def] # noqa: ANN202
# the state file contains the driver from the last run
Expand Down
4 changes: 2 additions & 2 deletions src/molecule/driver/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,14 +267,14 @@ def get_playbook(self, step): # type: ignore[no-untyped-def] # noqa: ANN001, A
def schema_file(self): # type: ignore[no-untyped-def] # noqa: ANN201, D102
return None

def modules_dir(self): # type: ignore[no-untyped-def] # noqa: ANN201
def modules_dir(self) -> str | None:
"""Return path to ansible modules included with driver."""
p = os.path.join(self._path, "modules") # noqa: PTH118
if os.path.isdir(p): # noqa: PTH112
return p
return None

def reset(self): # type: ignore[no-untyped-def] # noqa: ANN201
def reset(self) -> None:
"""Release all resources owned by molecule.
This is a destructive operation that would affect all resources managed
Expand Down
2 changes: 1 addition & 1 deletion src/molecule/driver/delegated.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import os

from molecule import util
from molecule.api import Driver # type: ignore[attr-defined]
from molecule.api import Driver
from molecule.data import __file__ as data_module


Expand Down
2 changes: 1 addition & 1 deletion src/molecule/verifier/ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import os

from molecule import util
from molecule.api import Verifier # type: ignore[attr-defined]
from molecule.api import Verifier


log = logging.getLogger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion src/molecule/verifier/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def default_env(self): # type: ignore[no-untyped-def] # pragma: no cover # noq
"""

@abc.abstractmethod
def execute(self, action_args=None): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
def execute(self, action_args=None | list[str]): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
"""Execute ``cmd`` and returns None."""

@abc.abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion src/molecule/verifier/testinfra.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import os

from molecule import util
from molecule.api import Verifier # type: ignore[attr-defined]
from molecule.api import Verifier


LOG = logging.getLogger(__name__)
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
def test_api_molecule_drivers_as_attributes(): # type: ignore[no-untyped-def] # noqa: ANN201, D103
results = api.drivers()
assert hasattr(results, "default")
assert isinstance(results.default, api.Driver) # type: ignore[attr-defined] # pylint:disable=no-member
assert isinstance(results.default, api.Driver)


def test_api_drivers(): # type: ignore[no-untyped-def] # noqa: ANN201, D103
results = api.drivers()

for result in results:
assert isinstance(result, api.Driver) # type: ignore[attr-defined]
assert isinstance(result, api.Driver)

assert "default" in results

Expand Down

0 comments on commit bd5cc07

Please sign in to comment.