From 99063c5ad20114e1a279dd50482f08f25bace062 Mon Sep 17 00:00:00 2001 From: Sorin Sbarnea Date: Wed, 14 Feb 2024 15:17:53 +0000 Subject: [PATCH] Resolve mypy disallow_any_generics (partial) (#1686) --- docs/_ext/regenerate_docs.py | 5 +- mypy.ini | 49 ------------------- pyproject.toml | 24 ++++++--- src/ansible_navigator/action_base.py | 6 +-- src/ansible_navigator/action_defs.py | 1 - src/ansible_navigator/actions/__init__.py | 3 +- src/ansible_navigator/actions/_actions.py | 20 ++++---- src/ansible_navigator/actions/builder.py | 2 +- src/ansible_navigator/actions/collections.py | 18 ++++--- src/ansible_navigator/actions/config.py | 11 +++-- src/ansible_navigator/actions/doc.py | 4 +- src/ansible_navigator/actions/exec.py | 4 +- src/ansible_navigator/actions/images.py | 8 +-- src/ansible_navigator/actions/inventory.py | 8 +-- src/ansible_navigator/actions/lint.py | 4 +- src/ansible_navigator/actions/open_file.py | 9 ++-- src/ansible_navigator/actions/run.py | 12 ++--- src/ansible_navigator/actions/settings.py | 8 +-- src/ansible_navigator/app_public.py | 6 +-- src/ansible_navigator/cli.py | 10 ++-- .../configuration_subsystem/configurator.py | 2 +- .../configuration_subsystem/definitions.py | 1 - .../defs_presentable.py | 16 +++--- .../configuration_subsystem/parser.py | 2 +- .../configuration_subsystem/transform.py | 6 +-- src/ansible_navigator/content_defs.py | 1 - .../data/image_introspect.py | 7 ++- src/ansible_navigator/diagnostics.py | 5 +- .../image_manager/introspector.py | 5 +- src/ansible_navigator/initialization.py | 2 +- src/ansible_navigator/runner/base.py | 8 +-- src/ansible_navigator/steps.py | 4 +- src/ansible_navigator/tm_tokenize/reg.py | 1 - src/ansible_navigator/tm_tokenize/rules.py | 1 - src/ansible_navigator/ui_framework/form.py | 3 -- .../ui_framework/form_defs.py | 1 - src/ansible_navigator/ui_framework/ui.py | 44 +++++++++-------- .../ui_framework/validators.py | 2 +- src/ansible_navigator/utils/compatibility.py | 16 +++--- src/ansible_navigator/utils/dict_merge.py | 5 +- src/ansible_navigator/utils/dot_paths.py | 9 ++-- src/ansible_navigator/utils/json_schema.py | 7 ++- .../utils/version_migration/migrate.py | 2 +- tests/integration/_action_run_test.py | 16 +++--- tests/integration/_interactions.py | 4 +- tests/integration/_tmux_session.py | 7 ++- .../actions/doc/test_direct_interactive_ee.py | 25 +++++++--- .../doc/test_direct_interactive_noee.py | 22 ++++++--- tests/integration/actions/doc/test_stdout.py | 40 +++++++-------- .../doc/test_welcome_interactive_ee.py | 24 +++++---- .../doc/test_welcome_interactive_noee.py | 24 +++++---- tests/integration/actions/images/base.py | 2 +- .../test_json_schema_errors.py | 4 +- tests/unit/actions/run/test_artifact.py | 2 +- tests/unit/actions/run/test_runner_async.py | 17 ++++--- tests/unit/actions/test_exec.py | 2 +- .../unit/configuration_subsystem/conftest.py | 5 +- ...est_execution_environment_volume_mounts.py | 3 +- .../post_processors/test_time_zone.py | 3 +- .../test_presentable.py | 2 - .../test_settings_effective.py | 7 +-- tests/unit/logger/test_time_zone.py | 2 +- tests/unit/ui_framework/test_progress_bar.py | 3 +- tests/unit/utils/test_dot_paths.py | 3 +- tests/unit/utils/test_serialize_dataclass.py | 1 - 65 files changed, 284 insertions(+), 296 deletions(-) delete mode 100644 mypy.ini diff --git a/docs/_ext/regenerate_docs.py b/docs/_ext/regenerate_docs.py index 7ca238d1f..88c19725c 100644 --- a/docs/_ext/regenerate_docs.py +++ b/docs/_ext/regenerate_docs.py @@ -14,7 +14,6 @@ from ansible_navigator.configuration_subsystem import NavigatorConfiguration from ansible_navigator.configuration_subsystem.definitions import SettingsEntry from ansible_navigator.utils.functions import oxfordcomma -from ansible_navigator.version import __version__ logger = logging.getLogger(__name__) @@ -46,7 +45,7 @@ ] -def _mk_row(row: tuple) -> list: +def _mk_row(row: tuple[str, ...]) -> list[str]: """Convert a row as a markdown definition list entry. :param row: The row tuple, with name, description and list of options @@ -97,7 +96,7 @@ def md_settings_dump() -> str: return "\n".join(lines) -def _params_row_for_entry(entry: SettingsEntry) -> tuple: +def _params_row_for_entry(entry: SettingsEntry) -> tuple[str, ...]: # pylint: disable=too-many-branches """Create a row entry for one settings parameter. diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 8c8b363ff..000000000 --- a/mypy.ini +++ /dev/null @@ -1,49 +0,0 @@ -[mypy] -files = - docs/, - share/, - src/, - tests/ -install_types = true -namespace_packages = true -no_implicit_optional = true -non_interactive = true -pretty = true -show_column_numbers = true -show_error_codes = true -show_error_context = true -# check_untyped_defs = true -# strict = true -# strict_optional = true - -[mypy-ansible.*] -# No type hints as of version 2.12 -ignore_missing_imports = true - -[mypy-ansible_runner] -# No type hints as of version 2.1.2 -ignore_missing_imports = true - -[mypy-jsonschema.*] -# No type hints as of version 4.4.0 -ignore_missing_imports = true - -[mypy-libtmux] -# No type hints as of version 0.10.3 -ignore_missing_imports = true - -[mypy-onigurumacffi] -# No type hints as of version 1.1.0 -ignore_missing_imports = true - -[mypy-setuptools_scm] -# No type hints as of version 6.4.2 -# See docs/conf.py for an explanation of why the recommended -# use of importlib.metadata is not possible. -ignore_missing_imports = True - -[mypy-setuptools_scm.*] -# No type hints as of version 6.4.2 -# See docs/conf.py for an explanation of why the recommended -# use of importlib.metadata is not possible. -ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml index 3323f710d..6ef2f337c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,16 @@ data_file = ".tox/.coverage" parallel = true source_pkgs = ["ansible_navigator"] +[tool.mypy] +python_version = "3.10" +# strict = true +color_output = true +error_summary = true +# disallow_untyped_calls = true +# disallow_untyped_defs = true +# disallow_any_generics = true +incremental = false + [tool.pydoclint] allow-init-docstring = true arg-type-hints-in-docstring = false @@ -240,7 +250,9 @@ PYTEST_MAX_TEST_ID_LENGTH = 0 fix = true line-length = 100 builtins = ["__"] -select = ["ALL"] +exclude = ["tests/fixtures/**", ".git"] + +[tool.ruff.lint] ignore = [ 'ANN001', # Missing type annotation for function argument `output` 'ANN002', # Missing type annotation for `*args` @@ -277,8 +289,8 @@ ignore = [ 'D105', # Missing docstring in magic method 'D400', # [*] First line should end with a period 'D403', # [*] First word of the first line should be capitalized: `tokenize` -> `Tokenize` + 'E501', # line-too-long, already covered by black 'ERA001', # [*] Found commented-out code - 'F401', # [*] `ansible_navigator.version.__version__` imported but unused 'FBT001', # Boolean positional arg in function definition 'FBT002', # Boolean default value in function definition 'FBT003', # Boolean positional value in function call @@ -370,18 +382,18 @@ ignore = [ 'TRY400', # Use `logging.exception` instead of `logging.error` 'TRY401' # Redundant exception object included in `logging.exception` call ] -exclude = ["tests/fixtures/**", ".git"] +select = ["ALL"] -[tool.ruff.flake8-pytest-style] +[tool.ruff.lint.flake8-pytest-style] parametrize-values-type = "tuple" -[tool.ruff.isort] +[tool.ruff.lint.isort] force-single-line = true # Force from .. import to be 1 per line known-first-party = ["ansible_navigator"] lines-after-imports = 2 # Ensures consistency for cases when there's variable vs function/class definitions after imports lines-between-types = 1 # Separate import/from with 1 line -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = "pep257" [tool.setuptools.dynamic] diff --git a/src/ansible_navigator/action_base.py b/src/ansible_navigator/action_base.py index 1b50ee516..695c781f4 100644 --- a/src/ansible_navigator/action_base.py +++ b/src/ansible_navigator/action_base.py @@ -41,9 +41,9 @@ def __init__(self, args: ApplicationConfiguration, name: str, logger_name: str = self._calling_app: AppPublic self._interaction: Interaction self._name = name - self._previous_filter: Pattern | None + self._previous_filter: Pattern[str] | None self._previous_scroll: int - self.stdout: list = [] + self.stdout: list[str] = [] self.steps = Steps() @staticmethod @@ -168,7 +168,7 @@ def update(self) -> None: def _update_args( self, - params: list, + params: list[str], apply_previous_cli_entries: C = C.ALL, attach_cdc: bool = False, ) -> bool: diff --git a/src/ansible_navigator/action_defs.py b/src/ansible_navigator/action_defs.py index 577ae1e2d..bbe732d93 100644 --- a/src/ansible_navigator/action_defs.py +++ b/src/ansible_navigator/action_defs.py @@ -3,7 +3,6 @@ from __future__ import annotations from typing import NamedTuple -from typing import Union class RunReturn(NamedTuple): diff --git a/src/ansible_navigator/actions/__init__.py b/src/ansible_navigator/actions/__init__.py index dc4e6aec4..4ae5587a0 100644 --- a/src/ansible_navigator/actions/__init__.py +++ b/src/ansible_navigator/actions/__init__.py @@ -17,7 +17,6 @@ from collections.abc import Callable from typing import Any -from typing import Optional from ansible_navigator.action_defs import RunStdoutReturn from ansible_navigator.app_public import AppPublic @@ -31,7 +30,7 @@ names = actions.names_factory(__package__) -kegexes: Callable = actions.kegexes_factory(__package__) +kegexes: Callable[..., Any] = actions.kegexes_factory(__package__) run_action_stdout: Callable[ [str, ApplicationConfiguration], diff --git a/src/ansible_navigator/actions/_actions.py b/src/ansible_navigator/actions/_actions.py index 8ee4d990d..89ab32c5e 100644 --- a/src/ansible_navigator/actions/_actions.py +++ b/src/ansible_navigator/actions/_actions.py @@ -26,7 +26,7 @@ Kegex = namedtuple("Kegex", ("name", "kegex")) # Dictionary with information about all registered actions -_ACTIONS: dict[str, dict] = {} +_ACTIONS: dict[str, dict[str, Any]] = {} def _import(package: str, action: str) -> None: @@ -60,7 +60,7 @@ def register(cls: Any) -> Any: return cls -def get(package: str, action: str) -> Callable: +def get(package: str, action: str) -> Callable[..., Any]: """Import and return a given action. :param package: The name of the package @@ -71,7 +71,7 @@ def get(package: str, action: str) -> Callable: return _ACTIONS[package][action].cls -def get_factory(package: str) -> Callable: +def get_factory(package: str) -> Callable[..., Any]: """Create a ``get()`` function for one package. :param package: The name of the package @@ -80,7 +80,7 @@ def get_factory(package: str) -> Callable: return functools.partial(get, package) -def kegex(package: str, action: str) -> tuple: +def kegex(package: str, action: str) -> tuple[str, str, str]: """Return a tuple of name, class, ``kegex`` for an action. :param package: The name of the package @@ -91,7 +91,7 @@ def kegex(package: str, action: str) -> tuple: return _ACTIONS[package][action] -def kegexes(package: str) -> Generator: +def kegexes(package: str) -> Generator[tuple[str, str, str], None, None]: """Return a tuple of tuples, name, ``kegex`` for all actions. :param package: The name of the package @@ -101,7 +101,7 @@ def kegexes(package: str) -> Generator: return (kegex(package, name) for name in names(package)) -def kegexes_factory(package: str) -> Callable: +def kegexes_factory(package: str) -> Callable[..., Any]: """Create a ``kegexes()`` function for all packages. :param package: The name of the package @@ -110,7 +110,7 @@ def kegexes_factory(package: str) -> Callable: return functools.partial(kegexes, package) -def names(package: str) -> list: +def names(package: str) -> list[str]: """List all actions in one package. :param package: The name of the package @@ -120,7 +120,7 @@ def names(package: str) -> list: return sorted(_ACTIONS[package]) -def names_factory(package: str) -> Callable: +def names_factory(package: str) -> Callable[..., Any]: """Create a ``names()`` function for one package. :param package: The name of the package @@ -163,7 +163,7 @@ def run_interactive(package: str, action: str, *args: Any, **_kwargs: Any) -> An return None -def run_interactive_factory(package: str) -> Callable: +def run_interactive_factory(package: str) -> Callable[..., Any]: """Create a ``run_interactive()`` function for one package. :param package: The name of the package @@ -186,7 +186,7 @@ def run_stdout(package: str, action: str, *args: Any, **_kwargs: Any) -> RunStdo return action_cls(args).run_stdout() -def run_stdout_factory(package: str) -> Callable: +def run_stdout_factory(package: str) -> Callable[..., Any]: """Create a ``run_stdout()`` function for one package. :param package: The name of the package diff --git a/src/ansible_navigator/actions/builder.py b/src/ansible_navigator/actions/builder.py index 3692894e1..692f29b1f 100644 --- a/src/ansible_navigator/actions/builder.py +++ b/src/ansible_navigator/actions/builder.py @@ -46,7 +46,7 @@ def run_stdout(self) -> RunStdoutReturn: _out, error, return_code = response return RunStdoutReturn(message=error, return_code=return_code) - def _run_runner(self) -> tuple | None: + def _run_runner(self) -> tuple[str, str, int] | None: """Spin up runner. :raises RuntimeError: When ansible-builder can not be found diff --git a/src/ansible_navigator/actions/collections.py b/src/ansible_navigator/actions/collections.py index 51c8ad7ac..80a0e19cf 100644 --- a/src/ansible_navigator/actions/collections.py +++ b/src/ansible_navigator/actions/collections.py @@ -100,9 +100,9 @@ def __init__(self, args: ApplicationConfiguration): self._adjacent_collection_dir: str self._collection_cache: KeyValueStore self._collection_cache_path: str - self._collection_scanned_paths: list = [] - self._collections: list = [] - self._stats: dict = {} + self._collection_scanned_paths: list[str] = [] + self._collections: list[Any] = [] + self._stats: dict[str, Any] = {} def update(self) -> None: """Request calling app update, no collection update is required.""" @@ -596,13 +596,15 @@ def _parse(self, output) -> None: return None - def _get_collection_plugins_details(self, selected_collection: dict) -> dict: + def _get_collection_plugins_details( + self, selected_collection: dict[str, Any] + ) -> dict[str, Any]: """Get plugin details for the given collection. :param selected_collection: The selected collection :returns: The plugin details like full-name, type and short description. """ - plugins_details: dict = {} + plugins_details: dict[str, Any] = {} for plugin_checksum, plugin_info in selected_collection["plugin_checksums"].items(): plugin_type = plugin_info.get("type") @@ -639,13 +641,13 @@ def _get_collection_plugins_details(self, selected_collection: dict) -> dict: return plugins_details - def _parse_collection_info_stdout(self) -> dict: + def _parse_collection_info_stdout(self) -> dict[str, Any]: # pylint: disable=too-many-nested-blocks """Parse collection information from catalog collection cache. :returns: The collection information to be displayed on stdout """ - collections_info: dict = { + collections_info: dict[str, Any] = { "collections": [], } collection_exclude_keys = [ @@ -662,7 +664,7 @@ def _parse_collection_info_stdout(self) -> dict: for collection in self._collections: plugins_details = self._get_collection_plugins_details(collection) - collection_stdout: dict = {} + collection_stdout: dict[str, Any] = {} for info_name, info_value in collection.items(): info_name = remove_dbl_un(info_name) if info_name in collection_exclude_keys: diff --git a/src/ansible_navigator/actions/config.py b/src/ansible_navigator/actions/config.py index 8f918334b..5737abe14 100644 --- a/src/ansible_navigator/actions/config.py +++ b/src/ansible_navigator/actions/config.py @@ -148,7 +148,12 @@ def run_stdout(self) -> RunStdoutReturn: """ self._logger.debug("config requested in stdout mode") response = self._run_runner() - if response is None: + if ( + response is None + or response[0] is None + or response[1] is None + or not isinstance(response[2], int) + ): self._logger.error("Unexpected response: %s", response) return RunStdoutReturn(message="Please review the log for errors.", return_code=1) _out, error, return_code = response @@ -209,7 +214,7 @@ def _build_option_content(self): index=self.steps.current.index, ) - def _run_runner(self) -> tuple | None: + def _run_runner(self) -> tuple[str, str, int] | None: """Use the runner subsystem to retrieve the configuration. :raises RuntimeError: When the ansible-config command cannot be found with execution @@ -298,7 +303,7 @@ def _run_runner(self) -> tuple | None: self._runner = Command(executable_cmd=ansible_config_path, **kwargs) stdout_return = self._runner.run() return stdout_return - return (None, None, None) + return None def _parse_and_merge(self, list_output, dump_output) -> None: """Parse the list and dump output. Merge dump into list. diff --git a/src/ansible_navigator/actions/doc.py b/src/ansible_navigator/actions/doc.py index 2f5ec43bd..e1213c7e8 100644 --- a/src/ansible_navigator/actions/doc.py +++ b/src/ansible_navigator/actions/doc.py @@ -42,7 +42,7 @@ def __init__(self, args: ApplicationConfiguration): self._plugin_type: str | None = None self._runner: Command | AnsibleDoc - def generate_content_heading(self, _obj: dict, screen_w: int) -> CursesLines: + def generate_content_heading(self, _obj: dict[Any, Any], screen_w: int) -> CursesLines: """Create a heading for doc content. :param _obj: The content going to be shown @@ -133,7 +133,7 @@ def run_stdout(self) -> RunStdoutReturn: _out, error, return_code = response return RunStdoutReturn(message=error, return_code=return_code) - def _run_runner(self) -> dict | tuple[str, str, int] | None: + def _run_runner(self) -> dict[Any, Any] | tuple[str, str, int] | None: # pylint: disable=no-else-return """Use the runner subsystem to retrieve the configuration. diff --git a/src/ansible_navigator/actions/exec.py b/src/ansible_navigator/actions/exec.py index 0c17e4456..ee34ec11b 100644 --- a/src/ansible_navigator/actions/exec.py +++ b/src/ansible_navigator/actions/exec.py @@ -6,8 +6,6 @@ import os import shlex -from typing import Optional - from ansible_navigator.action_base import ActionBase from ansible_navigator.action_defs import RunStdoutReturn from ansible_navigator.configuration_subsystem.definitions import ApplicationConfiguration @@ -98,7 +96,7 @@ def run_stdout(self) -> RunStdoutReturn: _out, error, return_code = response return RunStdoutReturn(message=error, return_code=return_code) - def _run_runner(self) -> tuple | None: + def _run_runner(self) -> tuple[str, str, int] | None: """Spin up runner. :returns: The stdout, stderr and return code from runner diff --git a/src/ansible_navigator/actions/images.py b/src/ansible_navigator/actions/images.py index 075be725a..cec3209a2 100644 --- a/src/ansible_navigator/actions/images.py +++ b/src/ansible_navigator/actions/images.py @@ -61,7 +61,7 @@ def __init__(self, args: ApplicationConfiguration): :param args: The current settings for the application """ super().__init__(args=args, logger_name=__name__, name="images") - self._image_list: list = [] + self._image_list: list[str] = [] self._images = Step( name="images", step_type="menu", @@ -92,7 +92,9 @@ def color_menu(self, colno: int, colname: str, entry: dict[str, Any]) -> tuple[i return 12, 0 return 2, 0 - def generate_content_heading(self, obj: dict, screen_w: int, name: str = "") -> CursesLines: + def generate_content_heading( + self, obj: dict[Any, Any], screen_w: int, name: str = "" + ) -> CursesLines: """Create a heading for image content. :param obj: The content going to be shown @@ -516,7 +518,7 @@ def _introspect_image(self) -> bool: return False return True - def _parse(self, output) -> dict | None: + def _parse(self, output) -> dict[Any, Any] | None: """Load and process the ``json`` output from the image introspection process. :param output: The output from the image introspection process diff --git a/src/ansible_navigator/actions/inventory.py b/src/ansible_navigator/actions/inventory.py index 68507652b..51151434f 100644 --- a/src/ansible_navigator/actions/inventory.py +++ b/src/ansible_navigator/actions/inventory.py @@ -90,11 +90,11 @@ def filter_content_keys(obj: dict[Any, Any]) -> dict[Any, Any]: return {k: v for k, v in obj.items() if not k.startswith("__")} -class MenuEntry(dict): +class MenuEntry(dict[Any, Any]): """A menu entry.""" -class Menu(list): +class Menu(list[Any]): """A menu.""" @@ -129,7 +129,7 @@ def _inventory(self) -> dict[Any, Any]: return self.__inventory @_inventory.setter - def _inventory(self, value: dict) -> None: + def _inventory(self, value: dict[Any, Any]) -> None: """Set the inventory and hostvars. :param value: The inventory data @@ -146,7 +146,7 @@ def _inventory(self, value: dict) -> None: self._host_vars[host] = {"inventory_hostname": host} @property - def _show_columns(self) -> list: + def _show_columns(self) -> list[str]: """Return the columns to show for an inventory menu. :returns: The columns to show diff --git a/src/ansible_navigator/actions/lint.py b/src/ansible_navigator/actions/lint.py index 561e96c0c..3843c12f5 100644 --- a/src/ansible_navigator/actions/lint.py +++ b/src/ansible_navigator/actions/lint.py @@ -103,7 +103,7 @@ def color_menu(colno: int, colname: str, entry: dict[str, Any]) -> tuple[int, in return (severity_to_color(entry["severity"]), Color.BLACK) -def content_heading(obj: dict, screen_w: int) -> CursesLines: +def content_heading(obj: dict[Any, Any], screen_w: int) -> CursesLines: """Generate the content heading. :param obj: The content for which the heading will be generated @@ -140,7 +140,7 @@ def filter_content_keys(obj: dict[Any, Any]) -> dict[Any, Any]: return {k: v for k, v in obj.items() if not k.startswith("__") and k not in ignored_keys} -def massage_issue(issue: dict) -> dict: +def massage_issue(issue: dict[Any, Any]) -> dict[Any, Any]: """Massage an issue by injecting some useful keys with strings for rendering. :param issue: The issue reported diff --git a/src/ansible_navigator/actions/open_file.py b/src/ansible_navigator/actions/open_file.py index aece94157..a6b0da8c0 100644 --- a/src/ansible_navigator/actions/open_file.py +++ b/src/ansible_navigator/actions/open_file.py @@ -8,8 +8,8 @@ from collections.abc import Callable from pathlib import Path +from re import Pattern from typing import Any -from typing import Optional from ansible_navigator.app_public import AppPublic from ansible_navigator.configuration_subsystem.definitions import ApplicationConfiguration @@ -62,7 +62,7 @@ def __init__(self, args: ApplicationConfiguration): def _transform_menu( self, menu: Menu, - menu_filter: Callable, + menu_filter: Callable[..., Pattern[str] | None], serialization_format=SerializationFormat | None, ) -> list[dict[Any, Any]]: """Convert a menu into structured data. @@ -85,11 +85,12 @@ def _transform_menu( menu_entries = [ {remove_dbl_un(k): v for k, v in c.items() if k in menu.columns} for c in menu_entries ] - if menu_filter(): + menu_filter_result = menu_filter() + if menu_filter_result: menu_entries = [ e for e in menu_entries - if menu_filter().search(" ".join(str(v) for v in e.values())) + if menu_filter_result.search(" ".join(str(v) for v in e.values())) ] return menu_entries diff --git a/src/ansible_navigator/actions/run.py b/src/ansible_navigator/actions/run.py index 104cb7d0e..374de9827 100644 --- a/src/ansible_navigator/actions/run.py +++ b/src/ansible_navigator/actions/run.py @@ -208,7 +208,7 @@ def __init__(self, args: ApplicationConfiguration): self._subaction_type: str self._msg_from_plays: tuple[str | None, int | None] = (None, None) - self._queue: Queue = Queue() + self._queue: Queue[dict[str, str]] = Queue() self.runner: CommandAsync self._runner_finished: bool self._auto_scroll = False @@ -224,7 +224,7 @@ def __init__(self, args: ApplicationConfiguration): select_func=self._task_list_for_play, ) self._task_list_columns: list[str] = TASK_LIST_COLUMNS - self._content_key_filter: Callable = filter_content_keys + self._content_key_filter: Callable[[dict[Any, Any]], dict[Any, Any]] = filter_content_keys self._playbook_type: str = check_playbook_type(self._args.playbook) self._task_cache: dict[str, str] = {} """Task name storage from playbook_on_start using the task uuid as the key""" @@ -462,8 +462,7 @@ def _prompt_for_artifact(self, artifact_file: str) -> dict[Any, Any]: if not isinstance(artifact_file, str): artifact_file = "" - FType = dict[str, Any] - form_dict: FType = { + form_dict: dict[str, Any] = { "title": "Artifact file not found, please confirm the following", "fields": [], } @@ -491,8 +490,7 @@ def _prompt_for_playbook(self) -> dict[Any, Any]: cmdline = " ".join(self._args.cmdline) if isinstance(self._args.cmdline, list) else "" - FType = dict[str, Any] - form_dict: FType = { + form_dict: dict[str, Any] = { "title": "Playbook not found, please confirm the following", "fields": [], } @@ -637,7 +635,7 @@ def _dequeue(self) -> None: if drain_count: self._logger.debug("Drained %s events", drain_count) - def _handle_message(self, message: dict) -> None: + def _handle_message(self, message: dict[str, Any]) -> None: # pylint: disable=too-many-locals """Handle a runner message. diff --git a/src/ansible_navigator/actions/settings.py b/src/ansible_navigator/actions/settings.py index adba9b983..4e4333db2 100644 --- a/src/ansible_navigator/actions/settings.py +++ b/src/ansible_navigator/actions/settings.py @@ -4,6 +4,7 @@ from dataclasses import asdict from functools import partial +from typing import Any from ansible_navigator.action_base import ActionBase from ansible_navigator.action_defs import RunStdoutReturn @@ -15,6 +16,7 @@ from ansible_navigator.configuration_subsystem import to_sample from ansible_navigator.configuration_subsystem import to_schema from ansible_navigator.configuration_subsystem import to_sources +from ansible_navigator.configuration_subsystem.definitions import ApplicationConfiguration from ansible_navigator.configuration_subsystem.definitions import Constants from ansible_navigator.content_defs import ContentFormat from ansible_navigator.steps import StepType @@ -82,7 +84,7 @@ class Action(ActionBase): KEGEX = r"^se(?:ttings)?$" - def __init__(self, args): + def __init__(self, args: ApplicationConfiguration): """Initialize the ``:settings`` action. :param args: The current settings for the application @@ -147,7 +149,7 @@ def run_stdout(self) -> RunStdoutReturn: dump(content=to_presentable(self._args), content_format=ContentFormat.YAML) return RunStdoutReturn(message="", return_code=0) - def _build_main_menu(self) -> TypedStep: + def _build_main_menu(self) -> TypedStep[Any]: """Build the main menu of settings. :returns: The settings menu definition @@ -161,7 +163,7 @@ def _build_main_menu(self) -> TypedStep: step.value = self._settings return step - def _build_settings_content(self) -> TypedStep: + def _build_settings_content(self) -> TypedStep[Any]: """Build the content for one settings entry. :returns: The option's content diff --git a/src/ansible_navigator/app_public.py b/src/ansible_navigator/app_public.py index 3b3723e4a..1a7cccaa9 100644 --- a/src/ansible_navigator/app_public.py +++ b/src/ansible_navigator/app_public.py @@ -25,8 +25,8 @@ class AppPublic(NamedTuple): # Quoted due to https://github.com/sphinx-doc/sphinx/issues/10400 args: ApplicationConfiguration name: str - rerun: Callable + rerun: Callable[[], None] stdout: list[str] steps: Steps - update: Callable - write_artifact: Callable + update: Callable[..., None] + write_artifact: Callable[..., None] diff --git a/src/ansible_navigator/cli.py b/src/ansible_navigator/cli.py index 0eb832706..a9cb39441 100644 --- a/src/ansible_navigator/cli.py +++ b/src/ansible_navigator/cli.py @@ -141,7 +141,7 @@ def run(args: ApplicationConfiguration) -> ActionReturn: return RunReturn(message="", return_code=0) -def main(): +def main() -> None: """Start application here.""" messages: list[LogMessage] = log_dependencies() exit_messages: list[ExitMessage] = [] @@ -181,12 +181,12 @@ def main(): exit_messages.append(ExitMessage(message=exit_msg)) error_and_exit_early(exit_messages=exit_messages) - for entry in messages: - logger.log(level=entry.level, msg=entry.message) + for log_message in messages: + logger.log(level=log_message.level, msg=log_message.message) if exit_messages: - for exit_msg in exit_messages: - logger.log(level=exit_msg.level, msg=exit_msg.message) + for entry in exit_messages: + logger.log(level=entry.level, msg=entry.message) error_and_exit_early(exit_messages=exit_messages) os.environ.setdefault("ESCDELAY", "25") diff --git a/src/ansible_navigator/configuration_subsystem/configurator.py b/src/ansible_navigator/configuration_subsystem/configurator.py index 6a4023b91..d73f42c1c 100644 --- a/src/ansible_navigator/configuration_subsystem/configurator.py +++ b/src/ansible_navigator/configuration_subsystem/configurator.py @@ -33,7 +33,7 @@ def __init__( self, params: list[str], application_configuration: ApplicationConfiguration, - apply_previous_cli_entries: list | C = C.NONE, + apply_previous_cli_entries: list[str] | C = C.NONE, skip_roll_back: bool = False, ): """Initialize the configuration variables. diff --git a/src/ansible_navigator/configuration_subsystem/definitions.py b/src/ansible_navigator/configuration_subsystem/definitions.py index 80eaaf531..4c8006121 100644 --- a/src/ansible_navigator/configuration_subsystem/definitions.py +++ b/src/ansible_navigator/configuration_subsystem/definitions.py @@ -15,7 +15,6 @@ from typing import Any from typing import NewType from typing import TypeVar -from typing import Union from ansible_navigator.utils.functions import abs_user_path from ansible_navigator.utils.functions import oxfordcomma diff --git a/src/ansible_navigator/configuration_subsystem/defs_presentable.py b/src/ansible_navigator/configuration_subsystem/defs_presentable.py index 62a571e10..92f0bd530 100644 --- a/src/ansible_navigator/configuration_subsystem/defs_presentable.py +++ b/src/ansible_navigator/configuration_subsystem/defs_presentable.py @@ -3,10 +3,10 @@ from __future__ import annotations from dataclasses import dataclass +from typing import Any from typing import ClassVar from typing import NewType from typing import TypeVar -from typing import Union from ansible_navigator.content_defs import ContentBase @@ -17,7 +17,7 @@ from .utils import create_settings_file_sample -PresentableSettingsEntryValue = bool | dict | str | list +PresentableSettingsEntryValue = bool | dict[Any, Any] | str | list[str] CliT = TypeVar("CliT", bound="PresentableCliParameters") EntT = TypeVar("EntT", bound="PresentableSettingsEntry") @@ -54,11 +54,11 @@ def from_cli_params( @dataclass -class PresentableSettingsEntry(ContentBase): +class PresentableSettingsEntry(ContentBase[Any]): # pylint: disable=too-many-instance-attributes """A settings entry in a presentable structure.""" - choices: list + choices: list[str | bool] """The possible values""" current_settings_file: str """The path to the current settings file""" @@ -74,11 +74,11 @@ class PresentableSettingsEntry(ContentBase): """The environment variable""" name: str """The name""" - settings_file_sample: str | dict + settings_file_sample: str | dict[Any, Any] """A sample settings file snippet""" source: str """The source of the current value""" - subcommands: list + subcommands: list[str] """A list of subcommands where this entry is available""" version_added: str """The version this entry was added in""" @@ -104,7 +104,7 @@ def __lt__(self, other): @classmethod def for_settings_file( cls: type[EntT], - all_subcommands: list, + all_subcommands: list[str], application_name: str, internals: Internals, ) -> EntT: @@ -138,7 +138,7 @@ def for_settings_file( @classmethod def from_settings_entry( cls: type[EntT], - all_subcommands: list, + all_subcommands: list[str], application_name_dashed: str, entry: SettingsEntry, settings_file_path: str, diff --git a/src/ansible_navigator/configuration_subsystem/parser.py b/src/ansible_navigator/configuration_subsystem/parser.py index ab5ec8d67..bbcb3834b 100644 --- a/src/ansible_navigator/configuration_subsystem/parser.py +++ b/src/ansible_navigator/configuration_subsystem/parser.py @@ -84,7 +84,7 @@ def _add_parser(self, group, entry) -> None: else: group.add_argument(short, long, **kwargs) - def _add_subcommand_holder(self) -> _SubParsersAction: + def _add_subcommand_holder(self) -> _SubParsersAction[Any]: """Add the subparsers holder. :raises ValueError: if zero or more than one subcommand is found diff --git a/src/ansible_navigator/configuration_subsystem/transform.py b/src/ansible_navigator/configuration_subsystem/transform.py index 821d1df9e..32c29181c 100644 --- a/src/ansible_navigator/configuration_subsystem/transform.py +++ b/src/ansible_navigator/configuration_subsystem/transform.py @@ -28,11 +28,11 @@ def to_effective( :param settings: The current settings :returns: The settings represented as settings file """ - rebuilt: dict = {} + rebuilt: dict[Any, Any] = {} for entry in settings.entries: path = entry.settings_file_path(prefix=settings.application_name_dashed) if not isinstance(entry.value.current, Constants): - current: bool | int | str | dict | list = entry.value.current + current: bool | int | str | dict[Any, Any] | list[Any] = entry.value.current # It is necessary to un post-process here if path == "ansible-navigator.ansible.cmdline": # post-processed into a list @@ -110,7 +110,7 @@ def to_schema(settings: ApplicationConfiguration) -> dict[str, Any]: partial_schema = json.loads(file_contents) for entry in settings.entries: - subschema: dict = partial_schema["properties"] + subschema: dict[Any, Any] = partial_schema["properties"] dot_parts = entry.settings_file_path(prefix=settings.application_name_dashed).split(".") for part in dot_parts[:-1]: if isinstance(subschema, dict): diff --git a/src/ansible_navigator/content_defs.py b/src/ansible_navigator/content_defs.py index cd277cf02..e53f0b895 100644 --- a/src/ansible_navigator/content_defs.py +++ b/src/ansible_navigator/content_defs.py @@ -10,7 +10,6 @@ from typing import Any from typing import Generic from typing import TypeVar -from typing import Union if TYPE_CHECKING: diff --git a/src/ansible_navigator/data/image_introspect.py b/src/ansible_navigator/data/image_introspect.py index 60f9e9453..451e4e310 100644 --- a/src/ansible_navigator/data/image_introspect.py +++ b/src/ansible_navigator/data/image_introspect.py @@ -13,7 +13,6 @@ from queue import Queue from types import SimpleNamespace from typing import Any -from typing import Union JSONTypes = bool | int | str | dict | list @@ -27,8 +26,8 @@ class Command(SimpleNamespace): parse: Callable stdout: str = "" stderr: str = "" - details: list | dict | str = "" - errors: list = [] + details: list[str] | dict[Any, Any] | str = "" + errors: list[str] = [] def run_command(command: Command) -> None: @@ -381,7 +380,7 @@ def main(serialize: bool = True) -> dict[str, JSONTypes] | None: :param serialize: Whether to serialize the results :returns: The collected data or none if serialize is False """ - response: dict = {"errors": []} + response: dict[str, Any] = {"errors": []} response["python_version"] = {"details": {"version": " ".join(sys.version.splitlines())}} response["environment_variables"] = {"details": dict(os.environ)} try: diff --git a/src/ansible_navigator/diagnostics.py b/src/ansible_navigator/diagnostics.py index fc97fdcb8..90fcdbfe2 100644 --- a/src/ansible_navigator/diagnostics.py +++ b/src/ansible_navigator/diagnostics.py @@ -15,7 +15,6 @@ from pathlib import Path from sys import stdout from typing import Any -from typing import Union from .command_runner import Command from .command_runner import CommandRunner @@ -36,7 +35,7 @@ from .utils.serialize import yaml -JSONTypes = bool | int | str | dict | list[Any] +JSONTypes = bool | int | str | dict[Any, Any] | list[Any] @dataclass @@ -193,7 +192,7 @@ def __init__( self._exit_messages = exit_messages @property - def registered(self) -> Iterator[Callable]: + def registered(self) -> Iterator[Callable[..., Any]]: """Return the registered diagnostics. :returns: The registered diagnostics diff --git a/src/ansible_navigator/image_manager/introspector.py b/src/ansible_navigator/image_manager/introspector.py index 663a9c261..4210f933e 100644 --- a/src/ansible_navigator/image_manager/introspector.py +++ b/src/ansible_navigator/image_manager/introspector.py @@ -8,6 +8,7 @@ import tempfile from pathlib import Path +from typing import Any from ansible_navigator.data import image_introspect from ansible_navigator.runner import Command @@ -16,7 +17,7 @@ logger = logging.getLogger(__name__) -def run(image_name: str, container_engine: str) -> tuple[dict, list[str], int]: +def run(image_name: str, container_engine: str) -> tuple[dict[Any, Any], list[str], int]: """Run runner to collect image details. :param image_name: The full image name @@ -48,7 +49,7 @@ def run(image_name: str, container_engine: str) -> tuple[dict, list[str], int]: return parsed, errors, return_code -def parse(output) -> tuple[list[str], dict]: +def parse(output: str) -> tuple[list[str], dict[Any, Any]]: """Load and process the ``json`` output from the image introspection process. :param output: The output from the image introspection process diff --git a/src/ansible_navigator/initialization.py b/src/ansible_navigator/initialization.py index edb5b59e3..f4c13afc5 100644 --- a/src/ansible_navigator/initialization.py +++ b/src/ansible_navigator/initialization.py @@ -162,7 +162,7 @@ def _diagnose( def parse_and_update( - params: list, + params: list[str], args: ApplicationConfiguration, apply_previous_cli_entries: C | list[str] = C.NONE, attach_cdc=False, diff --git a/src/ansible_navigator/runner/base.py b/src/ansible_navigator/runner/base.py index f44d91b94..537a32db6 100644 --- a/src/ansible_navigator/runner/base.py +++ b/src/ansible_navigator/runner/base.py @@ -28,11 +28,11 @@ def __init__( execution_environment: bool | None = False, execution_environment_image: str | None = None, navigator_mode: str | None = None, - container_volume_mounts: list | None = None, - container_options: list | None = None, + container_volume_mounts: list[str] | None = None, + container_options: list[str] | None = None, container_workdir: str | None = None, - set_environment_variable: dict | None = None, - pass_environment_variable: list | None = None, + set_environment_variable: dict[str, str] | None = None, + pass_environment_variable: list[str] | None = None, host_cwd: str | None = None, rotate_artifacts: int | None = None, timeout: int | None = None, diff --git a/src/ansible_navigator/steps.py b/src/ansible_navigator/steps.py index 66b18ea69..f0aaffd4b 100644 --- a/src/ansible_navigator/steps.py +++ b/src/ansible_navigator/steps.py @@ -159,7 +159,7 @@ class TypedStep(Generic[T]): _value_changed: bool = False _value: Sequence[T] = field(default_factory=list) columns: list[str] | None = None - select_func: Callable[[], TypedStep] | None = None + select_func: Callable[[], TypedStep[Any]] | None = None show_func: Callable[[], None] | None = None @property @@ -224,7 +224,7 @@ def value(self, value: Sequence[T]) -> None: self._value = value -class Steps(deque): +class Steps(deque[Any]): """A custom deque.""" def back_one(self) -> Any: diff --git a/src/ansible_navigator/tm_tokenize/reg.py b/src/ansible_navigator/tm_tokenize/reg.py index 7a063c757..14ef9d398 100644 --- a/src/ansible_navigator/tm_tokenize/reg.py +++ b/src/ansible_navigator/tm_tokenize/reg.py @@ -5,7 +5,6 @@ from re import Match from typing import TYPE_CHECKING -from typing import Optional import onigurumacffi diff --git a/src/ansible_navigator/tm_tokenize/rules.py b/src/ansible_navigator/tm_tokenize/rules.py index c74610b67..52919b9f3 100644 --- a/src/ansible_navigator/tm_tokenize/rules.py +++ b/src/ansible_navigator/tm_tokenize/rules.py @@ -4,7 +4,6 @@ from typing import TYPE_CHECKING from typing import Any from typing import NamedTuple -from typing import Optional from ._types import Protocol from .fchainmap import FChainMap diff --git a/src/ansible_navigator/ui_framework/form.py b/src/ansible_navigator/ui_framework/form.py index 868f729ce..b6afdc598 100644 --- a/src/ansible_navigator/ui_framework/form.py +++ b/src/ansible_navigator/ui_framework/form.py @@ -179,9 +179,6 @@ def _generate_form(self) -> tuple[tuple[int, CursesLine], ...]: field for field in self._form.fields if field.name not in ["submit", "cancel"] ] for form_field in body_fields: - # pylint: disable=not-an-iterable - # https://github.com/PyCQA/pylint/issues/2296 - if isinstance(form_field, (FieldCursesInformation)): for line in form_field.information: lines.append((self._line_number, line)) diff --git a/src/ansible_navigator/ui_framework/form_defs.py b/src/ansible_navigator/ui_framework/form_defs.py index e65d2bcfc..bcf57fb14 100644 --- a/src/ansible_navigator/ui_framework/form_defs.py +++ b/src/ansible_navigator/ui_framework/form_defs.py @@ -3,7 +3,6 @@ from __future__ import annotations from enum import Enum -from typing import Union from .sentinels import Unknown diff --git a/src/ansible_navigator/ui_framework/ui.py b/src/ansible_navigator/ui_framework/ui.py index f6ad7be89..8b90ef15b 100644 --- a/src/ansible_navigator/ui_framework/ui.py +++ b/src/ansible_navigator/ui_framework/ui.py @@ -57,7 +57,7 @@ class Action(NamedTuple): """the user's input.""" value: str | int - match: Match + match: Match[str] class Content(NamedTuple): @@ -97,11 +97,11 @@ def __call__( obj: ContentType, content_format: ContentFormat | None = None, index: int | None = None, - columns: list | None = None, + columns: list[str] | None = None, await_input: bool = True, - filter_content_keys: Callable = lambda x: x, - color_menu_item: Callable = lambda *args, **kwargs: (0, 0), - content_heading: Callable = lambda *args, **kwargs: None, + filter_content_keys: Callable[..., Any] = lambda x: x, + color_menu_item: Callable[..., Any] = lambda *args, **kwargs: (0, 0), + content_heading: Callable[..., Any] = lambda *args, **kwargs: None, ) -> Interaction: """Refer to and keep in sync with UserInterface.show. @@ -119,12 +119,12 @@ def __call__( class Ui(NamedTuple): """select functions that can be called from an action.""" - clear: Callable - menu_filter: Callable - scroll: Callable + clear: Callable[..., Any] + menu_filter: Callable[..., Any] + scroll: Callable[..., Any] show: ShowCallable show_form: Callable[[Form], Form] - update_status: Callable + update_status: Callable[..., Any] content_format: ContentFormatCallable @@ -175,7 +175,7 @@ def __init__( self._hide_keys = True self._kegexes = kegexes self._logger = logging.getLogger(__name__) - self._menu_filter: Pattern | None = None + self._menu_filter: Pattern[str] | None = None self._menu_indices: tuple[int, ...] = tuple() self._progress_bar_width = progress_bar_width @@ -217,7 +217,7 @@ def update_status(self, status: str = "", status_color: int = 0) -> None: self._status = status self._status_color = status_color - def menu_filter(self, value: str | None = "") -> Pattern | None: + def menu_filter(self, value: str | None = "") -> Pattern[str] | None: """Set or return the menu filter. :param value: None or the menu_filter regex to set @@ -407,7 +407,7 @@ def _display( line_numbers: tuple[int, ...], heading: CursesLines | None, indent_heading: int, - key_dict: dict, + key_dict: dict[Any, Any], await_input: bool, count: int, ) -> str: @@ -574,7 +574,7 @@ def _serialize_color(self, obj: Any) -> CursesLines: self._cache_init_colors(rendered) return self._color_decorate_lines(rendered) - def _cache_init_colors(self, lines: list): + def _cache_init_colors(self, lines: list[list[SimpleLinePart]]): """Cache and init the unique colors for future use. Maintain a mapping of RGB colors @@ -767,7 +767,7 @@ def _show_obj_from_list( content = Content(showing=filtered) return Interaction(name=name, action=action, content=content, ui=self._ui) - def _obj_match_filter(self, obj: dict, columns: list) -> bool: + def _obj_match_filter(self, obj: dict[Any, Any], columns: list[str]) -> bool: """Check columns in a dictionary against a regex. :param obj: The dict to check @@ -778,7 +778,7 @@ def _obj_match_filter(self, obj: dict, columns: list) -> bool: @staticmethod @cache - def _search_value(regex: Pattern, value: str) -> Match | None: + def _search_value(regex: Pattern[str], value: str) -> Match[str] | None: """Check a str against a regex. :param regex: the compiled regex @@ -790,7 +790,7 @@ def _search_value(regex: Pattern, value: str) -> Match | None: def _get_heading_menu_items( self, current: Sequence[Any], - columns: list, + columns: list[str], indices, ) -> tuple[CursesLines, CursesLines]: """Build the menu. @@ -810,7 +810,9 @@ def _get_heading_menu_items( menu_heading, menu_items = menu_builder.build(current, columns, indices) return menu_heading, menu_items - def _show_menu(self, current: Sequence[Any], columns: list, await_input: bool) -> Interaction: + def _show_menu( + self, current: Sequence[Any], columns: list[str], await_input: bool + ) -> Interaction: """Show a menu on the screen. :param current: A dict @@ -872,11 +874,11 @@ def show( obj: ContentType, content_format: ContentFormat | None = None, index: int | None = None, - columns: list | None = None, + columns: list[str] | None = None, await_input: bool = True, - filter_content_keys: Callable = lambda x: x, - color_menu_item: Callable = lambda *args, **kwargs: (0, 0), - content_heading: Callable = lambda *args, **kwargs: None, + filter_content_keys: Callable[..., Any] = lambda x: x, + color_menu_item: Callable[..., Any] = lambda *args, **kwargs: (0, 0), + content_heading: Callable[..., Any] = lambda *args, **kwargs: None, ) -> Interaction: """Show something on the screen. diff --git a/src/ansible_navigator/ui_framework/validators.py b/src/ansible_navigator/ui_framework/validators.py index a5a13d8fc..7fc238ece 100644 --- a/src/ansible_navigator/ui_framework/validators.py +++ b/src/ansible_navigator/ui_framework/validators.py @@ -83,7 +83,7 @@ def null(text="", hint: bool = False) -> Validation | str: return Validation(value=text, error_msg="") @staticmethod - def one_of(choices: list = [], text: str = "", hint: bool = False) -> Validation | str: + def one_of(choices: list[str] = [], text: str = "", hint: bool = False) -> Validation | str: """Validate that some text is one of choices. :param choices: The list of choices diff --git a/src/ansible_navigator/utils/compatibility.py b/src/ansible_navigator/utils/compatibility.py index 6f7ac045d..7104b731f 100644 --- a/src/ansible_navigator/utils/compatibility.py +++ b/src/ansible_navigator/utils/compatibility.py @@ -1,21 +1,17 @@ """Conditional imports related to python versions.""" -# pylint: disable=unused-import - +import importlib.metadata as importlib_metadata import sys -from typing import TYPE_CHECKING - - -if TYPE_CHECKING: - # https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases - from typing import TypeAlias - -import importlib.metadata as importlib_metadata +# https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases +from typing import TypeAlias if sys.version_info < (3, 11): from importlib.abc import Traversable else: from importlib.resources.abc import Traversable + + +__all__ = ["Traversable", "importlib_metadata", "TypeAlias"] diff --git a/src/ansible_navigator/utils/dict_merge.py b/src/ansible_navigator/utils/dict_merge.py index a17423be5..40b7ddd98 100644 --- a/src/ansible_navigator/utils/dict_merge.py +++ b/src/ansible_navigator/utils/dict_merge.py @@ -2,15 +2,14 @@ from __future__ import annotations -from typing import Optional -from typing import Union +from typing import Any class DictMergeError(Exception): """Custom exception for a dict merge error.""" -Mergeable = bool | dict | list | str | None +Mergeable = bool | dict[Any, Any] | list[Any] | str | None def in_place_list_replace(left: Mergeable, right: Mergeable): diff --git a/src/ansible_navigator/utils/dot_paths.py b/src/ansible_navigator/utils/dot_paths.py index f8d035bfc..9046f4f0f 100644 --- a/src/ansible_navigator/utils/dot_paths.py +++ b/src/ansible_navigator/utils/dot_paths.py @@ -8,6 +8,7 @@ from collections.abc import MutableMapping from enum import Enum from functools import reduce +from typing import Any class MergeBehaviors(Enum): @@ -23,7 +24,7 @@ class MergeBehaviors(Enum): DICT_DICT_REPLACE = "replace left dict with right dict" -def get_with_path(content: MutableMapping, path: str): +def get_with_path(content: MutableMapping[Any, Any], path: str): """Get a value from a path in a dictionary. :param content: The content of the settings file @@ -33,7 +34,7 @@ def get_with_path(content: MutableMapping, path: str): return reduce(operator.getitem, path.split("."), content) -def check_path(content: MutableMapping, path: str): +def check_path(content: MutableMapping[Any, Any], path: str): """Check if a path exists in a dictionary. :param content: The content of the settings file @@ -47,7 +48,7 @@ def check_path(content: MutableMapping, path: str): return False -def delete_with_path(content: MutableMapping, path: str): +def delete_with_path(content: MutableMapping[Any, Any], path: str): """Delete a value from a path in a dictionary. :param content: The content of the settings file @@ -77,7 +78,7 @@ def descendants_to_path(path: str): return [path.rsplit(".", i)[0] for i in reversed(range(len(parts)))] -def remove_and_delete_empty_ascendants(content: MutableMapping, path: str): +def remove_and_delete_empty_ascendants(content: MutableMapping[Any, Any], path: str): """Remove and delete empty ascendants. :param content: The content of the settings file diff --git a/src/ansible_navigator/utils/json_schema.py b/src/ansible_navigator/utils/json_schema.py index 558acdcaf..e62d39e89 100644 --- a/src/ansible_navigator/utils/json_schema.py +++ b/src/ansible_navigator/utils/json_schema.py @@ -15,7 +15,7 @@ from .functions import ExitMessage -def to_path(schema_path: deque): +def to_path(schema_path: deque[Any]) -> str: """Flatten a path to a dot delimited string. :param schema_path: The schema path @@ -24,7 +24,7 @@ def to_path(schema_path: deque): return ".".join(str(index) for index in schema_path) -def json_path(absolute_path: deque): +def json_path(absolute_path: deque[Any]) -> str: """Flatten a data path to a dot delimited string. :param absolute_path: The path @@ -79,6 +79,9 @@ def validate(schema: str | dict[str, Any], data: dict[str, Any]) -> list[JsonSch if isinstance(schema, str): schema = json.loads(schema) + if isinstance(schema, bool): + msg = "Unexpected schema data." + raise RuntimeError(msg) validator = validator_for(schema) try: validator.check_schema(schema) diff --git a/src/ansible_navigator/utils/version_migration/migrate.py b/src/ansible_navigator/utils/version_migration/migrate.py index 3f8ae7f93..87cc95156 100644 --- a/src/ansible_navigator/utils/version_migration/migrate.py +++ b/src/ansible_navigator/utils/version_migration/migrate.py @@ -20,7 +20,7 @@ # isort: off # pylint: disable=unused-import # Migrations will run in the order they are imported -from .v1_v2_settings_file import V1V2SettingsFile +from .v1_v2_settings_file import V1V2SettingsFile # noqa: F401 # isort: on diff --git a/tests/integration/_action_run_test.py b/tests/integration/_action_run_test.py index 3f272e683..fc0c3787a 100644 --- a/tests/integration/_action_run_test.py +++ b/tests/integration/_action_run_test.py @@ -33,12 +33,12 @@ def __init__( self, action_name, container_engine: str | None = None, - container_options: list | None = None, + container_options: list[str] | None = None, execution_environment: str | None = None, execution_environment_image: str | None = None, - host_cwd: list | None = None, - set_environment_variable: dict | None = None, - pass_environment_variable: list | None = None, + host_cwd: list[str] | None = None, + set_environment_variable: dict[str, str] | None = None, + pass_environment_variable: list[str] | None = None, private_data_dir: str | None = None, rotate_artifacts: int | None = None, timeout: int | None = None, @@ -118,11 +118,11 @@ def show( obj: ContentType, content_format: ContentFormat | None = None, index: int | None = None, - columns: list | None = None, + columns: list[str] | None = None, await_input: bool = True, - filter_content_keys: Callable = lambda x: x, - color_menu_item: Callable = lambda *args, **kwargs: (0, 0), - content_heading: Callable = lambda *args, **kwargs: None, + filter_content_keys: Callable[..., Any] = lambda x: x, + color_menu_item: Callable[..., Any] = lambda *args, **kwargs: (0, 0), + content_heading: Callable[..., Any] = lambda *args, **kwargs: None, ) -> None: """Show a content object, but don't really. diff --git a/tests/integration/_interactions.py b/tests/integration/_interactions.py index fa39aa6f4..006def610 100644 --- a/tests/integration/_interactions.py +++ b/tests/integration/_interactions.py @@ -25,7 +25,7 @@ class Command(NamedTuple): format_: str | None = None log_level: str = "debug" mode: str = "interactive" - pass_environment_variables: list = [] + pass_environment_variables: list[str] = [] preclear: bool = False precommand: str = "" raw_append: str = "" @@ -76,7 +76,7 @@ class UiTestStep(NamedTuple): #: The index of the step with the list of all steps step_index: int = 0 #: Find this before returning from the tmux session to the test - search_within_response: SearchFor | str | list = SearchFor.HELP + search_within_response: SearchFor | str | list[str] = SearchFor.HELP def __str__(self) -> str: """Produce a test id for this step. diff --git a/tests/integration/_tmux_session.py b/tests/integration/_tmux_session.py index 0b59af959..eb89d6206 100644 --- a/tests/integration/_tmux_session.py +++ b/tests/integration/_tmux_session.py @@ -47,7 +47,7 @@ def __init__( pane_height: int = 20, pane_width: int = 200, pull_policy: str = "never", - setup_commands: list | None = None, + setup_commands: list[str] | None = None, shell_prompt_timeout: int = 10, ) -> None: """Initialize a tmux session. @@ -66,7 +66,7 @@ def __init__( self.cli_prompt: str self._config_path = config_path self._cwd = cwd - self._fail_remaining: list = [] + self._fail_remaining: list[str] = [] self._pane_height = pane_height self._pane_width = pane_width self._pull_policy = pull_policy @@ -112,7 +112,6 @@ def __enter__(self) -> TmuxSession: :raises ValueError: If the time is exceeded for finding the shell prompt """ # pylint: disable=attribute-defined-outside-init - # pylint: disable=too-many-locals self._server = libtmux.Server() self._build_tmux_session() @@ -233,7 +232,7 @@ def _capture_pane(self) -> list[str]: def interaction( self, value: str, - search_within_response: list | str | None = None, + search_within_response: list[str] | str | None = None, ignore_within_response: str | None = None, timeout: int = 300, send_clear: bool = True, diff --git a/tests/integration/actions/doc/test_direct_interactive_ee.py b/tests/integration/actions/doc/test_direct_interactive_ee.py index 84dda1b23..23c26c082 100644 --- a/tests/integration/actions/doc/test_direct_interactive_ee.py +++ b/tests/integration/actions/doc/test_direct_interactive_ee.py @@ -10,9 +10,11 @@ # module doc CLI_MODULE_DOC = "ansible-navigator doc company_name.coll_1.mod_1 --execution-environment true" -testdata_module_doc: list = [ - (0, CLI_MODULE_DOC, "ansible-navigator doc module plugin display", "module_doc_pass", []), - (1, ":{{ examples }}", "load examples", "module_doc_pass", []), +testdata_module_doc = [ + pytest.param( + 0, CLI_MODULE_DOC, "ansible-navigator doc module plugin display", "module_doc_pass", [] + ), + pytest.param(1, ":{{ examples }}", "load examples", "module_doc_pass", []), ] # lookup plugin doc @@ -20,8 +22,10 @@ "ansible-navigator doc company_name.coll_1.lookup_1 -t lookup --execution-environment true" ) -testdata_lookup_doc: list = [ - (0, CLI_LOOKUP_DOC, "ansible-navigator doc lookup plugin display", "lookup_doc_pass", []), +testdata_lookup_doc = [ + pytest.param( + 0, CLI_LOOKUP_DOC, "ansible-navigator doc lookup plugin display", "lookup_doc_pass", [] + ), ] # filter plugin doc @@ -29,8 +33,15 @@ "ansible-navigator doc company_name.coll_1.filter_1 -t filter --execution-environment true" ) -testdata_filter_doc: list = [ - (0, CLI_FILTER_DOC, "ansible-navigator doc filter plugin display", "filter_doc_pass", []), +testdata_filter_doc = [ + pytest.param( + 0, + CLI_FILTER_DOC, + "ansible-navigator doc filter plugin display", + "filter_doc_pass", + [], + id="filter_doc", + ), ] # plugin does not exist diff --git a/tests/integration/actions/doc/test_direct_interactive_noee.py b/tests/integration/actions/doc/test_direct_interactive_noee.py index 397a08eed..9aa06f8ad 100644 --- a/tests/integration/actions/doc/test_direct_interactive_noee.py +++ b/tests/integration/actions/doc/test_direct_interactive_noee.py @@ -9,25 +9,31 @@ # module doc CLI_MODULE_DOC = "ansible-navigator doc company_name.coll_1.mod_1 --execution-environment false" -testdata_module_doc: list = [ - (0, CLI_MODULE_DOC, "ansible-navigator doc module plugin display", "module_doc_pass", []), - (1, ":{{ examples }}", "load examples", "module_doc_pass", []), +testdata_module_doc = [ + pytest.param( + 0, CLI_MODULE_DOC, "ansible-navigator doc module plugin display", "module_doc_pass", [] + ), + pytest.param(1, ":{{ examples }}", "load examples", "module_doc_pass", []), ] # lookup plugin doc CLI_LOOKUP_DOC = ( "ansible-navigator doc company_name.coll_1.lookup_1 -t lookup --execution-environment false" ) -testdata_lookup_doc: list = [ - (0, CLI_LOOKUP_DOC, "ansible-navigator doc lookup plugin display", "lookup_doc_pass", []), +testdata_lookup_doc = [ + pytest.param( + 0, CLI_LOOKUP_DOC, "ansible-navigator doc lookup plugin display", "lookup_doc_pass", [] + ), ] # filter plugin doc CLI_FILTER_DOC = ( "ansible-navigator doc company_name.coll_1.filter_1 -t filter --execution-environment false" ) -testdata_filter_doc: list = [ - (0, CLI_FILTER_DOC, "ansible-navigator doc filter plugin display", "filter_doc_pass", []), +testdata_filter_doc = [ + pytest.param( + 0, CLI_FILTER_DOC, "ansible-navigator doc filter plugin display", "filter_doc_pass", [] + ), ] # plugin does not exist @@ -35,7 +41,7 @@ "ansible-navigator doc company_name.coll_1.doesnotexist --execution-environment false" ) testdata_module_doc_not_exist = [ - ( + pytest.param( 0, CLI_WRONG_MODULE_NOT_EXIST, "ansible-navigator doc wrong plugin name", diff --git a/tests/integration/actions/doc/test_stdout.py b/tests/integration/actions/doc/test_stdout.py index 0551be366..6f2d49e17 100644 --- a/tests/integration/actions/doc/test_stdout.py +++ b/tests/integration/actions/doc/test_stdout.py @@ -13,8 +13,8 @@ " --execution-environment true" ) -testdata_1: list = [ - ( +testdata_1 = [ + pytest.param( 0, CLI_DOC_HELP_WITH_EE, "ansible-navigator doc help with ee", @@ -37,8 +37,8 @@ class TestDocHelpWithEE(BaseClass): " --help-doc -m stdout --execution-environment false" ) -testdata_2: list = [ - ( +testdata_2 = [ + pytest.param( 0, CLI_DOC_HELP_WITHOUT_EE, "ansible-navigator doc help without ee", @@ -61,8 +61,8 @@ class TestDocHelpWithoutEE(BaseClass): " --execution-environment true" ) -testdata_3: list = [ - ( +testdata_3 = [ + pytest.param( 0, CLI_DOC_HELP_WITH_EE_INTERACTIVE_MODE, "ansible-navigator doc help with ee in interactive mode", @@ -85,8 +85,8 @@ class TestDocHelpWithEEInteractiveMode(BaseClass): " --execution-environment false" ) -testdata_4: list = [ - ( +testdata_4 = [ + pytest.param( 0, CLI_DOC_HELP_WITHOUT_EE_INTERACTIVE_MODE, "ansible-navigator doc help without ee in wrong mode", @@ -108,8 +108,8 @@ class TestDocHelpWithoutEEInteractiveMode(BaseClass): "ansible-navigator doc company_name.coll_1.mod_1 -m stdout -j --execution-environment false" ) -testdata_5: list = [ - ( +testdata_5 = [ + pytest.param( 0, CLI_MODULE_DOC_WITHOUT_EE, "ansible-navigator doc in stdout mode without EE", @@ -132,8 +132,8 @@ class TestModuleDocWithoutEE(BaseClass): "ansible-navigator doc company_name.coll_1.mod_1 -m stdout -j --execution-environment true" ) -testdata_6: list = [ - ( +testdata_6 = [ + pytest.param( 0, CLI_MODULE_DOC_WITH_EE, "ansible-navigator doc in stdout mode with EE", @@ -157,8 +157,8 @@ class TestModuleDocWithEE(BaseClass): " --execution-environment false" ) -testdata_7: list = [ - ( +testdata_7 = [ + pytest.param( 0, CLI_LOOKUP_DOC_WITHOUT_EE, "ansible-navigator lookup doc in stdout mode without EE", @@ -182,8 +182,8 @@ class TestLookUpDocWithoutEE(BaseClass): " --execution-environment true" ) -testdata_8: list = [ - ( +testdata_8 = [ + pytest.param( 0, CLI_LOOKUP_DOC_WITH_EE, "ansible-navigator lookup doc in stdout mode with EE", @@ -207,8 +207,8 @@ class TestLookUpDocWithEE(BaseClass): " --execution-environment false" ) -testdata_9: list = [ - ( +testdata_9 = [ + pytest.param( 0, CLI_FILTER_DOC_WITHOUT_EE, "ansible-navigator filter doc in stdout mode without EE", @@ -232,8 +232,8 @@ class TestFilterDocWithoutEE(BaseClass): " --execution-environment true" ) -testdata_10: list = [ - ( +testdata_10 = [ + pytest.param( 0, CLI_FILTER_DOC_WITH_EE, "ansible-navigator filter doc in stdout mode with EE", diff --git a/tests/integration/actions/doc/test_welcome_interactive_ee.py b/tests/integration/actions/doc/test_welcome_interactive_ee.py index 92afaab88..b58677db2 100644 --- a/tests/integration/actions/doc/test_welcome_interactive_ee.py +++ b/tests/integration/actions/doc/test_welcome_interactive_ee.py @@ -10,26 +10,30 @@ # module doc CLI_MODULE_DOC = "ansible-navigator --execution-environment true" -testdata_module_doc: list = [ - (0, CLI_MODULE_DOC, "welcome", "module_doc_pass", []), - (1, ":doc company_name.coll_1.mod_1", "load doc", "module_doc_pass", []), - (2, ":{{ examples }}", "load examples", "module_doc_pass", []), +testdata_module_doc = [ + pytest.param(0, CLI_MODULE_DOC, "welcome", "module_doc_pass", []), + pytest.param(1, ":doc company_name.coll_1.mod_1", "load doc", "module_doc_pass", []), + pytest.param(2, ":{{ examples }}", "load examples", "module_doc_pass", []), ] # lookup plugin doc CLI_LOOKUP_DOC = "ansible-navigator --execution-environment true" -testdata_lookup_doc: list = [ - (0, CLI_LOOKUP_DOC, "welcome", "lookup_doc_pass", []), - (1, ":doc company_name.coll_1.lookup_1 -t lookup", "load doc", "lookup_doc_pass", []), +testdata_lookup_doc = [ + pytest.param(0, CLI_LOOKUP_DOC, "welcome", "lookup_doc_pass", []), + pytest.param( + 1, ":doc company_name.coll_1.lookup_1 -t lookup", "load doc", "lookup_doc_pass", [] + ), ] # filter plugin doc CLI_FILTER_DOC = "ansible-navigator --execution-environment true" -testdata_filter_doc: list = [ - (0, CLI_FILTER_DOC, "welcome", "filter_doc_pass", []), - (1, ":doc company_name.coll_1.filter_1 -t filter", "load doc", "filter_doc_pass", []), +testdata_filter_doc = [ + pytest.param(0, CLI_FILTER_DOC, "welcome", "filter_doc_pass", []), + pytest.param( + 1, ":doc company_name.coll_1.filter_1 -t filter", "load doc", "filter_doc_pass", [] + ), ] # plugin does not exist diff --git a/tests/integration/actions/doc/test_welcome_interactive_noee.py b/tests/integration/actions/doc/test_welcome_interactive_noee.py index 5c6f75573..fd0a4301b 100644 --- a/tests/integration/actions/doc/test_welcome_interactive_noee.py +++ b/tests/integration/actions/doc/test_welcome_interactive_noee.py @@ -10,26 +10,30 @@ # module doc CLI_MODULE_DOC = "ansible-navigator --execution-environment false" -testdata_module_doc: list = [ - (0, CLI_MODULE_DOC, "welcome", "module_doc_pass", []), - (1, ":doc company_name.coll_1.mod_1", "load doc", "module_doc_pass", []), - (2, ":{{ examples }}", "load examples", "module_doc_pass", []), +testdata_module_doc = [ + pytest.param(0, CLI_MODULE_DOC, "welcome", "module_doc_pass", []), + pytest.param(1, ":doc company_name.coll_1.mod_1", "load doc", "module_doc_pass", []), + pytest.param(2, ":{{ examples }}", "load examples", "module_doc_pass", []), ] # lookup plugin doc CLI_LOOKUP_DOC = "ansible-navigator --execution-environment false" -testdata_lookup_doc: list = [ - (0, CLI_LOOKUP_DOC, "welcome", "lookup_doc_pass", []), - (1, ":doc company_name.coll_1.lookup_1 -t lookup", "load doc", "lookup_doc_pass", []), +testdata_lookup_doc = [ + pytest.param(0, CLI_LOOKUP_DOC, "welcome", "lookup_doc_pass", []), + pytest.param( + 1, ":doc company_name.coll_1.lookup_1 -t lookup", "load doc", "lookup_doc_pass", [] + ), ] # filter plugin doc CLI_FILTER_DOC = "ansible-navigator --execution-environment false" -testdata_filter_doc: list = [ - (0, CLI_FILTER_DOC, "welcome", "filter_doc_pass", []), - (1, ":doc company_name.coll_1.filter_1 -t filter", "load doc", "filter_doc_pass", []), +testdata_filter_doc = [ + pytest.param(0, CLI_FILTER_DOC, "welcome", "filter_doc_pass", []), + pytest.param( + 1, ":doc company_name.coll_1.filter_1 -t filter", "load doc", "filter_doc_pass", [] + ), ] # plugin does not exist diff --git a/tests/integration/actions/images/base.py b/tests/integration/actions/images/base.py index 516627c37..406abc74d 100644 --- a/tests/integration/actions/images/base.py +++ b/tests/integration/actions/images/base.py @@ -45,7 +45,7 @@ ) -def some_time_repl(match: re.Match) -> str: +def some_time_repl(match: re.Match[str]) -> str: """Replace the match string with a string of the same length. :param match: The string matched diff --git a/tests/integration/settings_from_cli/test_json_schema_errors.py b/tests/integration/settings_from_cli/test_json_schema_errors.py index 15e657e99..69a04aa8c 100644 --- a/tests/integration/settings_from_cli/test_json_schema_errors.py +++ b/tests/integration/settings_from_cli/test_json_schema_errors.py @@ -3,6 +3,7 @@ from __future__ import annotations import os +import shlex import subprocess from dataclasses import dataclass @@ -11,7 +12,6 @@ import pytest -from ansible_navigator.utils.functions import shlex_join from tests.defaults import FIXTURES_DIR from tests.defaults import BaseScenario from tests.defaults import id_func @@ -86,7 +86,7 @@ def test(data: Scenario, subtests: Any, tmp_path: Path): command = list(data.command) + ["--lf", str(log_file)] - bash_wrapped = f"/bin/bash -c '{venv_prefix!s}{shlex_join(command)}'" + bash_wrapped = f"/bin/bash -c '{venv_prefix!s}{shlex.join(split_command=command)}'" # Some os.environ are required in order to make it work, likely HOME and PATH at least. env = os.environ | {"ANSIBLE_NAVIGATOR_CONFIG": str(data.settings_file), "NO_COLOR": "true"} proc_out = subprocess.run( diff --git a/tests/unit/actions/run/test_artifact.py b/tests/unit/actions/run/test_artifact.py index 7bbe22489..e42635b63 100644 --- a/tests/unit/actions/run/test_artifact.py +++ b/tests/unit/actions/run/test_artifact.py @@ -52,7 +52,7 @@ class Scenario(BaseScenario): filename: str | None playbook: str starts_with: str | None = None - re_match: Pattern | None = None + re_match: Pattern[str] | None = None help_playbook: bool = False enable_prompts: bool = False playbook_artifact_enable: bool = True diff --git a/tests/unit/actions/run/test_runner_async.py b/tests/unit/actions/run/test_runner_async.py index 90679cff8..d68bfc808 100644 --- a/tests/unit/actions/run/test_runner_async.py +++ b/tests/unit/actions/run/test_runner_async.py @@ -6,6 +6,7 @@ from dataclasses import dataclass from pathlib import Path from queue import Queue +from typing import Any import pytest @@ -24,23 +25,23 @@ class Scenario(BaseScenario): # pylint: disable=too-many-instance-attributes name: str container_engine: str | None - container_options: list | None + container_options: list[str] | None execution_environment_image: str | None execution_environment: bool | None - inventory: list | None + inventory: list[str] | None playbook_artifact_enable: bool mode: str | None - pass_environment_variable: list | None - set_environment_variable: dict | None + pass_environment_variable: list[str] | None + set_environment_variable: dict[str, str] | None playbook: str | None - container_volume_mounts: list | None + container_volume_mounts: list[str] | None help_playbook: bool - cmdline: list | None + cmdline: list[str] | None private_data_dir: str | None rotate_artifacts: int | None timeout: int | None write_job_events: bool - expected: dict + expected: dict[str, Any] def __str__(self): """Provide the test id. @@ -50,7 +51,7 @@ def __str__(self): return self.name -TEST_QUEUE: Queue = Queue() +TEST_QUEUE: Queue[dict[str, str]] = Queue() test_data = [ Scenario( diff --git a/tests/unit/actions/test_exec.py b/tests/unit/actions/test_exec.py index 86e9e8ec4..05c5c95e7 100644 --- a/tests/unit/actions/test_exec.py +++ b/tests/unit/actions/test_exec.py @@ -18,7 +18,7 @@ class CommandTestData(NamedTuple): use_shell: bool default_exec_command: bool result_command: str - result_params: list + result_params: list[str] def id_from_data(test_value): diff --git a/tests/unit/configuration_subsystem/conftest.py b/tests/unit/configuration_subsystem/conftest.py index e0a55ada2..8f0668c63 100644 --- a/tests/unit/configuration_subsystem/conftest.py +++ b/tests/unit/configuration_subsystem/conftest.py @@ -5,6 +5,7 @@ import os from copy import deepcopy +from typing import Any from typing import NamedTuple from typing import Protocol @@ -33,7 +34,7 @@ class GenerateConfigResponse(NamedTuple): messages: list[LogMessage] exit_messages: list[ExitMessage] application_configuration: ApplicationConfiguration - settings_contents: dict + settings_contents: dict[Any, Any] class GenerateConfigCallable(Protocol): @@ -144,7 +145,7 @@ def schema_dict_all_required(schema_dict: SettingsSchemaType) -> SettingsSchemaT :returns: the json schema as a dictionary """ - def property_dive(subschema: dict): + def property_dive(subschema: dict[str, Any]): if "properties" in subschema: subschema["required"] = list(subschema["properties"].keys()) for value in subschema["properties"].values(): diff --git a/tests/unit/configuration_subsystem/post_processors/test_execution_environment_volume_mounts.py b/tests/unit/configuration_subsystem/post_processors/test_execution_environment_volume_mounts.py index 511a55a61..90bf74ad3 100644 --- a/tests/unit/configuration_subsystem/post_processors/test_execution_environment_volume_mounts.py +++ b/tests/unit/configuration_subsystem/post_processors/test_execution_environment_volume_mounts.py @@ -7,6 +7,7 @@ from dataclasses import dataclass from itertools import repeat from pathlib import Path +from typing import Any import pytest @@ -24,7 +25,7 @@ class Scenario(BaseScenario): """Data structure for EEV post processor tests.""" name: str - current: bool | str | list | dict + current: bool | str | list[Any] | dict[Any, Any] source: C expected: list[str] | None = None exit_message_substr: str = "" diff --git a/tests/unit/configuration_subsystem/post_processors/test_time_zone.py b/tests/unit/configuration_subsystem/post_processors/test_time_zone.py index 43479da2a..f59b93499 100644 --- a/tests/unit/configuration_subsystem/post_processors/test_time_zone.py +++ b/tests/unit/configuration_subsystem/post_processors/test_time_zone.py @@ -4,6 +4,7 @@ from copy import deepcopy from dataclasses import dataclass +from typing import Any import pytest @@ -22,7 +23,7 @@ class Scenario(BaseScenario): """Data structure for the time zone post processor tests.""" name: str - current: bool | str | dict + current: bool | str | dict[Any, Any] source: C exit_message_substr: str = "" expected: str | None = None diff --git a/tests/unit/configuration_subsystem/test_presentable.py b/tests/unit/configuration_subsystem/test_presentable.py index e19497c63..47cd69efa 100644 --- a/tests/unit/configuration_subsystem/test_presentable.py +++ b/tests/unit/configuration_subsystem/test_presentable.py @@ -77,7 +77,6 @@ def test_settings_file_entry(sample_settings, settings_file_dict): configurator = Configurator(params=[], application_configuration=sample_settings) configurator._post_process() # pylint: disable=protected-access presentable = to_presentable(sample_settings) - # pylint: disable=not-an-iterable # https://github.com/PyCQA/pylint/issues/2296 assert all(isinstance(p, PresentableSettingsEntry) for p in presentable) assert asdict(presentable[0]) == settings_file_dict @@ -104,7 +103,6 @@ def test_settings_entry(sample_settings, settings_file_dict): configurator = Configurator(params=[], application_configuration=sample_settings) configurator._post_process() # pylint: disable=protected-access presentable = to_presentable(sample_settings) - # pylint: disable=not-an-iterable # https://github.com/PyCQA/pylint/issues/2296 assert all(isinstance(p, PresentableSettingsEntry) for p in presentable) assert asdict(presentable[0]) == settings_file_dict entry_dict = { diff --git a/tests/unit/configuration_subsystem/test_settings_effective.py b/tests/unit/configuration_subsystem/test_settings_effective.py index 804ceaa42..f8b8e653b 100644 --- a/tests/unit/configuration_subsystem/test_settings_effective.py +++ b/tests/unit/configuration_subsystem/test_settings_effective.py @@ -7,6 +7,7 @@ from copy import deepcopy from functools import reduce from pathlib import Path +from typing import Any import pytest @@ -101,14 +102,14 @@ def test_settings_full( :param settings_env_var_to_full: The env var and file writing fixture """ - sample: dict = settings_env_var_to_full[1] + sample: dict[Any, Any] = settings_env_var_to_full[1] settings = deepcopy(NavigatorConfiguration) settings.internals.initializing = True _messages, _exit_messages = parse_and_update(params=[], args=settings) # Build the effective settings - effective: dict = to_effective(settings) + effective: SettingsFileType = to_effective(settings) # Compare the effective against the settings sample type_check_only = [ @@ -118,7 +119,7 @@ def test_settings_full( # Walk the settings, for each path extract the value from the sample and effective and compare for entry in settings.entries: path = entry.settings_file_path(prefix=settings.application_name_dashed) - effective_value = reduce(operator.getitem, path.split("."), effective) + effective_value = reduce(operator.getitem, path.split("."), effective) # type: ignore sample_value = reduce(operator.getitem, path.split("."), sample) # Don't check auto if entry.value.source == Constants.AUTO: diff --git a/tests/unit/logger/test_time_zone.py b/tests/unit/logger/test_time_zone.py index 94a3bd89b..c2052bed0 100644 --- a/tests/unit/logger/test_time_zone.py +++ b/tests/unit/logger/test_time_zone.py @@ -20,7 +20,7 @@ class Scenario(BaseScenario): """Data for time zone support in the logs.""" name: str - re_match: Pattern + re_match: Pattern[str] time_zone: str | None = None will_exit: bool = False diff --git a/tests/unit/ui_framework/test_progress_bar.py b/tests/unit/ui_framework/test_progress_bar.py index 5cbe12b4c..43c20d5e5 100644 --- a/tests/unit/ui_framework/test_progress_bar.py +++ b/tests/unit/ui_framework/test_progress_bar.py @@ -1,6 +1,7 @@ """Test for the conversion of percent string to progress bars.""" from dataclasses import dataclass +from typing import Any from ansible_navigator.content_defs import ContentBase from ansible_navigator.ui_framework.utils import convert_percentage @@ -23,7 +24,7 @@ def test_dictionary_complete() -> None: @dataclass -class ContentTest(ContentBase): +class ContentTest(ContentBase[Any]): """Test data for string conversion to a progress bar.""" progress: str diff --git a/tests/unit/utils/test_dot_paths.py b/tests/unit/utils/test_dot_paths.py index d170db5f7..e26952b1e 100644 --- a/tests/unit/utils/test_dot_paths.py +++ b/tests/unit/utils/test_dot_paths.py @@ -5,6 +5,7 @@ from collections.abc import MutableMapping from dataclasses import dataclass from dataclasses import field +from typing import Any import pytest @@ -84,7 +85,7 @@ class Scenario(BaseScenario): # pylint: disable=too-many-instance-attributes behaviors: tuple[MergeBehaviors, ...] comment: str path: str - expected: MutableMapping | None + expected: MutableMapping[Any, Any] | None value: bool | int | list | float | str | dict = "" content: dict = field(default_factory=lambda: base_dict) new_path: str = "" diff --git a/tests/unit/utils/test_serialize_dataclass.py b/tests/unit/utils/test_serialize_dataclass.py index 708e55750..fc4b294a3 100644 --- a/tests/unit/utils/test_serialize_dataclass.py +++ b/tests/unit/utils/test_serialize_dataclass.py @@ -9,7 +9,6 @@ from functools import partial from typing import Any from typing import NamedTuple -from typing import Union import pytest