From dee576f5b4a63106682e64a82b9203624c4539a0 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Tue, 27 Jan 2026 09:02:41 +0100 Subject: [PATCH 1/9] Use a list comprehension to create a transformed list --- infrahub_sdk/batch.py | 14 ++++++-------- infrahub_sdk/client.py | 10 ++++------ infrahub_sdk/diff.py | 21 ++++++++++----------- infrahub_sdk/spec/object.py | 8 +++++--- infrahub_sdk/utils.py | 5 ++--- infrahub_sdk/yaml.py | 8 ++++---- pyproject.toml | 1 - 7 files changed, 31 insertions(+), 36 deletions(-) diff --git a/infrahub_sdk/batch.py b/infrahub_sdk/batch.py index c86d7c77..6e9cc1cb 100644 --- a/infrahub_sdk/batch.py +++ b/infrahub_sdk/batch.py @@ -71,16 +71,14 @@ def add(self, *args: Any, task: Callable, node: Any | None = None, **kwargs: Any self._tasks.append(BatchTask(task=task, node=node, args=args, kwargs=kwargs)) async def execute(self) -> AsyncGenerator: - tasks = [] - - for batch_task in self._tasks: - tasks.append( - asyncio.create_task( - execute_batch_task_in_pool( - task=batch_task, semaphore=self.semaphore, return_exceptions=self.return_exceptions - ) + tasks = [ + asyncio.create_task( + execute_batch_task_in_pool( + task=batch_task, semaphore=self.semaphore, return_exceptions=self.return_exceptions ) ) + for batch_task in self._tasks + ] for completed_task in asyncio.as_completed(tasks): node, result = await completed_task diff --git a/infrahub_sdk/client.py b/infrahub_sdk/client.py index 33487ebf..92cebdea 100644 --- a/infrahub_sdk/client.py +++ b/infrahub_sdk/client.py @@ -1200,12 +1200,11 @@ async def query_gql_query( url_params["update_group"] = str(update_group).lower() if url_params: - url_params_str = [] + url_params_str: list[tuple[str, str]] = [] url_params_dict = {} for key, value in url_params.items(): if isinstance(value, (list)): - for item in value: - url_params_str.append((key, item)) + url_params_str.extend((key, item) for item in value) else: url_params_dict[key] = value @@ -2512,12 +2511,11 @@ def query_gql_query( url_params["update_group"] = str(update_group).lower() if url_params: - url_params_str = [] + url_params_str: list[tuple[str, str]] = [] url_params_dict = {} for key, value in url_params.items(): if isinstance(value, (list)): - for item in value: - url_params_str.append((key, item)) + url_params_str.extend((key, item) for item in value) else: url_params_dict[key] = value diff --git a/infrahub_sdk/diff.py b/infrahub_sdk/diff.py index 8e5513e2..fd4d9308 100644 --- a/infrahub_sdk/diff.py +++ b/infrahub_sdk/diff.py @@ -117,18 +117,17 @@ def diff_tree_node_to_node_diff(node_dict: dict[str, Any], branch_name: str) -> }, ) if not is_cardinality_one and "elements" in relationship_dict: - peer_diffs = [] - for element_dict in relationship_dict["elements"]: - peer_diffs.append( - NodeDiffPeer( - action=str(element_dict.get("status")), - summary={ - "added": int(element_dict.get("num_added") or 0), - "removed": int(element_dict.get("num_removed") or 0), - "updated": int(element_dict.get("num_updated") or 0), - }, - ) + peer_diffs = [ + NodeDiffPeer( + action=str(element_dict.get("status")), + summary={ + "added": int(element_dict.get("num_added") or 0), + "removed": int(element_dict.get("num_removed") or 0), + "updated": int(element_dict.get("num_updated") or 0), + }, ) + for element_dict in relationship_dict["elements"] + ] relationship_diff["peers"] = peer_diffs element_diffs.append(relationship_diff) return NodeDiff( diff --git a/infrahub_sdk/spec/object.py b/infrahub_sdk/spec/object.py index e21c8e12..cf7a6fc3 100644 --- a/infrahub_sdk/spec/object.py +++ b/infrahub_sdk/spec/object.py @@ -264,9 +264,11 @@ async def validate_object( context = context.copy() if context else {} # First validate if all mandatory fields are present - for element in schema.mandatory_input_names: - if not any([element in data, element in context]): - errors.append(ObjectValidationError(position=position + [element], message=f"{element} is mandatory")) + errors.extend( + ObjectValidationError(position=position + [element], message=f"{element} is mandatory") + for element in schema.mandatory_input_names + if not any([element in data, element in context]) + ) # Validate if all attributes are valid for key, value in data.items(): diff --git a/infrahub_sdk/utils.py b/infrahub_sdk/utils.py index 360366ef..6168664b 100644 --- a/infrahub_sdk/utils.py +++ b/infrahub_sdk/utils.py @@ -338,13 +338,12 @@ def get_user_permissions(data: list[dict]) -> dict: groups = {} for group in data: group_name = group["node"]["display_label"] - permissions = [] + permissions: list[str] = [] roles = group["node"].get("roles", {}).get("edges", []) for role in roles: role_permissions = role["node"].get("permissions", {}).get("edges", []) - for permission in role_permissions: - permissions.append(permission["node"]["identifier"]["value"]) + permissions.extend(permission["node"]["identifier"]["value"] for permission in role_permissions) groups[group_name] = permissions diff --git a/infrahub_sdk/yaml.py b/infrahub_sdk/yaml.py index 6b764081..dd5a0754 100644 --- a/infrahub_sdk/yaml.py +++ b/infrahub_sdk/yaml.py @@ -92,10 +92,10 @@ def load_file_from_disk(cls, path: Path) -> list[Self]: has_multiple_document = bool(file_content.count("---") > 1) if has_multiple_document: - for content in yaml.safe_load_all(file_content): - yaml_files.append( - cls.init(location=path, multiple_documents=has_multiple_document, content=content) - ) + yaml_files.extend( + cls.init(location=path, multiple_documents=has_multiple_document, content=content) + for content in yaml.safe_load_all(file_content) + ) else: yaml_files.append( diff --git a/pyproject.toml b/pyproject.toml index 7361ba1d..7b6ac7ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -242,7 +242,6 @@ ignore = [ "INP001", # File declares a package, but is nested under an implicit namespace package. "N802", # Function name should be lowercase "PERF203", # `try`-`except` within a loop incurs performance overhead - "PERF401", # Use a list comprehension to create a transformed list "PLR0912", # Too many branches "PLR0913", # Too many arguments in function definition "PLR0917", # Too many positional arguments From 184f421491e2b05385c90bdac648171d3d79df71 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Tue, 27 Jan 2026 19:36:24 +0100 Subject: [PATCH 2/9] Add missing __init__.py files --- pyproject.toml | 1 - tests/fixtures/__init__.py | 0 tests/fixtures/integration/__init__.py | 0 tests/fixtures/integration/test_infrahubctl/__init__.py | 0 .../nested_spec_objects/0_folder/4_subfolder/__init__.py | 0 tests/fixtures/nested_spec_objects/0_folder/__init__.py | 0 tests/fixtures/nested_spec_objects/__init__.py | 0 tests/fixtures/repos/__init__.py | 0 tests/fixtures/repos/ctl_integration/__init__.py | 0 tests/fixtures/repos/ctl_integration/generators/__init__.py | 0 tests/fixtures/repos/ctl_integration/transforms/__init__.py | 0 tests/unit/sdk/graphql/__init__.py | 0 tests/unit/sdk/spec/__init__.py | 0 13 files changed, 1 deletion(-) create mode 100644 tests/fixtures/__init__.py create mode 100644 tests/fixtures/integration/__init__.py create mode 100644 tests/fixtures/integration/test_infrahubctl/__init__.py create mode 100644 tests/fixtures/nested_spec_objects/0_folder/4_subfolder/__init__.py create mode 100644 tests/fixtures/nested_spec_objects/0_folder/__init__.py create mode 100644 tests/fixtures/nested_spec_objects/__init__.py create mode 100644 tests/fixtures/repos/__init__.py create mode 100644 tests/fixtures/repos/ctl_integration/__init__.py create mode 100644 tests/fixtures/repos/ctl_integration/generators/__init__.py create mode 100644 tests/fixtures/repos/ctl_integration/transforms/__init__.py create mode 100644 tests/unit/sdk/graphql/__init__.py create mode 100644 tests/unit/sdk/spec/__init__.py diff --git a/pyproject.toml b/pyproject.toml index 7b6ac7ae..87ecea76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -239,7 +239,6 @@ ignore = [ ################################################################################################## "B008", # Do not perform function call `typer.Option` in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable "B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling - "INP001", # File declares a package, but is nested under an implicit namespace package. "N802", # Function name should be lowercase "PERF203", # `try`-`except` within a loop incurs performance overhead "PLR0912", # Too many branches diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/integration/__init__.py b/tests/fixtures/integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/integration/test_infrahubctl/__init__.py b/tests/fixtures/integration/test_infrahubctl/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/nested_spec_objects/0_folder/4_subfolder/__init__.py b/tests/fixtures/nested_spec_objects/0_folder/4_subfolder/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/nested_spec_objects/0_folder/__init__.py b/tests/fixtures/nested_spec_objects/0_folder/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/nested_spec_objects/__init__.py b/tests/fixtures/nested_spec_objects/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/repos/__init__.py b/tests/fixtures/repos/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/repos/ctl_integration/__init__.py b/tests/fixtures/repos/ctl_integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/repos/ctl_integration/generators/__init__.py b/tests/fixtures/repos/ctl_integration/generators/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/fixtures/repos/ctl_integration/transforms/__init__.py b/tests/fixtures/repos/ctl_integration/transforms/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/sdk/graphql/__init__.py b/tests/unit/sdk/graphql/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/sdk/spec/__init__.py b/tests/unit/sdk/spec/__init__.py new file mode 100644 index 00000000..e69de29b From 2b01488cdd173fb56362e92df5a97772d0b400cd Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Tue, 27 Jan 2026 19:49:27 +0100 Subject: [PATCH 3/9] Add __hash__ method to object that already has __eq__ --- infrahub_sdk/recorder.py | 3 +++ pyproject.toml | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/infrahub_sdk/recorder.py b/infrahub_sdk/recorder.py index 40c45dd3..e2038be7 100644 --- a/infrahub_sdk/recorder.py +++ b/infrahub_sdk/recorder.py @@ -34,6 +34,9 @@ def default(cls) -> NoRecorder: def __eq__(self, other: object) -> bool: return isinstance(other, NoRecorder) + def __hash__(self) -> int: + return hash(self.__class__) + class JSONRecorder(BaseSettings): model_config = SettingsConfigDict(env_prefix="INFRAHUB_JSON_RECORDER_") diff --git a/pyproject.toml b/pyproject.toml index 7b6ac7ae..9df38dfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -248,7 +248,6 @@ ignore = [ "PLR2004", # Magic value used in comparison "PLR6301", # Method could be a function, class method, or static method "PLW0603", # Using the global statement to update `SETTINGS` is discouraged - "PLW1641", # Object does not implement `__hash__` method "RUF005", # Consider `[*path, str(key)]` instead of concatenation "RUF029", # Function is declared `async`, but doesn't `await` or use `async` features. "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes From 42d78714769525395a6552ff438e5f045e5963fd Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Tue, 27 Jan 2026 19:55:55 +0100 Subject: [PATCH 4/9] Fix ruff Jinja2 violations and move the remaining warning --- infrahub_sdk/protocols_generator/generator.py | 7 ++++++- pyproject.toml | 9 ++++++++- tasks.py | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/infrahub_sdk/protocols_generator/generator.py b/infrahub_sdk/protocols_generator/generator.py index ee80732f..e70e221c 100644 --- a/infrahub_sdk/protocols_generator/generator.py +++ b/infrahub_sdk/protocols_generator/generator.py @@ -69,7 +69,12 @@ def __init__(self, schema: dict[str, MainSchemaTypesAll]) -> None: ) def render(self, sync: bool = True) -> str: - jinja2_env = jinja2.Environment(loader=jinja2.BaseLoader(), trim_blocks=True, lstrip_blocks=True) + jinja2_env = jinja2.Environment( + loader=jinja2.BaseLoader(), + trim_blocks=True, + lstrip_blocks=True, + autoescape=False, # noqa: S701 + ) jinja2_env.filters["render_attribute"] = self._jinja2_filter_render_attribute jinja2_env.filters["render_relationship"] = self._jinja2_filter_render_relationship jinja2_env.filters["syncify"] = self._jinja2_filter_syncify diff --git a/pyproject.toml b/pyproject.toml index 7b6ac7ae..bde19885 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -252,7 +252,6 @@ ignore = [ "RUF005", # Consider `[*path, str(key)]` instead of concatenation "RUF029", # Function is declared `async`, but doesn't `await` or use `async` features. "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes - "S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True` "SIM108", # Use ternary operator `key_str = f"{value[ALIAS_KEY]}: {key}" if ALIAS_KEY in value and value[ALIAS_KEY] else key` instead of `if`-`else`-block "TC003", # Move standard library import `collections.abc.Iterable` into a type-checking block "UP031", # Use format specifiers instead of percent format @@ -310,6 +309,14 @@ max-complexity = 17 "S105", # 'PASS' is not a password but a state ] +"infrahub_sdk/template/__init__.py" = [ + ################################################################################################## + # Review and change the below later # + ################################################################################################## + "S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True` or the `select_autoescape` function to mitigate XSS vulnerabilities. +] + + "tests/**/*.py" = [ "PLR2004", # Magic value used in comparison "S101", # Use of assert detected diff --git a/tasks.py b/tasks.py index e47bffce..c4c82004 100644 --- a/tasks.py +++ b/tasks.py @@ -100,7 +100,7 @@ def _generate_infrahub_sdk_configuration_documentation() -> None: template_text = template_file.read_text(encoding="utf-8") - environment = jinja2.Environment(trim_blocks=True) + environment = jinja2.Environment(trim_blocks=True, autoescape=jinja2.select_autoescape(default_for_string=False)) template = environment.from_string(template_text) rendered_file = template.render(properties=properties) From 5aa7e40d2405dde38975e3cd10de4c85b6452736 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Tue, 27 Jan 2026 19:44:32 +0100 Subject: [PATCH 5/9] Move rules for too many branches --- pyproject.toml | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0e267ab5..2ade0bc8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -241,12 +241,10 @@ ignore = [ "B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling "N802", # Function name should be lowercase "PERF203", # `try`-`except` within a loop incurs performance overhead - "PLR0912", # Too many branches "PLR0913", # Too many arguments in function definition "PLR0917", # Too many positional arguments "PLR2004", # Magic value used in comparison "PLR6301", # Method could be a function, class method, or static method - "PLW0603", # Using the global statement to update `SETTINGS` is discouraged "RUF005", # Consider `[*path, str(key)]` instead of concatenation "RUF029", # Function is declared `async`, but doesn't `await` or use `async` features. "S311", # Standard pseudo-random generators are not suitable for cryptographic purposes @@ -303,6 +301,20 @@ max-complexity = 17 "PLR0904", # Too many public methods ] +"infrahub_sdk/node/node.py" = [ + ################################################################################################## + # Review and change the below later # + ################################################################################################## + "PLR0912", # Too many branches +] + +"infrahub_sdk/node/related_node.py" = [ + ################################################################################################## + # Review and change the below later # + ################################################################################################## + "PLR0912", # Too many branches +] + "infrahub_sdk/pytest_plugin/models.py" = [ "S105", # 'PASS' is not a password but a state ] @@ -314,6 +326,19 @@ max-complexity = 17 "S701", # By default, jinja2 sets `autoescape` to `False`. Consider using `autoescape=True` or the `select_autoescape` function to mitigate XSS vulnerabilities. ] +"infrahub_sdk/spec/object.py" = [ + ################################################################################################## + # Review and change the below later # + ################################################################################################## + "PLR0912", # Too many branches +] + +"infrahub_sdk/transfer/importer/json.py" = [ + ################################################################################################## + # Review and change the below later # + ################################################################################################## + "PLR0912", # Too many branches +] "tests/**/*.py" = [ "PLR2004", # Magic value used in comparison From 33e6410c0a700169eef3809ff6f25684bb97ba34 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Wed, 28 Jan 2026 10:44:14 +0100 Subject: [PATCH 6/9] Update packages: urllib3, filelock & virtualenv --- uv.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/uv.lock b/uv.lock index a4855b8b..77334b35 100644 --- a/uv.lock +++ b/uv.lock @@ -571,11 +571,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.20.0" +version = "3.20.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922, upload-time = "2025-10-08T18:03:50.056Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054, upload-time = "2025-10-08T18:03:48.35Z" }, + { url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" }, ] [[package]] @@ -2943,11 +2943,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.0" +version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/43/554c2569b62f49350597348fc3ac70f786e3c32e7f19d266e19817812dd3/urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1", size = 432585, upload-time = "2025-12-05T15:08:47.885Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/1a/9ffe814d317c5224166b23e7c47f606d6e473712a2fad0f704ea9b99f246/urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f", size = 131083, upload-time = "2025-12-05T15:08:45.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] @@ -2966,7 +2966,7 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.35.3" +version = "20.36.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, @@ -2974,9 +2974,9 @@ dependencies = [ { name = "platformdirs" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a4/d5/b0ccd381d55c8f45d46f77df6ae59fbc23d19e901e2d523395598e5f4c93/virtualenv-20.35.3.tar.gz", hash = "sha256:4f1a845d131133bdff10590489610c98c168ff99dc75d6c96853801f7f67af44", size = 6002907, upload-time = "2025-10-10T21:23:33.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/a3/4d310fa5f00863544e1d0f4de93bddec248499ccf97d4791bc3122c9d4f3/virtualenv-20.36.1.tar.gz", hash = "sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba", size = 6032239, upload-time = "2026-01-09T18:21:01.296Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/27/73/d9a94da0e9d470a543c1b9d3ccbceb0f59455983088e727b8a1824ed90fb/virtualenv-20.35.3-py3-none-any.whl", hash = "sha256:63d106565078d8c8d0b206d48080f938a8b25361e19432d2c9db40d2899c810a", size = 5981061, upload-time = "2025-10-10T21:23:30.433Z" }, + { url = "https://files.pythonhosted.org/packages/6a/2a/dc2228b2888f51192c7dc766106cd475f1b768c10caaf9727659726f7391/virtualenv-20.36.1-py3-none-any.whl", hash = "sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f", size = 6008258, upload-time = "2026-01-09T18:20:59.425Z" }, ] [[package]] From e58e3295dbab49c04868d432c5f084a34806fa59 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Wed, 28 Jan 2026 14:12:31 +0100 Subject: [PATCH 7/9] Fix flake8 raise linting violations --- infrahub_sdk/ctl/cli_commands.py | 2 +- infrahub_sdk/ctl/config.py | 4 ++-- pyproject.toml | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/infrahub_sdk/ctl/cli_commands.py b/infrahub_sdk/ctl/cli_commands.py index accebe4b..2b571723 100644 --- a/infrahub_sdk/ctl/cli_commands.py +++ b/infrahub_sdk/ctl/cli_commands.py @@ -239,7 +239,7 @@ async def _run_transform( elif isinstance(error, str) and "Branch:" in error: console.print(f"[yellow] - {error}") console.print("[yellow] you can specify a different branch with --branch") - raise typer.Abort() + raise typer.Abort if inspect.iscoroutinefunction(transform_func): output = await transform_func(response) diff --git a/infrahub_sdk/ctl/config.py b/infrahub_sdk/ctl/config.py index 38b527d1..b3d2a404 100644 --- a/infrahub_sdk/ctl/config.py +++ b/infrahub_sdk/ctl/config.py @@ -44,7 +44,7 @@ def active(self) -> Settings: return self._settings print("Configuration not properly loaded") - raise typer.Abort() + raise typer.Abort def load(self, config_file: str | Path = "infrahubctl.toml", config_data: dict | None = None) -> None: """Load configuration. @@ -90,7 +90,7 @@ def load_and_exit(self, config_file: str | Path = "infrahubctl.toml", config_dat for error in exc.errors(): loc_str = [str(item) for item in error["loc"]] print(f" {'/'.join(loc_str)} | {error['msg']} ({error['type']})") - raise typer.Abort() + raise typer.Abort SETTINGS = ConfiguredSettings() diff --git a/pyproject.toml b/pyproject.toml index 2ade0bc8..fbd19a54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -229,7 +229,6 @@ ignore = [ "TID", # flake8-tidy-imports "FBT", # flake8-boolean-trap "G", # flake8-logging-format - "RSE", # flake8-raise "BLE", # flake8-blind-except (BLE) ################################################################################################## From 8f9641c7b930f25c2f5d09c570b771d6127be816 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Wed, 28 Jan 2026 14:18:42 +0100 Subject: [PATCH 8/9] Split apart pytest rule violations --- pyproject.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2ade0bc8..86fb6d96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -219,7 +219,6 @@ ignore = [ ################################################################################################## # Rules below needs to be Investigated # ################################################################################################## - "PT", # flake8-pytest-style "ERA", # eradicate commented-out code "SLF001", # flake8-self "EM", # flake8-errmsg @@ -292,6 +291,7 @@ max-complexity = 17 "ANN202", # Missing return type annotation for private function "ANN401", # Dynamically typed expressions (typing.Any) are disallowed "ASYNC240", # Async functions should not use pathlib.Path methods, use trio.Path or anyio.path + "PT013", # Incorrect import of `pytest`; use `import pytest` instead ] "infrahub_sdk/client.py" = [ @@ -347,6 +347,10 @@ max-complexity = 17 "S106", # Possible hardcoded password assigned to argument "ARG001", # Unused function argument "ARG002", # Unused method argument + "PT006", # Wrong type passed to first argument of `pytest.mark.parametrize`; expected `tuple` + "PT011", # `pytest.raises(ValueError)` is too broad, set the `match` parameter or use a more specific exception + "PT012", # `pytest.raises()` block should contain a single simple statement + "PT013", # Incorrect import of `pytest`; use `import pytest` instead ] # tests/integration/ From d6defe3d5dab78951bfa932752a86846a1c0070d Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Wed, 28 Jan 2026 14:25:27 +0100 Subject: [PATCH 9/9] Avoid shadowing builtin `list` --- infrahub_sdk/ctl/repository.py | 4 ++-- pyproject.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/infrahub_sdk/ctl/repository.py b/infrahub_sdk/ctl/repository.py index ec03136a..1e4ca6f4 100644 --- a/infrahub_sdk/ctl/repository.py +++ b/infrahub_sdk/ctl/repository.py @@ -150,8 +150,8 @@ async def add( await client.execute_graphql(query=query.render(), tracker="mutation-repository-create") -@app.command() -async def list( +@app.command(name="list") +async def list_repositories( branch: str | None = typer.Option(None, help="Branch on which to list repositories."), debug: bool = False, _: str = CONFIG_PARAM, diff --git a/pyproject.toml b/pyproject.toml index 2ade0bc8..47e8db5f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -268,7 +268,6 @@ ignorelist = [ # Review and update builtin shadowing below this line "filter", "format", - "list", "property", ]