Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docstrings and type hints to the rest of the commands. #4315

Merged
merged 3 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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