Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/+f97cdf92.removed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed support for Python 3.9 (end of life)
3 changes: 2 additions & 1 deletion infrahub_sdk/async_typer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import asyncio
import inspect
from collections.abc import Callable
from functools import partial, wraps
from typing import Any, Callable
from typing import Any

from typer import Typer

Expand Down
4 changes: 2 additions & 2 deletions infrahub_sdk/batch.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from __future__ import annotations

import asyncio
from collections.abc import AsyncGenerator, Awaitable, Generator
from collections.abc import AsyncGenerator, Awaitable, Callable, Generator
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Callable
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
from .node import InfrahubNode, InfrahubNodeSync
Expand Down
3 changes: 1 addition & 2 deletions infrahub_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import logging
import time
import warnings
from collections.abc import Coroutine, Mapping, MutableMapping
from collections.abc import Callable, Coroutine, Mapping, MutableMapping
from datetime import datetime
from functools import wraps
from time import sleep
from typing import (
TYPE_CHECKING,
Any,
Callable,
Literal,
TypedDict,
TypeVar,
Expand Down
3 changes: 2 additions & 1 deletion infrahub_sdk/ctl/cli_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import logging
import platform
import sys
from collections.abc import Callable
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Optional
from typing import TYPE_CHECKING, Any, Optional

import typer
import ujson
Expand Down
4 changes: 2 additions & 2 deletions infrahub_sdk/ctl/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import asyncio
import logging
import traceback
from collections.abc import Coroutine
from collections.abc import Callable, Coroutine
from functools import wraps
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, NoReturn, Optional, TypeVar
from typing import TYPE_CHECKING, Any, NoReturn, Optional, TypeVar

import typer
from click.exceptions import Exit
Expand Down
3 changes: 2 additions & 1 deletion infrahub_sdk/node/attribute.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

import ipaddress
from typing import TYPE_CHECKING, Any, Callable, get_args
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, get_args

from ..protocols_base import CoreNodeBase
from ..uuidt import UUIDT
Expand Down
3 changes: 1 addition & 2 deletions infrahub_sdk/node/constants.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import ipaddress
import re
from typing import Union

PROPERTIES_FLAG = ["is_visible", "is_protected"]
PROPERTIES_OBJECT = ["source", "owner"]
SAFE_VALUE = re.compile(r"(^[\. /:a-zA-Z0-9_-]+$)|(^$)")

IP_TYPES = Union[ipaddress.IPv4Interface, ipaddress.IPv6Interface, ipaddress.IPv4Network, ipaddress.IPv6Network]
IP_TYPES = ipaddress.IPv4Interface | ipaddress.IPv6Interface | ipaddress.IPv4Network | ipaddress.IPv6Network

ARTIFACT_FETCH_FEATURE_NOT_SUPPORTED_MESSAGE = (
"calling artifact_fetch is only supported for nodes that are Artifact Definition target"
Expand Down
15 changes: 7 additions & 8 deletions infrahub_sdk/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
from collections.abc import MutableMapping
from enum import Enum
from time import sleep
from typing import TYPE_CHECKING, Any, TypedDict, Union
from typing import TYPE_CHECKING, Any, TypeAlias, TypedDict
from urllib.parse import urlencode

import httpx
from pydantic import BaseModel, Field
from typing_extensions import TypeAlias

from ..exceptions import (
BranchNotFoundError,
Expand Down Expand Up @@ -46,7 +45,7 @@
from ..client import InfrahubClient, InfrahubClientSync, SchemaType, SchemaTypeSync
from ..node import InfrahubNode, InfrahubNodeSync

InfrahubNodeTypes = Union[InfrahubNode, InfrahubNodeSync]
InfrahubNodeTypes: TypeAlias = InfrahubNode | InfrahubNodeSync


__all__ = [
Expand Down Expand Up @@ -84,11 +83,11 @@ class EnumMutation(str, Enum):
remove = "SchemaEnumRemove"


MainSchemaTypes: TypeAlias = Union[NodeSchema, GenericSchema]
MainSchemaTypesAPI: TypeAlias = Union[NodeSchemaAPI, GenericSchemaAPI, ProfileSchemaAPI, TemplateSchemaAPI]
MainSchemaTypesAll: TypeAlias = Union[
NodeSchema, GenericSchema, NodeSchemaAPI, GenericSchemaAPI, ProfileSchemaAPI, TemplateSchemaAPI
]
MainSchemaTypes: TypeAlias = NodeSchema | GenericSchema
MainSchemaTypesAPI: TypeAlias = NodeSchemaAPI | GenericSchemaAPI | ProfileSchemaAPI | TemplateSchemaAPI
MainSchemaTypesAll: TypeAlias = (
NodeSchema | GenericSchema | NodeSchemaAPI | GenericSchemaAPI | ProfileSchemaAPI | TemplateSchemaAPI
)


class SchemaWarningType(Enum):
Expand Down
4 changes: 2 additions & 2 deletions infrahub_sdk/schema/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import warnings
from collections.abc import MutableMapping
from enum import Enum
from typing import TYPE_CHECKING, Any, Union
from typing import TYPE_CHECKING, Any

from pydantic import BaseModel, ConfigDict, Field
from typing_extensions import Self

if TYPE_CHECKING:
from ..node import InfrahubNode, InfrahubNodeSync

InfrahubNodeTypes = Union[InfrahubNode, InfrahubNodeSync]
InfrahubNodeTypes = InfrahubNode | InfrahubNodeSync


class RelationshipCardinality(str, Enum):
Expand Down
4 changes: 2 additions & 2 deletions infrahub_sdk/schema/repository.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Any, TypeVar, Union
from typing import TYPE_CHECKING, Any, TypeVar

from pydantic import BaseModel, ConfigDict, Field, field_validator

Expand All @@ -18,7 +18,7 @@
if TYPE_CHECKING:
from ..node import InfrahubNode, InfrahubNodeSync

InfrahubNodeTypes = Union[InfrahubNode, InfrahubNodeSync]
InfrahubNodeTypes = InfrahubNode | InfrahubNodeSync

ResourceClass = TypeVar("ResourceClass")

Expand Down
2 changes: 1 addition & 1 deletion infrahub_sdk/spec/range_expansion.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def _extract_constants(pattern: str, re_compiled: re.Pattern) -> tuple[list[int]
def _expand_interfaces(pattern: str, interface_constant: list[int], cartesian_list: list[list[str]]) -> list[str]:
def _pairwise(lst: list[int]) -> list[tuple[int, int]]:
it = iter(lst)
return list(zip(it, it))
return list(zip(it, it, strict=False))

if interface_constant[-1] < len(pattern):
interface_constant.append(len(pattern))
Expand Down
3 changes: 2 additions & 1 deletion infrahub_sdk/template/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from __future__ import annotations

import linecache
from collections.abc import Callable
from pathlib import Path
from typing import Any, Callable, NoReturn
from typing import Any, NoReturn

import jinja2
from jinja2 import meta, nodes
Expand Down
2 changes: 1 addition & 1 deletion infrahub_sdk/transfer/importer/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async def import_data(self, import_directory: Path, branch: str) -> None:

with self.wrapped_task_output("Analyzing import"):
import_nodes_by_kind = defaultdict(list)
for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind")):
for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=False):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Consider using strict=True for data integrity.

Since both columns come from the same table, they should always have identical lengths. Using strict=False would silently skip rows if the columns have mismatched lengths due to data corruption or a bug, potentially causing incomplete imports.

Apply this diff to fail fast on data integrity issues:

-            for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=False):
+            for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=True):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=False):
for graphql_data, kind in zip(table.column("graphql_json"), table.column("kind"), strict=True):
🤖 Prompt for AI Agents
In infrahub_sdk/transfer/importer/json.py around line 65, the zip over
table.column("graphql_json") and table.column("kind") uses strict=False which
can silently drop mismatched rows; change it to strict=True to raise an error on
length mismatches so the importer fails fast on data integrity issues, and
handle or propagate the resulting exception where appropriate (e.g., let it
bubble up or catch and log a clear error message).

node = await InfrahubNode.from_graphql(self.client, branch, ujson.loads(str(graphql_data)))
import_nodes_by_kind[str(kind)].append(node)
self.all_nodes[node.id] = node
Expand Down
4 changes: 2 additions & 2 deletions infrahub_sdk/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import enum
from logging import Logger
from typing import TYPE_CHECKING, Any, Protocol, Union, runtime_checkable
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable

from pydantic import BaseModel

Expand Down Expand Up @@ -65,7 +65,7 @@ def exception(self, event: str | None = None, *args: Any, **kw: Any) -> Any:
"""Send an exception event."""


InfrahubLoggers = Union[InfrahubLogger, Logger]
InfrahubLoggers = InfrahubLogger | Logger


class Order(BaseModel):
Expand Down
8 changes: 1 addition & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ authors = [
]
readme = "README.md"
license = {text = "Apache-2.0"}
requires-python = ">=3.9,<3.14"
requires-python = ">=3.10,<3.14"
classifiers = [
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand All @@ -26,7 +25,6 @@ dependencies = [
"dulwich>=0.21.4",
"whenever>=0.7.2,<0.8.0",
"netutils>=1.0.0",
"eval-type-backport>=0.2.2; python_version>='3.9' and python_version<'3.10'",
"tomli>=1.1.0; python_version<'3.11'",
]

Expand Down Expand Up @@ -252,10 +250,6 @@ max-complexity = 17
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed
]

"infrahub_sdk/ctl/**/*.py" = [
"UP007", # Use `X | Y` for type annotations | Required for Typer until we can drop the support for Python 3.9
]

"infrahub_sdk/client.py" = [
##################################################################################################
# Review and change the below later #
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/sdk/test_batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ async def test_batch_return_exception(

result_iter = batch.execute()
# Assert first node success
node, result = await result_iter.__anext__()
node, result = await anext(result_iter)
assert node == results[0]
assert not isinstance(result, Exception)

# Assert second node failure
node, result = await result_iter.__anext__()
node, result = await anext(result_iter)
assert node == results[1]
assert isinstance(result, GraphQLError)
assert "An error occurred while executing the GraphQL Query" in str(result)
Expand Down
Loading