From 91f8ae99441e037d8167ea7f222195b5362e4d33 Mon Sep 17 00:00:00 2001 From: Webster Mudge Date: Mon, 19 Jan 2026 16:35:47 -0500 Subject: [PATCH 1/4] Convert shorthand type hints to explicit Signed-off-by: Webster Mudge --- tests/unit/__init__.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py index 8499caa0..58978408 100644 --- a/tests/unit/__init__.py +++ b/tests/unit/__init__.py @@ -18,7 +18,7 @@ from email.utils import formatdate from functools import wraps -from typing import Any, Dict +from typing import Any, Dict, Optional from urllib.parse import urlencode from urllib.error import HTTPError from http.client import HTTPResponse @@ -54,7 +54,7 @@ def __init__(self, kwargs): self.__dict__.update(kwargs) def __getattr__(self, attr): - return self.__dict__[attr] + return self.__dict__.get(attr, None) def handle_response(func): @@ -108,9 +108,9 @@ def set_credential_headers( def prepare_body( - data: Dict[str, Any] | None = None, - json_data: Dict[str, Any] | None = None, -) -> str | None: + data: Optional[Dict[str, Any]] = None, + json_data: Optional[Dict[str, Any]] = None, +) -> Optional[str]: if json_data is not None: return json.dumps(json_data) elif data is not None: @@ -134,7 +134,7 @@ def __init__( self.private_key = private_key @handle_response - def get(self, path: str, params: Dict[str, Any] | None = None) -> Dict[str, Any]: + def get(self, path: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: # Prepare query parameters if params: path += "?" + urlencode(params) @@ -155,8 +155,8 @@ def get(self, path: str, params: Dict[str, Any] | None = None) -> Dict[str, Any] def post( self, path: str, - data: Dict[str, Any] | None = None, - json_data: Dict[str, Any] | None = None, + data: Optional[Dict[str, Any]] = None, + json_data: Optional[Dict[str, Any]] = None, squelch: Dict[int, Any] = {}, ) -> Dict[str, Any]: url = f"{self.endpoint}/{path.strip('/')}" @@ -175,8 +175,8 @@ def post( def put( self, path: str, - data: Dict[str, Any] | None = None, - json_data: Dict[str, Any] | None = None, + data: Optional[Dict[str, Any]] = None, + json_data: Optional[Dict[str, Any]] = None, squelch: Dict[int, Any] = {}, ) -> Dict[str, Any]: url = f"{self.endpoint}/{path.strip('/')}" From 3ee6dcef432c28484f668c1a58aff1e695393534 Mon Sep 17 00:00:00 2001 From: Webster Mudge Date: Mon, 19 Jan 2026 16:36:17 -0500 Subject: [PATCH 2/4] Skip legacy tests Signed-off-by: Webster Mudge --- tests/unit/plugins/modules/environment/env_test.py | 1 + tests/unit/plugins/modules/iam_role_info/iam_role_info_test.py | 2 ++ tests/unit/plugins/modules/iam_user_info/iam_user_info_test.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/tests/unit/plugins/modules/environment/env_test.py b/tests/unit/plugins/modules/environment/env_test.py index 7fed40a3..6345654e 100644 --- a/tests/unit/plugins/modules/environment/env_test.py +++ b/tests/unit/plugins/modules/environment/env_test.py @@ -89,6 +89,7 @@ def test_freeipa_specified(self): **expected, ) + @pytest.mark.skip(reason="Refactor to new structure") def test_freeipa_default(self): setup_module_args( { diff --git a/tests/unit/plugins/modules/iam_role_info/iam_role_info_test.py b/tests/unit/plugins/modules/iam_role_info/iam_role_info_test.py index e448ab53..d8a39d86 100644 --- a/tests/unit/plugins/modules/iam_role_info/iam_role_info_test.py +++ b/tests/unit/plugins/modules/iam_role_info/iam_role_info_test.py @@ -24,6 +24,8 @@ setup_module_args, ) +pytestmark = pytest.mark.skip(reason="Refactor to new structure") + def test_get_single_role_details(): setup_module_args({"name": "crn:iam:us-west-1:role:ClassicClustersCreator"}) diff --git a/tests/unit/plugins/modules/iam_user_info/iam_user_info_test.py b/tests/unit/plugins/modules/iam_user_info/iam_user_info_test.py index ed6f8b12..1e6b1cbd 100644 --- a/tests/unit/plugins/modules/iam_user_info/iam_user_info_test.py +++ b/tests/unit/plugins/modules/iam_user_info/iam_user_info_test.py @@ -24,6 +24,8 @@ setup_module_args, ) +pytestmark = pytest.mark.skip(reason="Refactor to new structure") + def test_user_info_username(): setup_module_args({"user_name": "mike01"}) From cb9c79811e9d5f29b7d8a2548d22d2ded2a1d11b Mon Sep 17 00:00:00 2001 From: Webster Mudge Date: Mon, 19 Jan 2026 16:37:08 -0500 Subject: [PATCH 3/4] Remove Python 3.9 from Hatch testing matrix due to dependency conflict Signed-off-by: Webster Mudge --- pyproject.toml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8d5d6536..47dad32d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ validate-bump = true detached = true dependencies = [ "pre-commit", - "coverage[toml]", + # "coverage[toml]", "pytest", "pytest-mock", # "pytest-cov", @@ -44,15 +44,19 @@ lint = [ [tool.hatch.envs.hatch-test] matrix-name-format = "{variable}_{value}" extra-dependencies = [ - "pytest", - "pytest-mock", "molecule", "molecule-plugins", "molecule-plugins[ec2]", - # "ansible-core<2.17", # For RHEL 8 support + # "ansible-core<2.17", # Handled by matrix overrides "cdpy @ git+https://github.com/cloudera-labs/cdpy@main#egg=cdpy", ] +[tool.hatch.envs.hatch-test.scripts] +run = [ + "pip list --verbose", + "pytest{env:HATCH_TEST_ARGS:} {args}" +] + # Ansible 2.18 - Python >= 3.11 [[tool.hatch.envs.hatch-test.matrix]] python = ["3.13", "3.12", "3.11"] @@ -68,9 +72,9 @@ ansible = ["2.17"] python = ["3.13", "3.12", "3.11", "3.10"] ansible = ["2.16"] -# Ansible 2.15 - Python <= 3.12 +# Ansible 2.15 - Python <= 3.12, >=3.10 [[tool.hatch.envs.hatch-test.matrix]] -python = ["3.12", "3.11", "3.10", "3.9"] +python = ["3.12", "3.11", "3.10"] ansible = ["2.15"] [tool.hatch.envs.hatch-test.overrides] From 9db4658f615d08b8473d299a5a7657e832d56630 Mon Sep 17 00:00:00 2001 From: Webster Mudge Date: Mon, 19 Jan 2026 16:37:22 -0500 Subject: [PATCH 4/4] Add documentation on testing Python 3.9 Signed-off-by: Webster Mudge --- TESTING.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/TESTING.md b/TESTING.md index c945732a..dac03121 100644 --- a/TESTING.md +++ b/TESTING.md @@ -37,3 +37,20 @@ hatch test -k iam_machine_user ```bash hatch test --all ``` + +> [!WARNING] Testing Python 3.9 +> Hatch currently has a dependency (`coverage[toml]`) that conflicts with Python 3.9. To test Python 3.9, run `pytest` in a standalone virtual environment. For example: + +```bash +python3.9 -m venv cloudera-cloud-python3.9 +``` + +Activate this virtual environment, and install the minimal requirements for testing. + +```bash +pip install pytest pytest-mock ansible-core==2.15 "cdpy @ git+https://github.com/cloudera-labs/cdpy@main#egg=cdpy" +``` + +Then run `pytest` directly instead of `hatch test`. + +All other requirements, like `PYTHONPATH`, are still valid.