Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 277d7ca

Browse files
committedJun 27, 2024··
Introduce more types
1 parent 033910c commit 277d7ca

File tree

14 files changed

+79
-80
lines changed

14 files changed

+79
-80
lines changed
 

‎.config/pydoclint-baseline.txt

-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
src/molecule/api.py
2-
DOC101: Method `UserListMap.__getitem__`: Docstring contains fewer arguments than in function signature.
3-
DOC106: Method `UserListMap.__getitem__`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
4-
DOC107: Method `UserListMap.__getitem__`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
5-
DOC103: Method `UserListMap.__getitem__`: Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ). Arguments in the function signature but not in the docstring: [i: ].
6-
DOC201: Method `UserListMap.__getitem__` does not have a return section in docstring
72
DOC201: Function `drivers` does not have a return section in docstring
83
DOC101: Function `verifiers`: Docstring contains fewer arguments than in function signature.
94
DOC106: Function `verifiers`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
@@ -565,10 +560,6 @@ src/molecule/verifier/base.py
565560
DOC603: Class `Verifier`: Class docstring attributes are different from actual class attributes. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ). Attributes in the class definition but not in the docstring: [__metaclass__: ]. (Please read https://jsh9.github.io/pydoclint/checking_class_attributes.html on how to correctly document class attributes.)
566561
DOC106: Method `Verifier.__init__`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
567562
DOC107: Method `Verifier.__init__`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
568-
DOC101: Method `Verifier.execute`: Docstring contains fewer arguments than in function signature.
569-
DOC106: Method `Verifier.execute`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
570-
DOC107: Method `Verifier.execute`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
571-
DOC103: Method `Verifier.execute`: Docstring arguments are different from function arguments. (Or could be other formatting issues: https://jsh9.github.io/pydoclint/violation_codes.html#notes-on-doc103 ). Arguments in the function signature but not in the docstring: [action_args: ].
572563
DOC101: Method `Verifier.__eq__`: Docstring contains fewer arguments than in function signature.
573564
DOC106: Method `Verifier.__eq__`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
574565
DOC107: Method `Verifier.__eq__`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints

‎pyproject.toml

+5-3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ source_pkgs = ["molecule"]
7272

7373
[tool.mypy]
7474
cache_dir = "./.cache/.mypy"
75+
# To ensure that calling `mypy .` produces desired results (vscode)
76+
exclude = ["build"]
7577
files = ["src", "tests"]
7678
strict = true
7779

@@ -348,9 +350,6 @@ verbosity_assertions = 2
348350
[tool.ruff]
349351
builtins = ["__"]
350352
cache-dir = "./.cache/.ruff"
351-
external = [
352-
"DOC" # pydoclint
353-
]
354353
fix = true
355354
line-length = 100
356355
target-version = "py310"
@@ -359,6 +358,9 @@ target-version = "py310"
359358
extend-ignore = [
360359
"ANN101" # missing-type-self (deprecated)
361360
]
361+
external = [
362+
"DOC" # pydoclint
363+
]
362364
select = ["ALL"]
363365

364366
[tool.ruff.lint.flake8-pytest-style]

‎src/molecule/api.py

+40-43
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,19 @@
33
import logging
44
import traceback
55

6-
from collections import UserList
7-
from typing import Any
6+
from collections.abc import Hashable
7+
from typing import Any, TypeVar
88

99
import pluggy
1010

1111
from ansible_compat.ports import cache
1212

13-
from molecule.driver.base import Driver # noqa: F401
14-
from molecule.verifier.base import Verifier # noqa: F401
13+
from molecule.driver.base import Driver
14+
from molecule.verifier.base import Verifier
1515

1616

1717
LOG = logging.getLogger(__name__)
18-
19-
20-
class UserListMap(UserList): # type: ignore[type-arg]
21-
"""A list where you can also access elements by their name.
22-
23-
Example:
24-
-------
25-
foo['boo']
26-
foo.boo
27-
"""
28-
29-
def __getitem__(self, i): # type: ignore[no-untyped-def] # noqa: ANN001, ANN204
30-
"""Implement indexing."""
31-
if isinstance(i, int):
32-
return super().__getitem__(i)
33-
return self.__dict__[i]
34-
35-
def get(self, key, default): # type: ignore[no-untyped-def] # noqa: ANN001, ANN201, D102
36-
return self.__dict__.get(key, default)
37-
38-
def append(self, item) -> None: # type: ignore[no-untyped-def] # noqa: ANN001, D102
39-
self.__dict__[str(item)] = item
40-
super().append(item)
18+
K = TypeVar("K", bound=Hashable)
4119

4220

4321
class MoleculeRuntimeWarning(RuntimeWarning):
@@ -49,44 +27,63 @@ class IncompatibleMoleculeRuntimeWarning(MoleculeRuntimeWarning):
4927

5028

5129
@cache
52-
def drivers(config: Any | None = None) -> UserListMap: # noqa: ANN401
30+
def drivers(config: Any | None = None) -> dict[str, Driver]: # noqa: ANN401
5331
"""Return list of active drivers.
5432
5533
Args:
5634
config: plugin config
5735
"""
58-
plugins = UserListMap()
36+
plugins = {}
5937
pm = pluggy.PluginManager("molecule.driver")
6038
try:
6139
pm.load_setuptools_entrypoints("molecule.driver")
6240
except (Exception, SystemExit):
6341
# These are not fatal because a broken driver should not make the entire
6442
# tool unusable.
6543
LOG.error("Failed to load driver entry point %s", traceback.format_exc()) # noqa: TRY400
66-
for p in pm.get_plugins():
67-
try:
68-
plugins.append(p(config))
69-
except (Exception, SystemExit) as e: # noqa: PERF203
70-
LOG.error("Failed to load %s driver: %s", pm.get_name(p), str(e)) # noqa: TRY400
71-
plugins.sort()
72-
return plugins
44+
for plugin in pm.get_plugins():
45+
if issubclass(plugin, Driver):
46+
try:
47+
driver = plugin(config)
48+
plugins[driver.name] = driver
49+
except (Exception, SystemExit, TypeError) as e:
50+
LOG.error( # noqa: TRY400
51+
"Failed to load %s driver: %s",
52+
pm.get_name(plugin),
53+
str(e),
54+
)
55+
else:
56+
msg = f"Skipped loading plugin class {plugin} because is not a subclass of Driver."
57+
LOG.error(msg)
58+
59+
return dict(sorted(plugins.items()))
7360

7461

7562
@cache
76-
def verifiers(config=None) -> UserListMap: # type: ignore[no-untyped-def] # noqa: ANN001
63+
def verifiers(config=None) -> dict[str, Verifier]: # type: ignore[no-untyped-def] # noqa: ANN001
7764
"""Return list of active verifiers."""
78-
plugins = UserListMap()
65+
plugins = {}
7966
pm = pluggy.PluginManager("molecule.verifier")
8067
try:
8168
pm.load_setuptools_entrypoints("molecule.verifier")
8269
except Exception: # noqa: BLE001
8370
# These are not fatal because a broken verifier should not make the entire
8471
# tool unusable.
8572
LOG.error("Failed to load verifier entry point %s", traceback.format_exc()) # noqa: TRY400
86-
for p in pm.get_plugins():
73+
for plugin in pm.get_plugins():
8774
try:
88-
plugins.append(p(config))
75+
if issubclass(plugin, Verifier):
76+
plugins[plugin.name] = plugin(config)
8977
except Exception as e: # noqa: BLE001, PERF203
90-
LOG.error("Failed to load %s driver: %s", pm.get_name(p), str(e)) # noqa: TRY400
91-
plugins.sort()
92-
return plugins
78+
LOG.error("Failed to load %s driver: %s", pm.get_name(plugin), str(e)) # noqa: TRY400
79+
return dict(sorted(plugins.items()))
80+
81+
82+
__all__ = (
83+
"Driver",
84+
"IncompatibleMoleculeRuntimeWarning",
85+
"MoleculeRuntimeWarning",
86+
"Verifier",
87+
"drivers",
88+
"verifiers",
89+
)

‎src/molecule/command/drivers.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,9 @@
4444
def drivers(ctx, format): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201, A002, ARG001
4545
"""List drivers."""
4646
drivers = [] # pylint: disable=redefined-outer-name
47-
for driver in api.drivers():
48-
description = driver
49-
if format != "plain":
50-
description = driver
51-
else:
47+
for driver in api.drivers().values():
48+
description = str(driver)
49+
if format == "plain":
5250
description = f"{driver!s:16s}[logging.level.notset] {driver.title} Version {driver.version} from {driver.module} python module.)[/logging.level.notset]" # noqa: E501
5351
drivers.append([driver, description])
5452
console.print(description)

‎src/molecule/command/reset.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,5 @@ def reset(ctx, scenario_name): # type: ignore[no-untyped-def] # pragma: no cove
4545
command_args = {"subcommand": subcommand}
4646

4747
base.execute_cmdline_scenarios(scenario_name, args, command_args)
48-
for driver in drivers():
48+
for driver in drivers().values():
4949
driver.reset()

‎src/molecule/config.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
from molecule.model import schema_v3
3939
from molecule.provisioner import ansible
4040
from molecule.util import boolean
41+
from molecule.verifier.base import Verifier
4142

4243

4344
LOG = logging.getLogger(__name__)
@@ -257,8 +258,20 @@ def state(self): # type: ignore[no-untyped-def] # noqa: ANN201, D102
257258
return state.State(self)
258259

259260
@cached_property
260-
def verifier(self): # type: ignore[no-untyped-def] # noqa: ANN201, D102
261-
return api.verifiers(self).get(self.config["verifier"]["name"], None) # type: ignore[no-untyped-call]
261+
def verifier(self) -> Verifier:
262+
"""Retrieve current verifier.
263+
264+
Raises:
265+
RuntimeError: If is not able to find the driver.
266+
267+
Returns:
268+
Instance of Verifier driver.
269+
"""
270+
name = self.config["verifier"]["name"]
271+
if name not in api.verifiers(self):
272+
msg = f"Unable to find '{name}' verifier driver."
273+
raise RuntimeError(msg)
274+
return api.verifiers(self)[name]
262275

263276
def _get_driver_name(self): # type: ignore[no-untyped-def] # noqa: ANN202
264277
# the state file contains the driver from the last run

‎src/molecule/driver/base.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -264,17 +264,17 @@ def get_playbook(self, step): # type: ignore[no-untyped-def] # noqa: ANN001, A
264264
return p
265265
return None
266266

267-
def schema_file(self): # type: ignore[no-untyped-def] # noqa: ANN201, D102
267+
def schema_file(self) -> None | str: # noqa: D102
268268
return None
269269

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

277-
def reset(self): # type: ignore[no-untyped-def] # noqa: ANN201
277+
def reset(self) -> None:
278278
"""Release all resources owned by molecule.
279279
280280
This is a destructive operation that would affect all resources managed

‎src/molecule/driver/delegated.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import os
2424

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

2929

‎src/molecule/provisioner/ansible.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -920,7 +920,7 @@ def _get_modules_directories(self) -> list[str]:
920920
util.abs_path(os.path.join(self._get_plugin_directory(), "modules")), # noqa: PTH118
921921
)
922922

923-
for d in drivers():
923+
for d in drivers().values():
924924
p = d.modules_dir()
925925
if p:
926926
paths.append(p)

‎src/molecule/shell.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def print_version(ctx, param, value): # type: ignore[no-untyped-def] # noqa: A
6363
msg = f"molecule [{color}]{v}[/] using python [repr.number]{sys.version_info[0]}.{sys.version_info[1]}[/] \n" # noqa: E501
6464

6565
msg += f" [repr.attrib_name]ansible[/][dim]:[/][repr.number]{app.runtime.version}[/]"
66-
for driver in drivers():
66+
for driver in drivers().values():
6767
msg += f"\n [repr.attrib_name]{driver!s}[/][dim]:[/][repr.number]{driver.version}[/][dim] from {driver.module}" # noqa: E501
6868
if driver.required_collections:
6969
msg += " requiring collections:"

‎src/molecule/verifier/ansible.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import os
2424

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

2828

2929
log = logging.getLogger(__name__)

‎src/molecule/verifier/base.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,12 @@ def default_env(self): # type: ignore[no-untyped-def] # pragma: no cover # noq
6565
"""
6666

6767
@abc.abstractmethod
68-
def execute(self, action_args=None): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
69-
"""Execute ``cmd`` and returns None."""
68+
def execute(self, action_args: None | list[str] = None) -> None: # pragma: no cover
69+
"""Execute ``cmd`` and returns None.
70+
71+
Args:
72+
action_args: list of arguments to be passed.
73+
"""
7074

7175
@abc.abstractmethod
7276
def schema(self): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN201

‎src/molecule/verifier/testinfra.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
import os
2525

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

2929

3030
LOG = logging.getLogger(__name__)

‎tests/unit/test_api.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,11 @@
2222
from molecule import api
2323

2424

25-
def test_api_molecule_drivers_as_attributes(): # type: ignore[no-untyped-def] # noqa: ANN201, D103
26-
results = api.drivers()
27-
assert hasattr(results, "default")
28-
assert isinstance(results.default, api.Driver) # type: ignore[attr-defined] # pylint:disable=no-member
29-
30-
3125
def test_api_drivers(): # type: ignore[no-untyped-def] # noqa: ANN201, D103
3226
results = api.drivers()
3327

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

3731
assert "default" in results
3832

0 commit comments

Comments
 (0)
Please sign in to comment.