Skip to content

Commit

Permalink
Add docstrings and type hints to the rest of the commands. (#4315)
Browse files Browse the repository at this point in the history
This covers reset through verify.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
Qalthos and pre-commit-ci[bot] authored Oct 31, 2024
1 parent cb654fe commit 4c0cdeb
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 114 deletions.
47 changes: 0 additions & 47 deletions .config/pydoclint-baseline.txt
Original file line number Diff line number Diff line change
@@ -1,50 +1,3 @@
src/molecule/command/reset.py
DOC101: Function `reset`: Docstring contains fewer arguments than in function signature.
DOC106: Function `reset`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Function `reset`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Function `reset`: 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: [ctx: , scenario_name: ].
--------------------
src/molecule/command/side_effect.py
DOC101: Method `SideEffect.execute`: Docstring contains fewer arguments than in function signature.
DOC106: Method `SideEffect.execute`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Method `SideEffect.execute`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Method `SideEffect.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: ].
DOC201: Method `SideEffect.execute` does not have a return section in docstring
DOC101: Function `side_effect`: Docstring contains fewer arguments than in function signature.
DOC106: Function `side_effect`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Function `side_effect`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Function `side_effect`: 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: [ctx: , scenario_name: ].
--------------------
src/molecule/command/syntax.py
DOC101: Method `Syntax.execute`: Docstring contains fewer arguments than in function signature.
DOC106: Method `Syntax.execute`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Method `Syntax.execute`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Method `Syntax.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: ].
DOC101: Function `syntax`: Docstring contains fewer arguments than in function signature.
DOC106: Function `syntax`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Function `syntax`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Function `syntax`: 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: [ctx: , scenario_name: ].
--------------------
src/molecule/command/test.py
DOC101: Method `Test.execute`: Docstring contains fewer arguments than in function signature.
DOC106: Method `Test.execute`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Method `Test.execute`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Method `Test.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: ].
DOC101: Function `test`: Docstring contains fewer arguments than in function signature.
DOC106: Function `test`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Function `test`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Function `test`: 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: [__all: , ansible_args: , ctx: , destroy: , driver_name: , parallel: , platform_name: , scenario_name: ].
--------------------
src/molecule/command/verify.py
DOC101: Method `Verify.execute`: Docstring contains fewer arguments than in function signature.
DOC106: Method `Verify.execute`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Method `Verify.execute`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Method `Verify.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: ].
DOC101: Function `verify`: Docstring contains fewer arguments than in function signature.
DOC106: Function `verify`: The option `--arg-type-hints-in-signature` is `True` but there are no argument type hints in the signature
DOC107: Function `verify`: The option `--arg-type-hints-in-signature` is `True` but not all args in the signature have type hints
DOC103: Function `verify`: 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: [ctx: , scenario_name: ].
--------------------
src/molecule/console.py
DOC101: Function `to_bool`: Docstring contains fewer arguments than in function signature.
DOC103: Function `to_bool`: 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: [a: Any].
Expand Down
16 changes: 12 additions & 4 deletions src/molecule/command/reset.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@


if TYPE_CHECKING:
from molecule.types import CommandArgs
from molecule.types import CommandArgs, MoleculeArgs


LOG = logging.getLogger(__name__)
Expand All @@ -45,9 +45,17 @@
default=base.MOLECULE_DEFAULT_SCENARIO_NAME,
help=f"Name of the scenario to target. ({base.MOLECULE_DEFAULT_SCENARIO_NAME})",
)
def reset(ctx, scenario_name): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
"""Reset molecule temporary folders."""
args = ctx.obj.get("args")
def reset(
ctx: click.Context,
scenario_name: str,
) -> None: # pragma: no cover
"""Reset molecule temporary folders.
Args:
ctx: Click context object holding commandline arguments.
scenario_name: Name of the scenario to target.
"""
args: MoleculeArgs = ctx.obj.get("args")
subcommand = base._get_subcommand(__name__) # noqa: SLF001
command_args: CommandArgs = {"subcommand": subcommand}

Expand Down
31 changes: 22 additions & 9 deletions src/molecule/command/side_effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,19 @@ class SideEffect(base.Base):
See the provisioners documentation for further details.
"""

def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: ANN001, ANN201
"""Execute the actions necessary to perform a `molecule side-effect` and returns None."""
if not self._config.provisioner.playbooks.side_effect: # type: ignore[union-attr]
msg = "Skipping, side effect playbook not configured."
LOG.warning(msg)
return
def execute(self, action_args: list[str] | None = None) -> None:
"""Execute the actions necessary to perform a `molecule side-effect`.
self._config.provisioner.side_effect(action_args) # type: ignore[union-attr]
Args:
action_args: Arguments for this command.
"""
if self._config.provisioner:
if not self._config.provisioner.playbooks.side_effect:
msg = "Skipping, side effect playbook not configured."
LOG.warning(msg)
return

self._config.provisioner.side_effect(action_args) # type: ignore[no-untyped-call]


@base.click_command_ex()
Expand All @@ -60,8 +65,16 @@ def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: AN
default=base.MOLECULE_DEFAULT_SCENARIO_NAME,
help=f"Name of the scenario to target. ({base.MOLECULE_DEFAULT_SCENARIO_NAME})",
)
def side_effect(ctx, scenario_name): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
"""Use the provisioner to perform side-effects to the instances."""
def side_effect(
ctx: click.Context,
scenario_name: str,
) -> None: # pragma: no cover
"""Use the provisioner to perform side-effects to the instances.
Args:
ctx: Click context object holding commandline arguments.
scenario_name: Name of the scenario to target.
"""
args = ctx.obj.get("args")
subcommand = base._get_subcommand(__name__) # noqa: SLF001
command_args: CommandArgs = {"subcommand": subcommand}
Expand Down
27 changes: 20 additions & 7 deletions src/molecule/command/syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


if TYPE_CHECKING:
from molecule.types import CommandArgs
from molecule.types import CommandArgs, MoleculeArgs


LOG = logging.getLogger(__name__)
Expand All @@ -39,9 +39,14 @@
class Syntax(base.Base):
"""Syntax Command Class."""

def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: ANN001, ANN201, ARG002
"""Execute the actions necessary to perform a `molecule syntax` and returns None."""
self._config.provisioner.syntax() # type: ignore[union-attr]
def execute(self, action_args: list[str] | None = None) -> None: # noqa: ARG002
"""Execute the actions necessary to perform a `molecule syntax`.
Args:
action_args: Arguments for this command. Unused.
"""
if self._config.provisioner:
self._config.provisioner.syntax() # type: ignore[no-untyped-call]


@base.click_command_ex()
Expand All @@ -52,9 +57,17 @@ def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: AN
default=base.MOLECULE_DEFAULT_SCENARIO_NAME,
help=f"Name of the scenario to target. ({base.MOLECULE_DEFAULT_SCENARIO_NAME})",
)
def syntax(ctx, scenario_name): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
"""Use the provisioner to syntax check the role."""
args = ctx.obj.get("args")
def syntax(
ctx: click.Context,
scenario_name: str,
) -> None: # pragma: no cover
"""Use the provisioner to syntax check the role.
Args:
ctx: Click context object holding commandline arguments.
scenario_name: Name of the scenario to target.
"""
args: MoleculeArgs = ctx.obj.get("args")
subcommand = base._get_subcommand(__name__) # noqa: SLF001
command_args: CommandArgs = {"subcommand": subcommand}

Expand Down
47 changes: 32 additions & 15 deletions src/molecule/command/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@


if TYPE_CHECKING:
from molecule.types import CommandArgs
from typing import Literal

from molecule.types import CommandArgs, MoleculeArgs


LOG = logging.getLogger(__name__)
Expand All @@ -45,8 +47,12 @@
class Test(base.Base):
"""Test Command Class."""

def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: ANN001, ANN201
"""Execute the actions necessary to perform a `molecule test` and returns None."""
def execute(self, action_args: list[str] | None = None) -> None:
"""Execute the actions necessary to perform a `molecule test`.
Args:
action_args: Arguments for this command. Unused.
"""


@base.click_command_ex()
Expand Down Expand Up @@ -87,18 +93,29 @@ def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: AN
help="Enable or disable parallel mode. Default is disabled.",
)
@click.argument("ansible_args", nargs=-1, type=click.UNPROCESSED)
def test( # type: ignore[no-untyped-def] # noqa: ANN201, PLR0913
ctx, # noqa: ANN001
scenario_name, # noqa: ANN001
driver_name, # noqa: ANN001
__all, # noqa: ANN001
destroy, # noqa: ANN001
parallel, # noqa: ANN001
ansible_args, # noqa: ANN001
platform_name, # noqa: ANN001
): # pragma: no cover
"""Test (dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy).""" # noqa: E501
args = ctx.obj.get("args")
def test( # noqa: PLR0913
ctx: click.Context,
scenario_name: str | None,
driver_name: str,
__all: bool, # noqa: FBT001
destroy: Literal["always", "never"],
parallel: bool, # noqa: FBT001
ansible_args: tuple[str, ...],
platform_name: str,
) -> None: # pragma: no cover
"""Test (dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy).
Args:
ctx: Click context object holding commandline arguments.
scenario_name: Name of the scenario to target.
driver_name: Name of the driver to use.
__all: Whether molecule should target scenario_name or all scenarios.
destroy: The destroy strategy to use.
parallel: Whether the scenario(s) should be run in parallel mode.
ansible_args: Arguments to forward to Ansible.
platform_name: Name of the platform to use.
""" # noqa: E501
args: MoleculeArgs = ctx.obj.get("args")
subcommand = base._get_subcommand(__name__) # noqa: SLF001
command_args: CommandArgs = {
"parallel": parallel,
Expand Down
24 changes: 18 additions & 6 deletions src/molecule/command/verify.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


if TYPE_CHECKING:
from molecule.types import CommandArgs
from molecule.types import CommandArgs, MoleculeArgs


LOG = logging.getLogger(__name__)
Expand All @@ -39,8 +39,12 @@
class Verify(base.Base):
"""Verify Command Class."""

def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: ANN001, ANN201
"""Execute the actions necessary to perform a `molecule verify` and returns None."""
def execute(self, action_args: list[str] | None = None) -> None:
"""Execute the actions necessary to perform a `molecule verify`.
Args:
action_args: Arguments for this command.
"""
self._config.verifier.execute(action_args)


Expand All @@ -52,9 +56,17 @@ def execute(self, action_args=None): # type: ignore[no-untyped-def] # noqa: AN
default=base.MOLECULE_DEFAULT_SCENARIO_NAME,
help=f"Name of the scenario to target. ({base.MOLECULE_DEFAULT_SCENARIO_NAME})",
)
def verify(ctx, scenario_name="default"): # type: ignore[no-untyped-def] # pragma: no cover # noqa: ANN001, ANN201
"""Run automated tests against instances."""
args = ctx.obj.get("args")
def verify(
ctx: click.Context,
scenario_name: str = "default",
) -> None: # pragma: no cover
"""Run automated tests against instances.
Args:
ctx: Click context object holding commandline arguments.
scenario_name: Name of the scenario to target.
"""
args: MoleculeArgs = ctx.obj.get("args")
subcommand = base._get_subcommand(__name__) # noqa: SLF001
command_args: CommandArgs = {"subcommand": subcommand}

Expand Down
33 changes: 20 additions & 13 deletions tests/unit/command/test_side_effect.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,18 @@


if TYPE_CHECKING:
from typing import Literal
from unittest.mock import MagicMock, Mock

from pytest_mock import MockerFixture

from molecule.types import ProvisionerData


@pytest.fixture()
def _command_provisioner_section_with_side_effect_data(): # type: ignore[no-untyped-def] # noqa: ANN202
def _command_provisioner_section_with_side_effect_data() -> (
dict[Literal["provisioner"], ProvisionerData]
):
return {
"provisioner": {
"name": "ansible",
Expand All @@ -44,7 +51,7 @@ def _command_provisioner_section_with_side_effect_data(): # type: ignore[no-unt


@pytest.fixture()
def _patched_ansible_side_effect(mocker): # type: ignore[no-untyped-def] # noqa: ANN001, ANN202
def _patched_ansible_side_effect(mocker: MockerFixture) -> MagicMock:
return mocker.patch("molecule.provisioner.ansible.Ansible.side_effect")


Expand All @@ -56,32 +63,32 @@ def _patched_ansible_side_effect(mocker): # type: ignore[no-untyped-def] # noq
["_command_provisioner_section_with_side_effect_data"], # noqa: PT007
indirect=True,
)
def test_side_effect_execute( # type: ignore[no-untyped-def] # noqa: ANN201, D103
def test_side_effect_execute( # noqa: D103
mocker: MockerFixture, # noqa: ARG001
_patched_ansible_side_effect, # noqa: ANN001, PT019
caplog, # noqa: ANN001
patched_config_validate, # noqa: ANN001, ARG001
_patched_ansible_side_effect: Mock, # noqa: PT019
caplog: pytest.LogCaptureFixture,
patched_config_validate: Mock, # noqa: ARG001
config_instance: config.Config,
):
) -> None:
pb = os.path.join(config_instance.scenario.directory, "side_effect.yml") # noqa: PTH118
util.write_file(pb, "")

se = side_effect.SideEffect(config_instance)
se.execute() # type: ignore[no-untyped-call]
se.execute()

assert "default" in caplog.text
assert "side_effect" in caplog.text

_patched_ansible_side_effect.assert_called_once_with(None)


def test_side_effect_execute_skips_when_playbook_not_configured( # type: ignore[no-untyped-def] # noqa: ANN201, D103
caplog, # noqa: ANN001
_patched_ansible_side_effect, # noqa: ANN001, PT019
def test_side_effect_execute_skips_when_playbook_not_configured( # noqa: D103
caplog: pytest.LogCaptureFixture,
_patched_ansible_side_effect: Mock, # noqa: PT019
config_instance: config.Config,
):
) -> None:
se = side_effect.SideEffect(config_instance)
se.execute() # type: ignore[no-untyped-call]
se.execute()

msg = "Skipping, side effect playbook not configured."
assert msg in caplog.text
Expand Down
16 changes: 9 additions & 7 deletions tests/unit/command/test_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,30 @@


if TYPE_CHECKING:
from unittest.mock import MagicMock, Mock

from pytest_mock import MockerFixture

from molecule import config


@pytest.fixture()
def _patched_ansible_syntax(mocker): # type: ignore[no-untyped-def] # noqa: ANN001, ANN202
def _patched_ansible_syntax(mocker: MockerFixture) -> MagicMock:
return mocker.patch("molecule.provisioner.ansible.Ansible.syntax")


# NOTE(retr0h): The use of the `patched_config_validate` fixture, disables
# config.Config._validate from executing. Thus preventing odd side-effects
# throughout patched.assert_called unit tests.
def test_syntax_execute( # type: ignore[no-untyped-def] # noqa: ANN201, D103
def test_syntax_execute( # noqa: D103
mocker: MockerFixture, # noqa: ARG001
caplog, # noqa: ANN001
_patched_ansible_syntax, # noqa: ANN001, PT019
patched_config_validate, # noqa: ANN001, ARG001
caplog: pytest.LogCaptureFixture,
_patched_ansible_syntax: Mock, # noqa: PT019
patched_config_validate: Mock, # noqa: ARG001
config_instance: config.Config,
):
) -> None:
s = syntax.Syntax(config_instance)
s.execute() # type: ignore[no-untyped-call]
s.execute()

assert "default" in caplog.text
assert "syntax" in caplog.text
Expand Down
Loading

0 comments on commit 4c0cdeb

Please sign in to comment.