Repository: ansible/ansible-navigator (language: python)

Issue:
Convert sphinx based documentation to mkdocs



Discussion / hints:

Fix patch:
diff --git a/.flake8 b/.flake8
index dc9c5d5ee..5d68f2255 100644
--- a/.flake8
+++ b/.flake8
@@ -76,11 +76,6 @@ per-file-ignores =
 
   # The following were present during the initial implementation.
   # They are expected to be fixed and unignored over time.
-  tests/integration/_action_run_test.py: D205, D400, D401, D403, DAR101, DAR201, DAR401
-  tests/integration/_cli2runner.py: D400, D401, D403, DAR101, DAR401
-  tests/integration/_interactions.py: D204, D400, D403, DAR101, DAR201
-  tests/integration/_tmux_session.py: D105, D205, D400, D403, DAR101, DAR201, DAR401
-  tests/integration/test_stdout_exit_codes.py: D400, D403, DAR101, DAR201
   tests/unit/configuration_subsystem/defaults.py: D400
   tests/unit/configuration_subsystem/test_entries_sanity.py: D400, DAR101
   tests/unit/configuration_subsystem/test_fixture_sanity.py: D205, D400
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 13f60fbe4..274f4cb51 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,7 +4,7 @@
   // Override the pyproject.toml and disable xdist to enable test debugging
   "python.testing.pytestArgs": ["-n0", "--dist", "no"],
   "python.formatting.provider": "black",
-  "editor.formatOnSave": false,
+  "editor.formatOnSave": true,
   "python.linting.pylintEnabled": true,
   "python.linting.flake8Enabled": true,
   "python.linting.mypyEnabled": true,


Test patch:
diff --git a/tests/integration/_action_run_test.py b/tests/integration/_action_run_test.py
index d15d32d49..562dc73a2 100644
--- a/tests/integration/_action_run_test.py
+++ b/tests/integration/_action_run_test.py
@@ -1,4 +1,4 @@
-"""directly run an action for testing"""
+"""Directly run an action for testing."""
 from __future__ import annotations
 
 import os
@@ -87,18 +87,31 @@ def __init__(
             fromlist=["Action"],
         )
 
-    def callable_pass_one_arg(self, value=0):
-        """a do nothing callable"""
+    def callable_pass_one_arg(self, value: int = 0) -> None:
+        """Do nothing callable.
 
-    def callable_pass(self, **kwargs):
-        """a do nothing callable"""
+        :param value: The value to return
+        """
+
+    def callable_pass(self, **kwargs) -> None:
+        """Do nothing callable.
+
+        :param kwargs: The call values
+        """
 
     def content_format(
         self,
         value: ContentFormat | None = None,
         default: bool = False,
-    ):
-        """A do nothing content format callable."""
+    ) -> ContentFormat:
+        # pylint: disable=unused-argument
+        """Do nothing content format callable.
+
+        :param value: The content format value
+        :param default: A boolean indicating if the default value should be used
+        :returns: The content format value
+        """
+        return value if value else ContentFormat.YAML
 
     def show(
         self,
@@ -110,17 +123,36 @@ def show(
         filter_content_keys: Callable = lambda x: x,
         color_menu_item: Callable = lambda *args, **kwargs: (0, 0),
         content_heading: Callable = lambda *args, **kwargs: None,
-    ):
-        """me"""
+    ) -> None:
+        """Show a content object, but don't really.
+
+        :param obj: The content object to show
+        :param content_format: The content format to use
+        :param index: The index of the content object
+        :param columns: The columns to display
+        :param await_input: A boolean indicating if input should be awaited
+        :param filter_content_keys: A callable to filter content keys
+        :param color_menu_item: A callable to color menu items
+        :param content_heading: A callable to display content headings
+        """
+
+    def show_form(self, form: Form) -> Form:
+        """Do nothing show form callable.
 
-    def show_form(self, form: Form):
-        """A do nothing show form callable."""
+        :param form: The form to show
+        :returns: The form to show
+        """
+        return form
 
     def run_action_interactive(self) -> Any:
-        """run the action
+        """Run the action.
+
         The return type is set to Any here since not all actions
         have the same signature, the corresponding integration test
         will be using the action internals for asserts
+
+        :returns: The action return value
+        :raises ValueError: If no action name match
         """
         self._app_args.update({"mode": "interactive"})
         args = deepcopy(NavigatorConfiguration)
@@ -144,7 +176,10 @@ def run_action_interactive(self) -> Any:
             clear=self.callable_pass,
             menu_filter=self.callable_pass_one_arg,
             scroll=self.callable_pass_one_arg,
-            show=self.show,
+            # Ignored here because it doesn't make sens to mock up a full
+            # Interaction for the above show function, this returns
+            # None and the ShowCallable protocol returns an Interaction
+            show=self.show,  # type: ignore[arg-type]
             show_form=self.show_form,
             update_status=self.callable_pass,
             content_format=self.content_format,
@@ -163,7 +198,11 @@ def run_action_interactive(self) -> Any:
 
     def run_action_stdout(self, **kwargs) -> tuple[RunStdoutReturn, str, str]:
         # pylint: disable=too-many-locals
-        """run the action"""
+        """Run the action, stdout.
+
+        :param kwargs: The action arguments
+        :returns: The result, stdout and stderr
+        """
         self._app_args.update({"mode": "stdout"})
         self._app_args.update(kwargs)
         args = deepcopy(NavigatorConfiguration)
diff --git a/tests/integration/_interactions.py b/tests/integration/_interactions.py
index a908ed8e0..71290e3fe 100644
--- a/tests/integration/_interactions.py
+++ b/tests/integration/_interactions.py
@@ -8,7 +8,7 @@
 
 
 class SearchFor(Enum):
-    """set the test mode"""
+    """An enum for response search types."""
 
     HELP = "search for help"
     PROMPT = "search for the shell prompt"
@@ -16,7 +16,7 @@ class SearchFor(Enum):
 
 
 class Command(NamedTuple):
-    """command details"""
+    """Command details."""
 
     execution_environment: bool
     cmdline: str | None = None
@@ -31,14 +31,17 @@ class Command(NamedTuple):
     """Anything raw that should be appended, and not shlex quoted"""
     subcommand: str | None = None
 
-    def join(self):
-        """create CLI command"""
+    def join(self) -> str:
+        """Create  the CLI command.
+
+        :return: The command
+        """
         args = [self.command]
         if isinstance(self.subcommand, str):
             args.append(self.subcommand)
         if isinstance(self.cmdline, str):
             args.extend(shlex.split(self.cmdline))
-        args.extend(["--ee", self.execution_environment])
+        args.extend(["--ee", str(self.execution_environment)])
         args.extend(["--ll", self.log_level])
         args.extend(["--mode", self.mode])
         if self.format:
@@ -74,24 +77,36 @@ class UiTestStep(NamedTuple):
     #: Find this before returning from the tmux session to the test
     search_within_response: SearchFor | str | list = SearchFor.HELP
 
-    def __str__(self):
-        """Produce a test id for this step."""
+    def __str__(self) -> str:
+        """Produce a test id for this step.
+
+        :return: The test id
+        """
         return f"{self.comment}  {self.user_input}"
 
 
-def add_indices(steps):
-    """update the index of each"""
-    return (step._replace(step_index=idx) for idx, step in enumerate(steps))
+def add_indices(steps: tuple[UiTestStep, ...]) -> tuple[UiTestStep, ...]:
+    """Update the index of each.
+
+    :param steps: The list of steps
+    :return: The list of steps with the index updated
+    """
+    return tuple(step._replace(step_index=idx) for idx, step in enumerate(steps))
 
 
-def step_id(value):
-    """return the test id from the test step object"""
+def step_id(value: UiTestStep) -> str:
+    """Create a test id from the test step object.
+
+    :param value: The test value
+    :return: The test id
+    """
     return f"{value.step_index}-{value.user_input}-{value.comment}"
 
 
-def step_id_padded(value):
+def step_id_padded(value: UiTestStep) -> str:
     """Return the test id from the test step object, index padded to 2.
 
     :param value: The test value
+    :return: The test id
     """
     return f"{value.step_index:02d}-{value.user_input}-{value.comment}"
diff --git a/tests/integration/_tmux_session.py b/tests/integration/_tmux_session.py
index 851bb75d5..2b0d5b3a8 100644
--- a/tests/integration/_tmux_session.py
+++ b/tests/integration/_tmux_session.py
@@ -1,10 +1,11 @@
-"""the tmux session"""
+"""The tmux session."""
 from __future__ import annotations
 
 import datetime
 import os
 import shlex
 import time
+import types
 import uuid
 import warnings
 
@@ -19,7 +20,7 @@
 
 
 class TmuxSessionKwargs(TypedDict, total=False):
-    """tmux session kwargs"""
+    """Tmux session kwargs."""
 
     config_path: Path
     cwd: Path
@@ -35,7 +36,7 @@ class TmuxSession:
     # pylint: disable=too-many-instance-attributes
     # pylint: disable=too-many-arguments
     # pylint: disable=too-many-locals
-    """tmux session"""
+    """Tmux session."""
 
     def __init__(
         self,
@@ -70,7 +71,7 @@ def __init__(
         self._pull_policy = pull_policy
         self._session: libtmux.Session
         self._session_name = str(uuid.uuid4())
-        self._setup_capture: list
+        self._setup_capture: str | list[str]
         self._setup_commands = setup_commands or []
         self._shell_prompt_timeout = shell_prompt_timeout
         self._test_log_dir = generate_test_log_dir(request)
@@ -79,11 +80,13 @@ def __init__(
             # ensure CWD is top folder of library
             self._cwd = Path(__file__).parent.parent.parent
 
-    def _build_tmux_session(self):
+    def _build_tmux_session(self) -> None:
         """Create a new tmux session.
 
         Retry here do to errors captured here:
         https://github.com/ansible/ansible-navigator/issues/812
+
+        :raises libtmux.exc.LibTmuxException: If tries are exceeded
         """
         count = 1
         tries = 3
@@ -91,7 +94,7 @@ def _build_tmux_session(self):
             try:
                 self._session = self._server.new_session(
                     session_name=self._session_name,
-                    start_directory=self._cwd,
+                    start_directory=str(self._cwd),
                     kill_session=True,
                 )
                 break
@@ -101,7 +104,13 @@ def _build_tmux_session(self):
                     raise
                 count += 1
 
-    def __enter__(self):
+    def __enter__(self) -> TmuxSession:
+        """Enter the tmux session.
+
+        :return: The tmux session
+        :raises AssertionError: If VIRTUAL_ENV environment variable was not set
+        :raises ValueError: If the time is exceeded for finding the shell prompt
+        """
         # pylint: disable=attribute-defined-outside-init
         # pylint: disable=too-many-locals
         # pylint: disable=too-many-statements
@@ -193,6 +202,8 @@ def __enter__(self):
         prompt_showing = False
         while True:
             showing = self._pane.capture_pane()
+            showing = [showing] if isinstance(showing, str) else showing
+
             # the screen has been cleared, wait for prompt in first line
             if showing:
                 prompt_showing = self.cli_prompt in showing[0]
@@ -207,26 +218,47 @@ def __enter__(self):
 
         return self
 
-    def __exit__(self, exc_type, exc_value, exc_traceback):
+    def __exit__(
+        self,
+        exc_type: BaseException | None,
+        exc_value: BaseException | None,
+        exc_traceback: types.TracebackType | None,
+    ) -> None:
+        """Exit the tmux session.
+
+        :param exc_type: exception type
+        :param exc_value: exception value
+        :param exc_traceback: exception traceback
+        """
         if self._server.has_session(self._session_name):
             self._session.kill_session()
 
+    def _capture_pane(self) -> list[str]:
+        """Capture the pane.
+
+        :returns: The captured pane
+        """
+        captured = self._pane.capture_pane()
+        return [captured] if isinstance(captured, str) else captured
+
     def interaction(
         self,
-        value,
+        value: str,
         search_within_response: list | str | None = None,
-        ignore_within_response=None,
-        timeout=300,
+        ignore_within_response: str | None = None,
+        timeout: int = 300,
         send_clear: bool = True,
-    ):
+    ) -> list[str]:
         # pylint: disable=too-many-branches
         # pylint: disable=too-many-statements
         """Interact with the tmux session.
 
-        :param value: send to screen
-        :param search_within_response: a list of strings or string to find
-        :param ignore_within_response: ignore screen if this there
-        :param timeout: the amount of time is seconds to allow for completion
+        :param value: Send to screen
+        :param search_within_response: A list of strings or string to find
+        :param ignore_within_response: Ignore screen if this there
+        :param timeout: The amount of time is seconds to allow for completion
+        :param send_clear: Send a clear command before sending the value
+        :returns: The screen content
         """
         showing = None
         if self._fail_remaining:
@@ -237,7 +269,8 @@ def interaction(
         # if presently at command prompt or in TUI
         mode = None
         while True:
-            showing = self._pane.capture_pane()
+            showing = self._capture_pane()
+
             if showing:
                 if self.cli_prompt in showing[-1]:
                     mode = "shell"
@@ -264,7 +297,8 @@ def interaction(
         self._pane.send_keys(value)
         command_executed = False
         while True:
-            showing = self._pane.capture_pane()
+            showing = self._capture_pane()
+
             if showing and showing != pre_send:
                 if mode == "shell":
                     command_executed = value not in showing[-1]
@@ -288,7 +322,7 @@ def interaction(
         ok_to_return = False
         err_message = "RESPONSE"
         while True:
-            showing = self._pane.capture_pane()
+            showing = self._capture_pane()
 
             if showing:
                 if isinstance(search_within_response, str):
@@ -309,7 +343,9 @@ def interaction(
             if ok_to_return:
                 screens = [showing]
                 while True:
-                    screens.append(self._pane.capture_pane())
+                    captured = self._capture_pane()
+
+                    screens.append(captured)
                     if len(screens) >= 5 and all(elem == screens[-1] for elem in screens[-5:]):
                         showing = screens[-1]
                         break
diff --git a/tests/integration/actions/config/test_welcome_interactive_param_use.py b/tests/integration/actions/config/test_welcome_interactive_param_use.py
index 31640a603..83510fa79 100644
--- a/tests/integration/actions/config/test_welcome_interactive_param_use.py
+++ b/tests/integration/actions/config/test_welcome_interactive_param_use.py
@@ -10,7 +10,7 @@
 
 CLI = Command(execution_environment=False).join()
 
-steps = (
+steps: tuple[UiTestStep, ...] = (
     UiTestStep(user_input=CLI, comment="welcome screen"),
     UiTestStep(
         user_input=":config",
diff --git a/tests/integration/actions/config/test_welcome_interactive_specified_config.py b/tests/integration/actions/config/test_welcome_interactive_specified_config.py
index 34e36b6d6..698bfae61 100644
--- a/tests/integration/actions/config/test_welcome_interactive_specified_config.py
+++ b/tests/integration/actions/config/test_welcome_interactive_specified_config.py
@@ -11,7 +11,7 @@
 
 CLI = Command(execution_environment=False).join()
 
-steps = (
+steps: tuple[UiTestStep, ...] = (
     UiTestStep(user_input=CLI, comment="welcome screen"),
     UiTestStep(
         user_input=":config",
diff --git a/tests/integration/actions/exec/test_stdout_vault.py b/tests/integration/actions/exec/test_stdout_vault.py
index 6836c4f22..b2338c6e5 100644
--- a/tests/integration/actions/exec/test_stdout_vault.py
+++ b/tests/integration/actions/exec/test_stdout_vault.py
@@ -36,7 +36,7 @@ class ShellCommand(UiTestStep):
     f'{BASE_COMMAND} exec "{VAULT_COMMAND}" --mode stdout --exec-shell false',
 )
 
-stdout_tests = (
+stdout_tests = tuple(
     ShellCommand(
         comment="Vault variation",
         user_input=f"clear && {variation}",
diff --git a/tests/integration/actions/lint/test_direct_interactive_ee.py b/tests/integration/actions/lint/test_direct_interactive_ee.py
index 8779fa877..e26adbeb6 100644
--- a/tests/integration/actions/lint/test_direct_interactive_ee.py
+++ b/tests/integration/actions/lint/test_direct_interactive_ee.py
@@ -11,7 +11,7 @@
 
 CLI = Command(subcommand="lint", cmdline=LINT_FIXTURES, execution_environment=True).join()
 
-steps = (
+steps: tuple[UiTestStep, ...] = (
     UiTestStep(
         user_input=CLI,
         comment="ansible-navigator lint top window",
diff --git a/tests/integration/actions/lint/test_direct_interactive_no_errors_ee.py b/tests/integration/actions/lint/test_direct_interactive_no_errors_ee.py
index 742cb2d5d..297fda0e8 100644
--- a/tests/integration/actions/lint/test_direct_interactive_no_errors_ee.py
+++ b/tests/integration/actions/lint/test_direct_interactive_no_errors_ee.py
@@ -20,7 +20,7 @@
     execution_environment=True,
 ).join()
 
-steps = (
+steps: tuple[UiTestStep, ...] = (
     UiTestStep(
         user_input=CLI,
         comment="ansible-navigator lint top window",
diff --git a/tests/integration/actions/templar/test_direct_interactive_ee_readme.py b/tests/integration/actions/templar/test_direct_interactive_ee_readme.py
index c0f75833d..13ccbeaf0 100644
--- a/tests/integration/actions/templar/test_direct_interactive_ee_readme.py
+++ b/tests/integration/actions/templar/test_direct_interactive_ee_readme.py
@@ -10,7 +10,7 @@
 
 CLI = Command(subcommand="collections", execution_environment=True).join()
 
-steps = (
+steps: tuple[UiTestStep, ...] = (
     UiTestStep(
         user_input=CLI,
         comment="ansible-navigator collections",
diff --git a/tests/integration/test_stdout_exit_codes.py b/tests/integration/test_stdout_exit_codes.py
index 4718c79e3..0fb1ec697 100644
--- a/tests/integration/test_stdout_exit_codes.py
+++ b/tests/integration/test_stdout_exit_codes.py
@@ -3,7 +3,9 @@
 
 import os
 
+from collections.abc import Iterable
 from pathlib import Path
+from typing import Any
 from typing import NamedTuple
 
 import pytest
@@ -12,6 +14,7 @@
 from tests.defaults import id_func
 from ..conftest import TCmdInTty
 from ..defaults import FIXTURES_DIR
+from .conftest import ActionRunTest
 
 
 PLAYBOOK = os.path.join(FIXTURES_DIR, "integration", "stdout_exit_codes", "site.yml")
@@ -26,6 +29,7 @@ def fixture_params(
     """Generate parameters.
 
     :param default_ee_image_name: The default execution environment image name
+    :param valid_container_engine: The valid container engine
     :param request: The pytest request object
     :returns: The parameters
     """
@@ -36,13 +40,21 @@ def fixture_params(
     }
 
 
-def id_ee(value):
-    """generate id"""
+def id_ee(value: bool):
+    """Generate the test id.
+
+    :param value: The value of the parameter
+    :returns: The test id
+    """
     return f"execution_environment={value}"
 
 
-def id_test_data(value):
-    """generate id"""
+def id_test_data(value: StdoutTest):
+    """Generate the test id.
+
+    :param value: The value of the parameter
+    :returns: The test id
+    """
     return f"action={value.action_name} return={value.return_code}"
 
 
@@ -52,7 +64,7 @@ class StdoutTest(NamedTuple):
     #: The name of the action
     action_name: str
     #: Parameters for the action
-    action_params: tuple[tuple, ...]
+    action_params: Iterable[tuple[str, str | bool | list[str]]]
     #: Text to search for
     present: str
     #: Expected return code
@@ -116,8 +128,18 @@ class StdoutTest(NamedTuple):
 
 @pytest.mark.parametrize("params", (True, False), indirect=["params"], ids=id_ee)
 @pytest.mark.parametrize("test_data", fixture_test_data, ids=id_test_data)
-def test(action_run_stdout, params, test_data):
-    """test for a return code"""
+def test(
+    action_run_stdout: type[ActionRunTest],
+    params: dict[str, Any],
+    test_data: StdoutTest,
+):
+    """Test for a return code.
+
+    :param action_run_stdout: The action runner
+    :param params: The parameters
+    :param test_data: The test data
+
+    """
     action_runner = action_run_stdout(action_name=test_data.action_name, **params)
     run_stdout_return, stdout, stderr = action_runner.run_action_stdout(
         **dict(test_data.action_params),
@@ -156,12 +178,18 @@ class StdoutCliTest(NamedTuple):
     """The mode to run in"""
 
     def __str__(self) -> str:
-        """Provide a test id."""
+        """Provide a test id.
+
+        :returns: The test id
+        """
         return self.comment
 
     @property
     def command(self) -> list[str]:
-        """Provide the constructed command"""
+        """Provide the constructed command.
+
+        :returns: The command
+        """
         return ["ansible-navigator", self.subcommand] + self.params + ["--mode", self.mode]