From c6b3deba3bb3ca8b367d4a85e383a109cb900efd Mon Sep 17 00:00:00 2001 From: Kate Case Date: Thu, 5 Dec 2024 10:40:57 -0500 Subject: [PATCH] Miscellaneous additional cleanup (#4337) Some things slipped my notice. This removes the last of the D102 exclusions, and fixes driver plugins from the molecule-plugins repo. --- src/molecule/command/__init__.py | 2 +- src/molecule/config.py | 112 ++++++++++++++++++++++++---- src/molecule/driver/base.py | 4 +- src/molecule/driver/delegated.py | 4 +- src/molecule/model/schema_v3.py | 6 +- src/molecule/provisioner/ansible.py | 77 ++++++++++++++++--- src/molecule/state.py | 59 ++++++++++++--- src/molecule/verifier/testinfra.py | 6 +- 8 files changed, 221 insertions(+), 49 deletions(-) diff --git a/src/molecule/command/__init__.py b/src/molecule/command/__init__.py index e8b6af6138..8f27b5587b 100644 --- a/src/molecule/command/__init__.py +++ b/src/molecule/command/__init__.py @@ -1,4 +1,4 @@ -# D104 # noqa: D104, ERA001 +# noqa: D104 # # Copyright (c) 2015-2018 Cisco Systems, Inc. # diff --git a/src/molecule/config.py b/src/molecule/config.py index 221beefe75..5d587fbf7d 100644 --- a/src/molecule/config.py +++ b/src/molecule/config.py @@ -129,50 +129,95 @@ def __init__( if self.molecule_file: self._validate() - def write(self) -> None: # noqa: D102 + def write(self) -> None: + """Write config file to filesystem.""" util.write_file(self.config_file, util.safe_dump(self.config)) @property def ansible_collections_path( self, ) -> str: - """Return collection path variable for current version of Ansible.""" + """Return collection path variable for current version of Ansible. + + Returns: + The correct ansible collection path to use. + """ # https://github.com/ansible/ansible/pull/70007 if self.runtime.version >= Version("2.10.0.dev0"): return "ANSIBLE_COLLECTIONS_PATH" return "ANSIBLE_COLLECTIONS_PATHS" @property - def config_file(self) -> str: # noqa: D102 + def config_file(self) -> str: + """Path to the config file. + + Returns: + The path to the config file. + """ path = Path(self.scenario.ephemeral_directory) / MOLECULE_FILE return str(path) @property - def is_parallel(self) -> bool: # noqa: D102 + def is_parallel(self) -> bool: + """Is molecule in parallel mode. + + Returns: + Whether molecule is in parallel mode. + """ return self.command_args.get("parallel", False) @property - def platform_name(self) -> str | None: # noqa: D102 + def platform_name(self) -> str | None: + """Configured platform. + + Returns: + The name of the platform plugin specified. + """ return self.command_args.get("platform_name", None) @property - def debug(self) -> bool: # noqa: D102 + def debug(self) -> bool: + """Is molecule in debug mode. + + Returns: + Whether molecule is in debug mode. + """ return self.args.get("debug", MOLECULE_DEBUG) @property - def env_file(self) -> str | None: # noqa: D102 + def env_file(self) -> str | None: + """Return path to env file. + + Returns: + Path to configured env file. + """ return util.abs_path(self.args.get("env_file")) @property - def subcommand(self) -> str: # noqa: D102 + def subcommand(self) -> str: + """Subcommand in use. + + Returns: + The current subcommand being run. + """ return self.command_args["subcommand"] @property - def action(self) -> str | None: # noqa: D102 + def action(self) -> str | None: + """Action value. + + Returns: + The value of action. + """ return self._action @action.setter def action(self, value: str) -> None: + """Action setter. + + Args: + value: New value for action. + """ self._action = value @property @@ -187,11 +232,21 @@ def cache_directory( return "molecule_parallel" if self.is_parallel else "molecule" @property - def molecule_directory(self) -> str: # noqa: D102 + def molecule_directory(self) -> str: + """Molecule directory for this project. + + Returns: + The appropriate molecule directory for this project. + """ return molecule_directory(self.project_directory) @cached_property - def dependency(self) -> Dependency | None: # noqa: D102 + def dependency(self) -> Dependency | None: + """Dependency manager in use. + + Returns: + Instance of a molecule dependency plugin. + """ dependency_name = self.config["dependency"]["name"] if dependency_name == "galaxy": return ansible_galaxy.AnsibleGalaxy(self) @@ -220,7 +275,12 @@ def driver(self) -> Driver: return driver @property - def env(self) -> dict[str, str]: # noqa: D102 + def env(self) -> dict[str, str]: + """Environment variables. + + Returns: + Total set of computed environment variables. + """ return { "MOLECULE_DEBUG": str(self.debug), "MOLECULE_FILE": self.config_file, @@ -240,7 +300,12 @@ def env(self) -> dict[str, str]: # noqa: D102 } @cached_property - def platforms(self) -> platforms.Platforms: # noqa: D102 + def platforms(self) -> platforms.Platforms: + """Platforms for this run. + + Returns: + A molecule Platforms instance. + """ return platforms.Platforms( self, parallelize_platforms=self.is_parallel, @@ -248,18 +313,33 @@ def platforms(self) -> platforms.Platforms: # noqa: D102 ) @cached_property - def provisioner(self) -> ansible.Ansible | None: # noqa: D102 + def provisioner(self) -> ansible.Ansible | None: + """Provisioner for this run. + + Returns: + An instance of the Ansible provisioner. + """ provisioner_name = self.config["provisioner"]["name"] if provisioner_name == "ansible": return ansible.Ansible(self) return None @cached_property - def scenario(self) -> scenario.Scenario: # noqa: D102 + def scenario(self) -> scenario.Scenario: + """Scenario for this run. + + Returns: + A molecule Scenario instance. + """ return scenario.Scenario(self) @cached_property - def state(self) -> State: # noqa: D102 + def state(self) -> State: + """Molecule state object. + + Returns: + A molecule State instance. + """ myState = state.State(self) # noqa: N806 # look at state file for molecule.yml date modified and warn if they do not match if self.molecule_file and os.path.isfile(self.molecule_file): # noqa: PTH113 diff --git a/src/molecule/driver/base.py b/src/molecule/driver/base.py index 3f8282f356..b7988842d7 100644 --- a/src/molecule/driver/base.py +++ b/src/molecule/driver/base.py @@ -344,13 +344,13 @@ def get_playbook(self, step: str) -> str | None: return str(p) return None - @abstractmethod - def schema_file(self) -> str: + def schema_file(self) -> str | None: # pragma: no cover """Return schema file path. Returns: Path to schema file. """ + return None def modules_dir(self) -> str | None: """Return path to ansible modules included with driver. diff --git a/src/molecule/driver/delegated.py b/src/molecule/driver/delegated.py index 31a1b04d59..890a2f2a57 100644 --- a/src/molecule/driver/delegated.py +++ b/src/molecule/driver/delegated.py @@ -21,8 +21,8 @@ from __future__ import annotations import logging -import os +from pathlib import Path from typing import TYPE_CHECKING, Any from molecule import util @@ -320,4 +320,4 @@ def schema_file(self) -> str: Returns: Path to schema file. """ - return os.path.join(os.path.dirname(data_module), "driver.json") # noqa: PTH118, PTH120 + return str(Path(data_module).parent / "driver.json") diff --git a/src/molecule/model/schema_v3.py b/src/molecule/model/schema_v3.py index f49cb7ebf0..03b97de796 100644 --- a/src/molecule/model/schema_v3.py +++ b/src/molecule/model/schema_v3.py @@ -57,16 +57,16 @@ def validate(c: ConfigData) -> list[str]: driver_schema_file = None if driver_name in api.drivers(): - driver_schema_file = Path(api.drivers()[driver_name].schema_file()) + driver_schema_file = api.drivers()[driver_name].schema_file() if driver_schema_file is None: msg = f"Driver {driver_name} does not provide a schema." LOG.warning(msg) - elif not driver_schema_file.exists(): + elif not Path(driver_schema_file).exists(): msg = f"Schema {driver_schema_file} for driver {driver_name} not found." LOG.warning(msg) else: - schema_files.append(str(driver_schema_file)) + schema_files.append(driver_schema_file) for schema_file in schema_files: with Path(schema_file).open(encoding="utf-8") as f: diff --git a/src/molecule/provisioner/ansible.py b/src/molecule/provisioner/ansible.py index bbd8a0cbf1..e3812bfad1 100644 --- a/src/molecule/provisioner/ansible.py +++ b/src/molecule/provisioner/ansible.py @@ -579,7 +579,12 @@ def config_options(self) -> dict[str, Any]: ) @property - def options(self) -> Options: # noqa: D102 + def options(self) -> Options: + """Appropriate options for provisioner. + + Returns: + Dictionary of provisioner options. + """ if self._config.action in ["create", "destroy"]: return self.default_options @@ -592,7 +597,12 @@ def options(self) -> Options: # noqa: D102 return util.merge_dicts(self.default_options, opts) @property - def env(self) -> dict[str, str]: # noqa: D102 + def env(self) -> dict[str, str]: + """Full computed environment variables for provisioner. + + Returns: + Complete set of collected environment variables. + """ default_env = self.default_env env = self._config.config["provisioner"]["env"].copy() # ensure that all keys and values are strings @@ -619,19 +629,39 @@ def env(self) -> dict[str, str]: # noqa: D102 return util.merge_dicts(default_env, env) @property - def hosts(self) -> dict[str, str]: # noqa: D102 + def hosts(self) -> dict[str, str]: + """Provisioner inventory hosts. + + Returns: + Dictionary of host names. + """ return self._config.config["provisioner"]["inventory"]["hosts"] @property - def host_vars(self) -> dict[str, str]: # noqa: D102 + def host_vars(self) -> dict[str, str]: + """Provisioner inventory host vars. + + Returns: + Dictionary of host vars. + """ return self._config.config["provisioner"]["inventory"]["host_vars"] @property - def group_vars(self) -> dict[str, str]: # noqa: D102 + def group_vars(self) -> dict[str, str]: + """Provisioner inventory group vars. + + Returns: + Dictionary of group vars. + """ return self._config.config["provisioner"]["inventory"]["group_vars"] @property - def links(self) -> dict[str, str]: # noqa: D102 + def links(self) -> dict[str, str]: + """Provisioner inventory links. + + Returns: + Dictionary of links. + """ return self._config.config["provisioner"]["inventory"]["links"] @property @@ -688,15 +718,30 @@ def inventory(self) -> dict[str, str]: return self._default_to_regular(dd) @property - def inventory_directory(self) -> str: # noqa: D102 + def inventory_directory(self) -> str: + """Inventory directory path. + + Returns: + Path to the directory containing inventory files. + """ return self._config.scenario.inventory_directory @property - def inventory_file(self) -> str: # noqa: D102 + def inventory_file(self) -> str: + """Inventory file path. + + Returns: + Path to ansible_inventory.yml + """ return str(Path(self.inventory_directory, "ansible_inventory.yml")) @property - def config_file(self) -> str: # noqa: D102 + def config_file(self) -> str: + """Configuration file path. + + Returns: + Path to ansible.cfg. + """ return str( Path( self._config.scenario.ephemeral_directory, @@ -705,11 +750,21 @@ def config_file(self) -> str: # noqa: D102 ) @cached_property - def playbooks(self) -> ansible_playbooks.AnsiblePlaybooks: # noqa: D102 + def playbooks(self) -> ansible_playbooks.AnsiblePlaybooks: + """Ansible playbooks provisioner instance. + + Returns: + AnsiblePlaybooks instance based on this config. + """ return ansible_playbooks.AnsiblePlaybooks(self._config) @property - def directory(self) -> str: # noqa: D102 + def directory(self) -> str: + """Ansible provisioner directory. + + Returns: + Path to the ansible provisioner directory. + """ return str(Path(__file__).parent.parent.parent / "molecule" / "provisioner" / "ansible") def cleanup(self) -> None: diff --git a/src/molecule/state.py b/src/molecule/state.py index 473dd2ef61..a8b9566762 100644 --- a/src/molecule/state.py +++ b/src/molecule/state.py @@ -120,39 +120,80 @@ def __init__(self, config: Config) -> None: self._write_state_file() @property - def state_file(self) -> str: # noqa: D102 + def state_file(self) -> str: + """State file path. + + Returns: + Path to the state file. + """ return str(self._state_file) @property - def converged(self) -> bool: # noqa: D102 + def converged(self) -> bool: + """Is run converged. + + Returns: + Whether the run has converged. + """ return self._data["converged"] @property - def created(self) -> bool: # noqa: D102 + def created(self) -> bool: + """Has scenario been created. + + Returns: + Whether scenario has been created. + """ return self._data["created"] @property - def driver(self) -> str | None: # noqa: D102 + def driver(self) -> str | None: + """Driver for scenario. + + Returns: + Name of the driver for the scenario. + """ return self._data["driver"] @property - def prepared(self) -> bool: # noqa: D102 + def prepared(self) -> bool: + """Has scenario prepare run. + + Returns: + Whether scenario prepare has run. + """ return self._data["prepared"] @property - def run_uuid(self) -> str: # noqa: D102 + def run_uuid(self) -> str: + """Scenario run UUID. + + Returns: + The UUID for this scenario run. + """ return self._data["run_uuid"] @property - def is_parallel(self) -> bool: # noqa: D102 + def is_parallel(self) -> bool: + """Is molecule in parallel mode. + + Returns: + Whether Molecule is in parallel mode. + """ return self._data["is_parallel"] @property - def molecule_yml_date_modified(self) -> float | None: # noqa: D102 + def molecule_yml_date_modified(self) -> float | None: + """The modified date of molecule.yml. + + Returns: + The timestamp of the last modification date of molecule.yml. + """ return self._data["molecule_yml_date_modified"] @marshal - def reset(self) -> None: # noqa: D102 + def reset(self) -> None: + """Reset state data.""" self._data = self._default_data() @marshal diff --git a/src/molecule/verifier/testinfra.py b/src/molecule/verifier/testinfra.py index d419786501..019bf2efc0 100644 --- a/src/molecule/verifier/testinfra.py +++ b/src/molecule/verifier/testinfra.py @@ -97,13 +97,8 @@ class Testinfra(Verifier): - ../path/to/directory/* ``` .. _`Testinfra`: https://testinfra.readthedocs.io - - Attributes: - _testinfra_command: List of strings composing the command to run. """ - _testinfra_command: list[str] - def __init__(self, config: Config) -> None: """Set up the requirements to execute ``testinfra`` and returns None. @@ -111,6 +106,7 @@ def __init__(self, config: Config) -> None: config: An instance of a Molecule config. """ super().__init__(config) + self._testinfra_command: list[str] = [] self._tests = [] # type: ignore[var-annotated] @property