From 8aaec9adbfc43168fd8855c6c9ea597fe49e9055 Mon Sep 17 00:00:00 2001 From: Damien Garros Date: Thu, 2 Jan 2025 13:42:44 +0100 Subject: [PATCH] Implement PEP 604 with future-annotations --- infrahub_sdk/_importer.py | 6 +- infrahub_sdk/analyzer.py | 16 +- infrahub_sdk/batch.py | 25 +- infrahub_sdk/branch.py | 36 +- infrahub_sdk/checks.py | 28 +- infrahub_sdk/client.py | 1038 ++++++++--------- infrahub_sdk/code_generator.py | 10 +- infrahub_sdk/config.py | 28 +- infrahub_sdk/ctl/check.py | 26 +- infrahub_sdk/ctl/cli_commands.py | 22 +- infrahub_sdk/ctl/client.py | 34 +- infrahub_sdk/ctl/config.py | 13 +- infrahub_sdk/ctl/exporter.py | 5 +- infrahub_sdk/ctl/generator.py | 12 +- infrahub_sdk/ctl/repository.py | 5 +- infrahub_sdk/ctl/schema.py | 10 +- infrahub_sdk/ctl/utils.py | 22 +- infrahub_sdk/ctl/validate.py | 5 +- infrahub_sdk/data.py | 6 +- infrahub_sdk/exceptions.py | 28 +- infrahub_sdk/generator.py | 14 +- infrahub_sdk/graphql.py | 8 +- infrahub_sdk/groups.py | 4 +- infrahub_sdk/node.py | 212 ++-- infrahub_sdk/object_store.py | 10 +- infrahub_sdk/playback.py | 16 +- infrahub_sdk/protocols_base.py | 60 +- infrahub_sdk/pytest_plugin/items/base.py | 8 +- infrahub_sdk/pytest_plugin/items/check.py | 4 +- .../pytest_plugin/items/graphql_query.py | 4 +- .../pytest_plugin/items/jinja2_transform.py | 10 +- .../pytest_plugin/items/python_transform.py | 4 +- infrahub_sdk/pytest_plugin/loader.py | 4 +- infrahub_sdk/pytest_plugin/models.py | 20 +- infrahub_sdk/pytest_plugin/plugin.py | 5 +- infrahub_sdk/query_groups.py | 30 +- infrahub_sdk/schema/__init__.py | 114 +- infrahub_sdk/schema/main.py | 100 +- infrahub_sdk/schema/repository.py | 18 +- infrahub_sdk/spec/menu.py | 4 +- infrahub_sdk/spec/object.py | 18 +- infrahub_sdk/store.py | 44 +- infrahub_sdk/task_report.py | 42 +- infrahub_sdk/testing/repository.py | 14 +- infrahub_sdk/timestamp.py | 3 +- infrahub_sdk/transfer/exporter/interface.py | 5 +- infrahub_sdk/transfer/exporter/json.py | 13 +- infrahub_sdk/transfer/importer/json.py | 15 +- infrahub_sdk/transfer/schema_sorter.py | 10 +- infrahub_sdk/transforms.py | 12 +- infrahub_sdk/types.py | 23 +- infrahub_sdk/utils.py | 10 +- infrahub_sdk/uuidt.py | 11 +- infrahub_sdk/yaml.py | 14 +- poetry.lock | 18 +- pyproject.toml | 9 +- tests/unit/ctl/test_cli.py | 6 + tests/unit/ctl/test_repository_app.py | 7 + tests/unit/ctl/test_transform_app.py | 11 +- tests/unit/ctl/test_validate_app.py | 7 + tests/unit/sdk/conftest.py | 18 +- 61 files changed, 1209 insertions(+), 1125 deletions(-) diff --git a/infrahub_sdk/_importer.py b/infrahub_sdk/_importer.py index b45beb85..27af0970 100644 --- a/infrahub_sdk/_importer.py +++ b/infrahub_sdk/_importer.py @@ -3,7 +3,7 @@ import importlib import sys from pathlib import Path -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from .exceptions import ModuleImportError @@ -13,9 +13,7 @@ module_mtime_cache: dict[str, float] = {} -def import_module( - module_path: Path, import_root: Optional[str] = None, relative_path: Optional[str] = None -) -> ModuleType: +def import_module(module_path: Path, import_root: str | None = None, relative_path: str | None = None) -> ModuleType: """Imports a python module. Args: diff --git a/infrahub_sdk/analyzer.py b/infrahub_sdk/analyzer.py index 89f4e7ef..f2582fbc 100644 --- a/infrahub_sdk/analyzer.py +++ b/infrahub_sdk/analyzer.py @@ -1,4 +1,6 @@ -from typing import Any, Optional +from __future__ import annotations + +from typing import Any from graphql import ( DocumentNode, @@ -19,23 +21,23 @@ class GraphQLQueryVariable(BaseModel): name: str type: str required: bool = False - default_value: Optional[Any] = None + default_value: Any | None = None class GraphQLOperation(BaseModel): - name: Optional[str] = None + name: str | None = None operation_type: OperationType class GraphQLQueryAnalyzer: - def __init__(self, query: str, schema: Optional[GraphQLSchema] = None): + def __init__(self, query: str, schema: GraphQLSchema | None = None): self.query: str = query - self.schema: Optional[GraphQLSchema] = schema + self.schema: GraphQLSchema | None = schema self.document: DocumentNode = parse(self.query) - self._fields: Optional[dict] = None + self._fields: dict | None = None @property - def is_valid(self) -> tuple[bool, Optional[list[GraphQLError]]]: + def is_valid(self) -> tuple[bool, list[GraphQLError] | None]: if self.schema is None: return False, [GraphQLError("Schema is not provided")] diff --git a/infrahub_sdk/batch.py b/infrahub_sdk/batch.py index 43304a10..f9e8ccd3 100644 --- a/infrahub_sdk/batch.py +++ b/infrahub_sdk/batch.py @@ -1,10 +1,13 @@ +from __future__ import annotations + import asyncio -from collections.abc import AsyncGenerator, Awaitable +from collections.abc import AsyncGenerator, Awaitable, Generator from concurrent.futures import ThreadPoolExecutor from dataclasses import dataclass -from typing import Any, Callable, Generator, Optional +from typing import TYPE_CHECKING, Any, Callable -from .node import InfrahubNode, InfrahubNodeSync +if TYPE_CHECKING: + from .node import InfrahubNode, InfrahubNodeSync @dataclass @@ -12,7 +15,7 @@ class BatchTask: task: Callable[[Any], Awaitable[Any]] args: tuple[Any, ...] kwargs: dict[str, Any] - node: Optional[Any] = None + node: Any | None = None @dataclass @@ -20,9 +23,9 @@ class BatchTaskSync: task: Callable[..., Any] args: tuple[Any, ...] kwargs: dict[str, Any] - node: Optional[InfrahubNodeSync] = None + node: InfrahubNodeSync | None = None - def execute(self, return_exceptions: bool = False) -> tuple[Optional[InfrahubNodeSync], Any]: + def execute(self, return_exceptions: bool = False) -> tuple[InfrahubNodeSync | None, Any]: """Executes the stored task.""" result = None try: @@ -37,7 +40,7 @@ def execute(self, return_exceptions: bool = False) -> tuple[Optional[InfrahubNod async def execute_batch_task_in_pool( task: BatchTask, semaphore: asyncio.Semaphore, return_exceptions: bool = False -) -> tuple[Optional[InfrahubNode], Any]: +) -> tuple[InfrahubNode | None, Any]: async with semaphore: try: result = await task.task(*task.args, **task.kwargs) @@ -52,7 +55,7 @@ async def execute_batch_task_in_pool( class InfrahubBatch: def __init__( self, - semaphore: Optional[asyncio.Semaphore] = None, + semaphore: asyncio.Semaphore | None = None, max_concurrent_execution: int = 5, return_exceptions: bool = False, ): @@ -64,7 +67,7 @@ def __init__( def num_tasks(self) -> int: return len(self._tasks) - def add(self, *args: Any, task: Callable, node: Optional[Any] = None, **kwargs: Any) -> None: + def add(self, *args: Any, task: Callable, node: Any | None = None, **kwargs: Any) -> None: self._tasks.append(BatchTask(task=task, node=node, args=args, kwargs=kwargs)) async def execute(self) -> AsyncGenerator: @@ -96,10 +99,10 @@ def __init__(self, max_concurrent_execution: int = 5, return_exceptions: bool = def num_tasks(self) -> int: return len(self._tasks) - def add(self, *args: Any, task: Callable[..., Any], node: Optional[Any] = None, **kwargs: Any) -> None: + def add(self, *args: Any, task: Callable[..., Any], node: Any | None = None, **kwargs: Any) -> None: self._tasks.append(BatchTaskSync(task=task, node=node, args=args, kwargs=kwargs)) - def execute(self) -> Generator[tuple[Optional[InfrahubNodeSync], Any], None, None]: + def execute(self) -> Generator[tuple[InfrahubNodeSync | None, Any], None, None]: with ThreadPoolExecutor(max_workers=self.max_concurrent_execution) as executor: futures = [executor.submit(task.execute, return_exceptions=self.return_exceptions) for task in self._tasks] for future in futures: diff --git a/infrahub_sdk/branch.py b/infrahub_sdk/branch.py index 18d32020..b4e21d64 100644 --- a/infrahub_sdk/branch.py +++ b/infrahub_sdk/branch.py @@ -1,7 +1,7 @@ from __future__ import annotations import warnings -from typing import TYPE_CHECKING, Any, Literal, Optional, Union, overload +from typing import TYPE_CHECKING, Any, Literal, overload from urllib.parse import urlencode from pydantic import BaseModel @@ -17,11 +17,11 @@ class BranchData(BaseModel): id: str name: str - description: Optional[str] = None + description: str | None = None sync_with_git: bool is_default: bool has_schema_changes: bool - origin_branch: Optional[str] = None + origin_branch: str | None = None branched_from: str @@ -50,11 +50,11 @@ class InfraHubBranchManagerBase: @classmethod def generate_diff_data_url( cls, - client: Union[InfrahubClient, InfrahubClientSync], + client: InfrahubClient | InfrahubClientSync, branch_name: str, branch_only: bool = True, - time_from: Optional[str] = None, - time_to: Optional[str] = None, + time_from: str | None = None, + time_to: str | None = None, ) -> str: """Generate the URL for the diff_data function.""" url = f"{client.address}/api/diff/data" @@ -80,7 +80,7 @@ async def create( sync_with_git: bool = True, description: str = "", wait_until_completion: Literal[True] = True, - background_execution: Optional[bool] = False, + background_execution: bool | None = False, ) -> BranchData: ... @overload @@ -90,7 +90,7 @@ async def create( sync_with_git: bool = True, description: str = "", wait_until_completion: Literal[False] = False, - background_execution: Optional[bool] = False, + background_execution: bool | None = False, ) -> str: ... async def create( @@ -99,8 +99,8 @@ async def create( sync_with_git: bool = True, description: str = "", wait_until_completion: bool = True, - background_execution: Optional[bool] = False, - ) -> Union[BranchData, str]: + background_execution: bool | None = False, + ) -> BranchData | str: if background_execution is not None: warnings.warn( "`background_execution` is deprecated, please use `wait_until_completion` instead.", @@ -206,8 +206,8 @@ async def diff_data( self, branch_name: str, branch_only: bool = True, - time_from: Optional[str] = None, - time_to: Optional[str] = None, + time_from: str | None = None, + time_to: str | None = None, ) -> dict[Any, Any]: url = self.generate_diff_data_url( client=self.client, @@ -251,7 +251,7 @@ def create( sync_with_git: bool = True, description: str = "", wait_until_completion: Literal[True] = True, - background_execution: Optional[bool] = False, + background_execution: bool | None = False, ) -> BranchData: ... @overload @@ -261,7 +261,7 @@ def create( sync_with_git: bool = True, description: str = "", wait_until_completion: Literal[False] = False, - background_execution: Optional[bool] = False, + background_execution: bool | None = False, ) -> str: ... def create( @@ -270,8 +270,8 @@ def create( sync_with_git: bool = True, description: str = "", wait_until_completion: bool = True, - background_execution: Optional[bool] = False, - ) -> Union[BranchData, str]: + background_execution: bool | None = False, + ) -> BranchData | str: if background_execution is not None: warnings.warn( "`background_execution` is deprecated, please use `wait_until_completion` instead.", @@ -313,8 +313,8 @@ def diff_data( self, branch_name: str, branch_only: bool = True, - time_from: Optional[str] = None, - time_to: Optional[str] = None, + time_from: str | None = None, + time_to: str | None = None, ) -> dict[Any, Any]: url = self.generate_diff_data_url( client=self.client, diff --git a/infrahub_sdk/checks.py b/infrahub_sdk/checks.py index 5b6c2c55..731d6476 100644 --- a/infrahub_sdk/checks.py +++ b/infrahub_sdk/checks.py @@ -5,7 +5,7 @@ import os import warnings from abc import abstractmethod -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import ujson from git.repo import Repo @@ -33,20 +33,20 @@ class InfrahubCheckInitializer(BaseModel): class InfrahubCheck: - name: Optional[str] = None + name: str | None = None query: str = "" timeout: int = 10 def __init__( self, - branch: Optional[str] = None, + branch: str | None = None, root_directory: str = "", - output: Optional[str] = None, - initializer: Optional[InfrahubCheckInitializer] = None, - params: Optional[dict] = None, - client: Optional[InfrahubClient] = None, + output: str | None = None, + initializer: InfrahubCheckInitializer | None = None, + params: dict | None = None, + client: InfrahubClient | None = None, ): - self.git: Optional[Repo] = None + self.git: Repo | None = None self.initializer = initializer or InfrahubCheckInitializer() self.logs: list[dict[str, Any]] = [] @@ -82,7 +82,7 @@ def client(self, value: InfrahubClient) -> None: self._client = value @classmethod - async def init(cls, client: Optional[InfrahubClient] = None, *args: Any, **kwargs: Any) -> InfrahubCheck: + async def init(cls, client: InfrahubClient | None = None, *args: Any, **kwargs: Any) -> InfrahubCheck: """Async init method, If an existing InfrahubClient client hasn't been provided, one will be created automatically.""" warnings.warn( "InfrahubCheck.init has been deprecated and will be removed in the version in Infrahub SDK 2.0.0", @@ -101,7 +101,7 @@ def errors(self) -> list[dict[str, Any]]: return [log for log in self.logs if log["level"] == "ERROR"] def _write_log_entry( - self, message: str, level: str, object_id: Optional[str] = None, object_type: Optional[str] = None + self, message: str, level: str, object_id: str | None = None, object_type: str | None = None ) -> None: log_message = {"level": level, "message": message, "branch": self.branch_name} if object_id: @@ -113,10 +113,10 @@ def _write_log_entry( if self.output == "stdout": print(ujson.dumps(log_message)) - def log_error(self, message: str, object_id: Optional[str] = None, object_type: Optional[str] = None) -> None: + def log_error(self, message: str, object_id: str | None = None, object_type: str | None = None) -> None: self._write_log_entry(message=message, level="ERROR", object_id=object_id, object_type=object_type) - def log_info(self, message: str, object_id: Optional[str] = None, object_type: Optional[str] = None) -> None: + def log_info(self, message: str, object_id: str | None = None, object_type: str | None = None) -> None: self._write_log_entry(message=message, level="INFO", object_id=object_id, object_type=object_type) @property @@ -155,7 +155,7 @@ async def collect_data(self) -> dict: return await self.client.query_gql_query(name=self.query, branch_name=self.branch_name, variables=self.params) - async def run(self, data: Optional[dict] = None) -> bool: + async def run(self, data: dict | None = None) -> bool: """Execute the check after collecting the data from the GraphQL query. The result of the check is determined based on the presence or not of ERROR log messages.""" @@ -179,7 +179,7 @@ async def run(self, data: Optional[dict] = None) -> bool: def get_check_class_instance( - check_config: InfrahubCheckDefinitionConfig, search_path: Optional[Path] = None + check_config: InfrahubCheckDefinitionConfig, search_path: Path | None = None ) -> InfrahubCheck: if check_config.file_path.is_absolute() or search_path is None: search_location = check_config.file_path diff --git a/infrahub_sdk/client.py b/infrahub_sdk/client.py index 9fca57b7..4b561533 100644 --- a/infrahub_sdk/client.py +++ b/infrahub_sdk/client.py @@ -11,10 +11,8 @@ Any, Callable, Literal, - Optional, TypedDict, TypeVar, - Union, overload, ) from urllib.parse import urlencode @@ -110,7 +108,7 @@ class BaseClient: def __init__( self, address: str = "", - config: Optional[Union[Config, dict[str, Any]]] = None, + config: Config | dict[str, Any] | None = None, ): self.client = None self.headers = {"content-type": "application/json"} @@ -140,7 +138,7 @@ def __init__( self.update_group_context = self.config.update_group_context self.identifier = self.config.identifier - self.group_context: Union[InfrahubGroupContext, InfrahubGroupContextSync] + self.group_context: InfrahubGroupContext | InfrahubGroupContextSync self._initialize() def _initialize(self) -> None: @@ -149,7 +147,7 @@ def _initialize(self) -> None: def _record(self, response: httpx.Response) -> None: self.config.custom_recorder.record(response) - def _echo(self, url: str, query: str, variables: Optional[dict] = None) -> None: + def _echo(self, url: str, query: str, variables: dict | None = None) -> None: if self.config.echo_graphql_queries: print(f"URL: {url}") print(f"QUERY:\n{query}") @@ -158,10 +156,10 @@ def _echo(self, url: str, query: str, variables: Optional[dict] = None) -> None: def start_tracking( self, - identifier: Optional[str] = None, - params: Optional[dict[str, Any]] = None, + identifier: str | None = None, + params: dict[str, Any] | None = None, delete_unused_nodes: bool = False, - group_type: Optional[str] = None, + group_type: str | None = None, ) -> Self: self.mode = InfrahubClientMode.TRACKING identifier = identifier or self.identifier or "python-sdk" @@ -173,10 +171,10 @@ def start_tracking( def set_context_properties( self, identifier: str, - params: Optional[dict[str, str]] = None, + params: dict[str, str] | None = None, delete_unused_nodes: bool = True, reset: bool = True, - group_type: Optional[str] = None, + group_type: str | None = None, ) -> None: if reset: if isinstance(self, InfrahubClient): @@ -189,8 +187,8 @@ def set_context_properties( def _graphql_url( self, - branch_name: Optional[str] = None, - at: Optional[Union[str, Timestamp]] = None, + branch_name: str | None = None, + at: str | Timestamp | None = None, ) -> str: url = f"{self.config.address}/graphql" if branch_name: @@ -207,10 +205,10 @@ def _graphql_url( def _build_ip_address_allocation_query( self, resource_pool_id: str, - identifier: Optional[str] = None, - prefix_length: Optional[int] = None, - address_type: Optional[str] = None, - data: Optional[dict[str, Any]] = None, + identifier: str | None = None, + prefix_length: int | None = None, + address_type: str | None = None, + data: dict[str, Any] | None = None, ) -> Mutation: input_data: dict[str, Any] = {"id": resource_pool_id} @@ -233,11 +231,11 @@ def _build_ip_address_allocation_query( def _build_ip_prefix_allocation_query( self, resource_pool_id: str, - identifier: Optional[str] = None, - prefix_length: Optional[int] = None, - member_type: Optional[str] = None, - prefix_type: Optional[str] = None, - data: Optional[dict[str, Any]] = None, + identifier: str | None = None, + prefix_length: int | None = None, + member_type: str | None = None, + prefix_type: str | None = None, + data: dict[str, Any] | None = None, ) -> Mutation: input_data: dict[str, Any] = {"id": resource_pool_id} @@ -280,8 +278,8 @@ def _initialize(self) -> None: async def create( self, kind: str, - data: Optional[dict] = ..., - branch: Optional[str] = ..., + data: dict | None = ..., + branch: str | None = ..., **kwargs: Any, ) -> InfrahubNode: ... @@ -289,19 +287,19 @@ async def create( async def create( self, kind: type[SchemaType], - data: Optional[dict] = ..., - branch: Optional[str] = ..., + data: dict | None = ..., + branch: str | None = ..., **kwargs: Any, ) -> SchemaType: ... async def create( self, - kind: Union[str, type[SchemaType]], - data: Optional[dict] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, + kind: str | type[SchemaType], + data: dict | None = None, + branch: str | None = None, + timeout: int | None = None, **kwargs: Any, - ) -> Union[InfrahubNode, SchemaType]: + ) -> InfrahubNode | SchemaType: branch = branch or self.default_branch schema = await self.schema.get(kind=kind, branch=branch, timeout=timeout) @@ -311,7 +309,7 @@ async def create( return InfrahubNode(client=self, schema=schema, branch=branch, data=data or kwargs) - async def delete(self, kind: Union[str, type[SchemaType]], id: str, branch: Optional[str] = None) -> None: + async def delete(self, kind: str | type[SchemaType], id: str, branch: str | None = None) -> None: branch = branch or self.default_branch schema = await self.schema.get(kind=kind, branch=branch) @@ -323,31 +321,31 @@ async def get( self, kind: type[SchemaType], raise_when_missing: Literal[False], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., **kwargs: Any, - ) -> Optional[SchemaType]: ... + ) -> SchemaType | None: ... @overload async def get( self, kind: type[SchemaType], raise_when_missing: Literal[True], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -359,13 +357,13 @@ async def get( self, kind: type[SchemaType], raise_when_missing: bool = ..., - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -377,31 +375,31 @@ async def get( self, kind: str, raise_when_missing: Literal[False], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., **kwargs: Any, - ) -> Optional[InfrahubNode]: ... + ) -> InfrahubNode | None: ... @overload async def get( self, kind: str, raise_when_missing: Literal[True], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -413,13 +411,13 @@ async def get( self, kind: str, raise_when_missing: bool = ..., - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -428,20 +426,20 @@ async def get( async def get( self, - kind: Union[str, type[SchemaType]], + kind: str | type[SchemaType], raise_when_missing: bool = True, - at: Optional[Timestamp] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, - id: Optional[str] = None, - hfid: Optional[list[str]] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + at: Timestamp | None = None, + branch: str | None = None, + timeout: int | None = None, + id: str | None = None, + hfid: list[str] | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, populate_store: bool = False, fragment: bool = False, prefetch_relationships: bool = False, **kwargs: Any, - ) -> Union[InfrahubNode, SchemaType, None]: + ) -> InfrahubNode | SchemaType | None: branch = branch or self.default_branch schema = await self.schema.get(kind=kind, branch=branch) @@ -490,7 +488,7 @@ async def _process_nodes_and_relationships( schema_kind: str, branch: str, prefetch_relationships: bool, - timeout: Optional[int] = None, + timeout: int | None = None, ) -> ProcessRelationsNode: """Processes InfrahubNode and their Relationships from the GraphQL query response. @@ -525,14 +523,14 @@ async def _process_nodes_and_relationships( async def all( self, kind: type[SchemaType], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., ) -> list[SchemaType]: ... @@ -541,32 +539,32 @@ async def all( async def all( self, kind: str, - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., ) -> list[InfrahubNode]: ... async def all( self, - kind: Union[str, type[SchemaType]], - at: Optional[Timestamp] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, + kind: str | type[SchemaType], + at: Timestamp | None = None, + branch: str | None = None, + timeout: int | None = None, populate_store: bool = False, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, fragment: bool = False, prefetch_relationships: bool = False, - ) -> Union[list[InfrahubNode], list[SchemaType]]: + ) -> list[InfrahubNode] | list[SchemaType]: """Retrieve all nodes of a given kind Args: @@ -603,14 +601,14 @@ async def all( async def filters( self, kind: type[SchemaType], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., partial_match: bool = ..., @@ -621,14 +619,14 @@ async def filters( async def filters( self, kind: str, - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., partial_match: bool = ..., @@ -637,20 +635,20 @@ async def filters( async def filters( self, - kind: Union[str, type[SchemaType]], - at: Optional[Timestamp] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, + kind: str | type[SchemaType], + at: Timestamp | None = None, + branch: str | None = None, + timeout: int | None = None, populate_store: bool = False, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, fragment: bool = False, prefetch_relationships: bool = False, partial_match: bool = False, **kwargs: Any, - ) -> Union[list[InfrahubNode], list[SchemaType]]: + ) -> list[InfrahubNode] | list[SchemaType]: """Retrieve nodes of a given kind based on provided filters. Args: @@ -742,12 +740,12 @@ def clone(self) -> InfrahubClient: async def execute_graphql( self, query: str, - variables: Optional[dict] = None, - branch_name: Optional[str] = None, - at: Optional[Union[str, Timestamp]] = None, - timeout: Optional[int] = None, + variables: dict | None = None, + branch_name: str | None = None, + at: str | Timestamp | None = None, + timeout: int | None = None, raise_for_error: bool = True, - tracker: Optional[str] = None, + tracker: str | None = None, ) -> dict: """Execute a GraphQL query (or mutation). If retry_on_failure is True, the query will retry until the server becomes reacheable. @@ -769,7 +767,7 @@ async def execute_graphql( branch_name = branch_name or self.default_branch url = self._graphql_url(branch_name=branch_name, at=at) - payload: dict[str, Union[str, dict]] = {"query": query} + payload: dict[str, str | dict] = {"query": query} if variables: payload["variables"] = variables @@ -820,7 +818,7 @@ async def execute_graphql( @handle_relogin async def _post( - self, url: str, payload: dict, headers: Optional[dict] = None, timeout: Optional[int] = None + self, url: str, payload: dict, headers: dict | None = None, timeout: int | None = None ) -> httpx.Response: """Execute a HTTP POST with HTTPX. @@ -839,7 +837,7 @@ async def _post( ) @handle_relogin - async def _get(self, url: str, headers: Optional[dict] = None, timeout: Optional[int] = None) -> httpx.Response: + async def _get(self, url: str, headers: dict | None = None, timeout: int | None = None) -> httpx.Response: """Execute a HTTP GET with HTTPX. Raises: @@ -857,20 +855,20 @@ async def _get(self, url: str, headers: Optional[dict] = None, timeout: Optional ) async def _request( - self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: Optional[dict] = None + self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: dict | None = None ) -> httpx.Response: response = await self._request_method(url=url, method=method, headers=headers, timeout=timeout, payload=payload) self._record(response) return response async def _default_request_method( - self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: Optional[dict] = None + self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: dict | None = None ) -> httpx.Response: params: dict[str, Any] = {} if payload: params["json"] = payload - proxy_config: dict[str, Union[str, dict[str, httpx.HTTPTransport]]] = {} + proxy_config: dict[str, str | dict[str, httpx.HTTPTransport]] = {} if self.config.proxy: proxy_config["proxy"] = self.config.proxy elif self.config.proxy_mounts.is_set: @@ -953,14 +951,14 @@ async def login(self, refresh: bool = False) -> None: async def query_gql_query( self, name: str, - variables: Optional[dict] = None, + variables: dict | None = None, update_group: bool = False, - subscribers: Optional[list[str]] = None, - params: Optional[dict] = None, - branch_name: Optional[str] = None, - at: Optional[str] = None, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + subscribers: list[str] | None = None, + params: dict | None = None, + branch_name: str | None = None, + at: str | None = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, ) -> dict: url = f"{self.address}/api/query/{name}" @@ -1015,8 +1013,8 @@ async def query_gql_query( async def get_diff_summary( self, branch: str, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, ) -> list[NodeDiff]: query = get_diff_summary_query() @@ -1045,13 +1043,13 @@ async def allocate_next_ip_address( self, resource_pool: CoreNode, kind: type[SchemaType], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> SchemaType: ... @@ -1060,28 +1058,28 @@ async def allocate_next_ip_address( self, resource_pool: CoreNode, kind: type[SchemaType], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[SchemaType]: ... + ) -> SchemaType | None: ... @overload async def allocate_next_ip_address( self, resource_pool: CoreNode, kind: type[SchemaType], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., ) -> SchemaType: ... @@ -1090,13 +1088,13 @@ async def allocate_next_ip_address( self, resource_pool: CoreNode, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> CoreNode: ... @@ -1105,44 +1103,44 @@ async def allocate_next_ip_address( self, resource_pool: CoreNode, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[CoreNode]: ... + ) -> CoreNode | None: ... @overload async def allocate_next_ip_address( self, resource_pool: CoreNode, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., - ) -> Optional[CoreNode]: ... + ) -> CoreNode | None: ... async def allocate_next_ip_address( self, resource_pool: CoreNode, - kind: Optional[type[SchemaType]] = None, # pylint: disable=unused-argument - identifier: Optional[str] = None, - prefix_length: Optional[int] = None, - address_type: Optional[str] = None, - data: Optional[dict[str, Any]] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + kind: type[SchemaType] | None = None, # pylint: disable=unused-argument + identifier: str | None = None, + prefix_length: int | None = None, + address_type: str | None = None, + data: dict[str, Any] | None = None, + branch: str | None = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, - ) -> Optional[Union[CoreNode, SchemaType]]: + ) -> CoreNode | SchemaType | None: """Allocate a new IP address by using the provided resource pool. Args: @@ -1189,14 +1187,14 @@ async def allocate_next_ip_prefix( self, resource_pool: CoreNode, kind: type[SchemaType], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> SchemaType: ... @@ -1205,30 +1203,30 @@ async def allocate_next_ip_prefix( self, resource_pool: CoreNode, kind: type[SchemaType], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[SchemaType]: ... + ) -> SchemaType | None: ... @overload async def allocate_next_ip_prefix( self, resource_pool: CoreNode, kind: type[SchemaType], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., ) -> SchemaType: ... @@ -1237,14 +1235,14 @@ async def allocate_next_ip_prefix( self, resource_pool: CoreNode, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> CoreNode: ... @@ -1253,47 +1251,47 @@ async def allocate_next_ip_prefix( self, resource_pool: CoreNode, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[CoreNode]: ... + ) -> CoreNode | None: ... @overload async def allocate_next_ip_prefix( self, resource_pool: CoreNode, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., - ) -> Optional[CoreNode]: ... + ) -> CoreNode | None: ... async def allocate_next_ip_prefix( self, resource_pool: CoreNode, - kind: Optional[type[SchemaType]] = None, # pylint: disable=unused-argument - identifier: Optional[str] = None, - prefix_length: Optional[int] = None, - member_type: Optional[str] = None, - prefix_type: Optional[str] = None, - data: Optional[dict[str, Any]] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + kind: type[SchemaType] | None = None, # pylint: disable=unused-argument + identifier: str | None = None, + prefix_length: int | None = None, + member_type: str | None = None, + prefix_type: str | None = None, + data: dict[str, Any] | None = None, + branch: str | None = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, - ) -> Optional[Union[CoreNode, SchemaType]]: + ) -> CoreNode | SchemaType | None: """Allocate a new IP prefix by using the provided resource pool. Args: @@ -1337,7 +1335,7 @@ async def create_batch(self, return_exceptions: bool = False) -> InfrahubBatch: return InfrahubBatch(semaphore=self.concurrent_execution_limit, return_exceptions=return_exceptions) async def get_list_repositories( - self, branches: Optional[dict[str, BranchData]] = None, kind: str = "CoreGenericRepository" + self, branches: dict[str, BranchData] | None = None, kind: str = "CoreGenericRepository" ) -> dict[str, RepositoryData]: branches = branches or await self.branch.all() @@ -1392,9 +1390,9 @@ async def __aenter__(self) -> Self: async def __aexit__( self, - exc_type: Optional[type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, ) -> None: if exc_type is None and self.mode == InfrahubClientMode.TRACKING: await self.group_context.update_group() @@ -1417,8 +1415,8 @@ def _initialize(self) -> None: def create( self, kind: str, - data: Optional[dict] = ..., - branch: Optional[str] = ..., + data: dict | None = ..., + branch: str | None = ..., **kwargs: Any, ) -> InfrahubNodeSync: ... @@ -1426,19 +1424,19 @@ def create( def create( self, kind: type[SchemaTypeSync], - data: Optional[dict] = ..., - branch: Optional[str] = ..., + data: dict | None = ..., + branch: str | None = ..., **kwargs: Any, ) -> SchemaTypeSync: ... def create( self, - kind: Union[str, type[SchemaTypeSync]], - data: Optional[dict] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, + kind: str | type[SchemaTypeSync], + data: dict | None = None, + branch: str | None = None, + timeout: int | None = None, **kwargs: Any, - ) -> Union[InfrahubNodeSync, SchemaTypeSync]: + ) -> InfrahubNodeSync | SchemaTypeSync: branch = branch or self.default_branch schema = self.schema.get(kind=kind, branch=branch, timeout=timeout) @@ -1447,7 +1445,7 @@ def create( return InfrahubNodeSync(client=self, schema=schema, branch=branch, data=data or kwargs) - def delete(self, kind: Union[str, type[SchemaTypeSync]], id: str, branch: Optional[str] = None) -> None: + def delete(self, kind: str | type[SchemaTypeSync], id: str, branch: str | None = None) -> None: branch = branch or self.default_branch schema = self.schema.get(kind=kind, branch=branch) @@ -1461,12 +1459,12 @@ def clone(self) -> InfrahubClientSync: def execute_graphql( self, query: str, - variables: Optional[dict] = None, - branch_name: Optional[str] = None, - at: Optional[Union[str, Timestamp]] = None, - timeout: Optional[int] = None, + variables: dict | None = None, + branch_name: str | None = None, + at: str | Timestamp | None = None, + timeout: int | None = None, raise_for_error: bool = True, - tracker: Optional[str] = None, + tracker: str | None = None, ) -> dict: """Execute a GraphQL query (or mutation). If retry_on_failure is True, the query will retry until the server becomes reacheable. @@ -1488,7 +1486,7 @@ def execute_graphql( branch_name = branch_name or self.default_branch url = self._graphql_url(branch_name=branch_name, at=at) - payload: dict[str, Union[str, dict]] = {"query": query} + payload: dict[str, str | dict] = {"query": query} if variables: payload["variables"] = variables @@ -1541,14 +1539,14 @@ def execute_graphql( def all( self, kind: type[SchemaTypeSync], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., ) -> list[SchemaTypeSync]: ... @@ -1557,32 +1555,32 @@ def all( def all( self, kind: str, - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., ) -> list[InfrahubNodeSync]: ... def all( self, - kind: Union[str, type[SchemaTypeSync]], - at: Optional[Timestamp] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, + kind: str | type[SchemaTypeSync], + at: Timestamp | None = None, + branch: str | None = None, + timeout: int | None = None, populate_store: bool = False, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, fragment: bool = False, prefetch_relationships: bool = False, - ) -> Union[list[InfrahubNodeSync], list[SchemaTypeSync]]: + ) -> list[InfrahubNodeSync] | list[SchemaTypeSync]: """Retrieve all nodes of a given kind Args: @@ -1621,7 +1619,7 @@ def _process_nodes_and_relationships( schema_kind: str, branch: str, prefetch_relationships: bool, - timeout: Optional[int] = None, + timeout: int | None = None, ) -> ProcessRelationsNodeSync: """Processes InfrahubNodeSync and their Relationships from the GraphQL query response. @@ -1654,14 +1652,14 @@ def _process_nodes_and_relationships( def filters( self, kind: type[SchemaTypeSync], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., partial_match: bool = ..., @@ -1672,14 +1670,14 @@ def filters( def filters( self, kind: str, - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., populate_store: bool = ..., - offset: Optional[int] = ..., - limit: Optional[int] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + offset: int | None = ..., + limit: int | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., fragment: bool = ..., prefetch_relationships: bool = ..., partial_match: bool = ..., @@ -1688,20 +1686,20 @@ def filters( def filters( self, - kind: Union[str, type[SchemaTypeSync]], - at: Optional[Timestamp] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, + kind: str | type[SchemaTypeSync], + at: Timestamp | None = None, + branch: str | None = None, + timeout: int | None = None, populate_store: bool = False, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, fragment: bool = False, prefetch_relationships: bool = False, partial_match: bool = False, **kwargs: Any, - ) -> Union[list[InfrahubNodeSync], list[SchemaTypeSync]]: + ) -> list[InfrahubNodeSync] | list[SchemaTypeSync]: """Retrieve nodes of a given kind based on provided filters. Args: @@ -1791,31 +1789,31 @@ def get( self, kind: type[SchemaTypeSync], raise_when_missing: Literal[False], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., **kwargs: Any, - ) -> Optional[SchemaTypeSync]: ... + ) -> SchemaTypeSync | None: ... @overload def get( self, kind: type[SchemaTypeSync], raise_when_missing: Literal[True], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -1827,13 +1825,13 @@ def get( self, kind: type[SchemaTypeSync], raise_when_missing: bool = ..., - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -1845,31 +1843,31 @@ def get( self, kind: str, raise_when_missing: Literal[False], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., **kwargs: Any, - ) -> Optional[InfrahubNodeSync]: ... + ) -> InfrahubNodeSync | None: ... @overload def get( self, kind: str, raise_when_missing: Literal[True], - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -1881,13 +1879,13 @@ def get( self, kind: str, raise_when_missing: bool = ..., - at: Optional[Timestamp] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - id: Optional[str] = ..., - hfid: Optional[list[str]] = ..., - include: Optional[list[str]] = ..., - exclude: Optional[list[str]] = ..., + at: Timestamp | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + id: str | None = ..., + hfid: list[str] | None = ..., + include: list[str] | None = ..., + exclude: list[str] | None = ..., populate_store: bool = ..., fragment: bool = ..., prefetch_relationships: bool = ..., @@ -1896,20 +1894,20 @@ def get( def get( self, - kind: Union[str, type[SchemaTypeSync]], + kind: str | type[SchemaTypeSync], raise_when_missing: bool = True, - at: Optional[Timestamp] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, - id: Optional[str] = None, - hfid: Optional[list[str]] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + at: Timestamp | None = None, + branch: str | None = None, + timeout: int | None = None, + id: str | None = None, + hfid: list[str] | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, populate_store: bool = False, fragment: bool = False, prefetch_relationships: bool = False, **kwargs: Any, - ) -> Union[InfrahubNodeSync, SchemaTypeSync, None]: + ) -> InfrahubNodeSync | SchemaTypeSync | None: branch = branch or self.default_branch schema = self.schema.get(kind=kind, branch=branch) @@ -1963,7 +1961,7 @@ def create_batch(self, return_exceptions: bool = False) -> InfrahubBatchSync: ) def get_list_repositories( - self, branches: Optional[dict[str, BranchData]] = None, kind: str = "CoreGenericRepository" + self, branches: dict[str, BranchData] | None = None, kind: str = "CoreGenericRepository" ) -> dict[str, RepositoryData]: raise NotImplementedError( "This method is deprecated in the async client and won't be implemented in the sync client." @@ -1972,14 +1970,14 @@ def get_list_repositories( def query_gql_query( self, name: str, - variables: Optional[dict] = None, + variables: dict | None = None, update_group: bool = False, - subscribers: Optional[list[str]] = None, - params: Optional[dict] = None, - branch_name: Optional[str] = None, - at: Optional[str] = None, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + subscribers: list[str] | None = None, + params: dict | None = None, + branch_name: str | None = None, + at: str | None = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, ) -> dict: url = f"{self.address}/api/query/{name}" @@ -2033,8 +2031,8 @@ def query_gql_query( def get_diff_summary( self, branch: str, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, ) -> list[NodeDiff]: query = get_diff_summary_query() @@ -2063,13 +2061,13 @@ def allocate_next_ip_address( self, resource_pool: CoreNodeSync, kind: type[SchemaTypeSync], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> SchemaTypeSync: ... @@ -2078,28 +2076,28 @@ def allocate_next_ip_address( self, resource_pool: CoreNodeSync, kind: type[SchemaTypeSync], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[SchemaTypeSync]: ... + ) -> SchemaTypeSync | None: ... @overload def allocate_next_ip_address( self, resource_pool: CoreNodeSync, kind: type[SchemaTypeSync], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., ) -> SchemaTypeSync: ... @@ -2108,13 +2106,13 @@ def allocate_next_ip_address( self, resource_pool: CoreNodeSync, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> CoreNodeSync: ... @@ -2123,44 +2121,44 @@ def allocate_next_ip_address( self, resource_pool: CoreNodeSync, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[CoreNodeSync]: ... + ) -> CoreNodeSync | None: ... @overload def allocate_next_ip_address( self, resource_pool: CoreNodeSync, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - address_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + address_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., - ) -> Optional[CoreNodeSync]: ... + ) -> CoreNodeSync | None: ... def allocate_next_ip_address( self, resource_pool: CoreNodeSync, - kind: Optional[type[SchemaTypeSync]] = None, # pylint: disable=unused-argument - identifier: Optional[str] = None, - prefix_length: Optional[int] = None, - address_type: Optional[str] = None, - data: Optional[dict[str, Any]] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + kind: type[SchemaTypeSync] | None = None, # pylint: disable=unused-argument + identifier: str | None = None, + prefix_length: int | None = None, + address_type: str | None = None, + data: dict[str, Any] | None = None, + branch: str | None = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, - ) -> Optional[Union[CoreNodeSync, SchemaTypeSync]]: + ) -> CoreNodeSync | SchemaTypeSync | None: """Allocate a new IP address by using the provided resource pool. Args: @@ -2203,14 +2201,14 @@ def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, kind: type[SchemaTypeSync], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> SchemaTypeSync: ... @@ -2219,30 +2217,30 @@ def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, kind: type[SchemaTypeSync], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[SchemaTypeSync]: ... + ) -> SchemaTypeSync | None: ... @overload def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, kind: type[SchemaTypeSync], - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., ) -> SchemaTypeSync: ... @@ -2251,14 +2249,14 @@ def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[True] = True, ) -> CoreNodeSync: ... @@ -2267,47 +2265,47 @@ def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: Literal[False] = False, - ) -> Optional[CoreNodeSync]: ... + ) -> CoreNodeSync | None: ... @overload def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, kind: Literal[None] = ..., - identifier: Optional[str] = ..., - prefix_length: Optional[int] = ..., - member_type: Optional[str] = ..., - prefix_type: Optional[str] = ..., - data: Optional[dict[str, Any]] = ..., - branch: Optional[str] = ..., - timeout: Optional[int] = ..., - tracker: Optional[str] = ..., + identifier: str | None = ..., + prefix_length: int | None = ..., + member_type: str | None = ..., + prefix_type: str | None = ..., + data: dict[str, Any] | None = ..., + branch: str | None = ..., + timeout: int | None = ..., + tracker: str | None = ..., raise_for_error: bool = ..., - ) -> Optional[CoreNodeSync]: ... + ) -> CoreNodeSync | None: ... def allocate_next_ip_prefix( self, resource_pool: CoreNodeSync, - kind: Optional[type[SchemaTypeSync]] = None, # pylint: disable=unused-argument - identifier: Optional[str] = None, - prefix_length: Optional[int] = None, - member_type: Optional[str] = None, - prefix_type: Optional[str] = None, - data: Optional[dict[str, Any]] = None, - branch: Optional[str] = None, - timeout: Optional[int] = None, - tracker: Optional[str] = None, + kind: type[SchemaTypeSync] | None = None, # pylint: disable=unused-argument + identifier: str | None = None, + prefix_length: int | None = None, + member_type: str | None = None, + prefix_type: str | None = None, + data: dict[str, Any] | None = None, + branch: str | None = None, + timeout: int | None = None, + tracker: str | None = None, raise_for_error: bool = True, - ) -> Optional[Union[CoreNodeSync, SchemaTypeSync]]: + ) -> CoreNodeSync | SchemaTypeSync | None: """Allocate a new IP prefix by using the provided resource pool. Args: @@ -2355,7 +2353,7 @@ def repository_update_commit( ) @handle_relogin_sync - def _get(self, url: str, headers: Optional[dict] = None, timeout: Optional[int] = None) -> httpx.Response: + def _get(self, url: str, headers: dict | None = None, timeout: int | None = None) -> httpx.Response: """Execute a HTTP GET with HTTPX. Raises: @@ -2371,9 +2369,7 @@ def _get(self, url: str, headers: Optional[dict] = None, timeout: Optional[int] return self._request(url=url, method=HTTPMethod.GET, headers=headers, timeout=timeout or self.default_timeout) @handle_relogin_sync - def _post( - self, url: str, payload: dict, headers: Optional[dict] = None, timeout: Optional[int] = None - ) -> httpx.Response: + def _post(self, url: str, payload: dict, headers: dict | None = None, timeout: int | None = None) -> httpx.Response: """Execute a HTTP POST with HTTPX. Raises: @@ -2391,20 +2387,20 @@ def _post( ) def _request( - self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: Optional[dict] = None + self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: dict | None = None ) -> httpx.Response: response = self._request_method(url=url, method=method, headers=headers, timeout=timeout, payload=payload) self._record(response) return response def _default_request_method( - self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: Optional[dict] = None + self, url: str, method: HTTPMethod, headers: dict[str, Any], timeout: int, payload: dict | None = None ) -> httpx.Response: params: dict[str, Any] = {} if payload: params["json"] = payload - proxy_config: dict[str, Union[str, dict[str, httpx.HTTPTransport]]] = {} + proxy_config: dict[str, str | dict[str, httpx.HTTPTransport]] = {} if self.config.proxy: proxy_config["proxy"] = self.config.proxy elif self.config.proxy_mounts.is_set: @@ -2489,9 +2485,9 @@ def __enter__(self) -> Self: def __exit__( self, - exc_type: Optional[type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, ) -> None: if exc_type is None and self.mode == InfrahubClientMode.TRACKING: self.group_context.update_group() diff --git a/infrahub_sdk/code_generator.py b/infrahub_sdk/code_generator.py index dc0c2ac9..6dba2433 100644 --- a/infrahub_sdk/code_generator.py +++ b/infrahub_sdk/code_generator.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from collections.abc import Mapping -from typing import Any, Optional, Union +from typing import Any import jinja2 @@ -43,8 +45,8 @@ class CodeGenerator: def __init__(self, schema: dict[str, MainSchemaTypesAll]): - self.generics: dict[str, Union[GenericSchemaAPI, GenericSchema]] = {} - self.nodes: dict[str, Union[NodeSchemaAPI, NodeSchema]] = {} + self.generics: dict[str, GenericSchemaAPI | GenericSchema] = {} + self.nodes: dict[str, NodeSchemaAPI | NodeSchema] = {} self.profiles: dict[str, ProfileSchemaAPI] = {} for name, schema_type in schema.items(): @@ -118,7 +120,7 @@ def _jinja2_filter_render_relationship(value: RelationshipSchemaAPI, sync: bool @staticmethod def _sort_and_filter_models( - models: Mapping[str, MainSchemaTypesAll], filters: Optional[list[str]] = None + models: Mapping[str, MainSchemaTypesAll], filters: list[str] | None = None ) -> list[MainSchemaTypesAll]: if filters is None: filters = ["CoreNode"] diff --git a/infrahub_sdk/config.py b/infrahub_sdk/config.py index 57c852b6..06144087 100644 --- a/infrahub_sdk/config.py +++ b/infrahub_sdk/config.py @@ -1,4 +1,6 @@ -from typing import Any, Optional +from __future__ import annotations + +from typing import Any from pydantic import Field, field_validator, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict @@ -13,13 +15,13 @@ class ProxyMountsConfig(BaseSettings): model_config = SettingsConfigDict(populate_by_name=True) - http: Optional[str] = Field( + http: str | None = Field( default=None, description="Proxy for HTTP requests", alias="http://", validation_alias="INFRAHUB_PROXY_MOUNTS_HTTP", ) - https: Optional[str] = Field( + https: str | None = Field( default=None, description="Proxy for HTTPS requests", alias="https://", @@ -34,12 +36,12 @@ def is_set(self) -> bool: class ConfigBase(BaseSettings): model_config = SettingsConfigDict(env_prefix="INFRAHUB_", validate_assignment=True) address: str = Field(default="http://localhost:8000", description="The URL to use when connecting to Infrahub.") - api_token: Optional[str] = Field(default=None, description="API token for authentication against Infrahub.") + api_token: str | None = Field(default=None, description="API token for authentication against Infrahub.") echo_graphql_queries: bool = Field( default=False, description="If set the GraphQL query and variables will be echoed to the screen" ) - username: Optional[str] = Field(default=None, description="Username for accessing Infrahub", min_length=1) - password: Optional[str] = Field(default=None, description="Password for accessing Infrahub", min_length=1) + username: str | None = Field(default=None, description="Username for accessing Infrahub", min_length=1) + password: str | None = Field(default=None, description="Password for accessing Infrahub", min_length=1) default_branch: str = Field( default="main", description="Default branch to target if not specified for each request." ) @@ -47,7 +49,7 @@ class ConfigBase(BaseSettings): default=False, description="Indicates if the default Infrahub branch to target should come from the active branch in the local Git repository.", ) - identifier: Optional[str] = Field(default=None, description="Tracker identifier") + identifier: str | None = Field(default=None, description="Tracker identifier") insert_tracker: bool = Field(default=False, description="Insert a tracker on queries to the server") max_concurrent_execution: int = Field(default=5, description="Max concurrent execution in batch mode") mode: InfrahubClientMode = Field(default=InfrahubClientMode.DEFAULT, description="Default mode for the client") @@ -61,7 +63,7 @@ class ConfigBase(BaseSettings): transport: RequesterTransport = Field( default=RequesterTransport.HTTPX, description="Set an alternate transport using a predefined option" ) - proxy: Optional[str] = Field(default=None, description="Proxy address") + proxy: str | None = Field(default=None, description="Proxy address") proxy_mounts: ProxyMountsConfig = Field(default=ProxyMountsConfig(), description="Proxy mounts configuration") update_group_context: bool = Field(default=False, description="Update GraphQL query groups") tls_insecure: bool = Field( @@ -71,7 +73,7 @@ class ConfigBase(BaseSettings): Enabling this option will disable: CA verification, expiry date verification, hostname verification). Can be useful to test with self-signed certificates.""", ) - tls_ca_file: Optional[str] = Field(default=None, description="File path to CA cert or bundle in PEM format") + tls_ca_file: str | None = Field(default=None, description="File path to CA cert or bundle in PEM format") @model_validator(mode="before") @classmethod @@ -117,7 +119,7 @@ def validate_proxy_config(self) -> Self: @property def default_infrahub_branch(self) -> str: - branch: Optional[str] = None + branch: str | None = None if not self.default_branch_from_git: branch = self.default_branch @@ -133,9 +135,9 @@ class Config(ConfigBase): custom_recorder: Recorder = Field( default_factory=NoRecorder.default, description="Provides a way to record responses from the Infrahub API" ) - requester: Optional[AsyncRequester] = None - sync_requester: Optional[SyncRequester] = None - log: Optional[Any] = None + requester: AsyncRequester | None = None + sync_requester: SyncRequester | None = None + log: Any | None = None @property def logger(self) -> InfrahubLoggers: diff --git a/infrahub_sdk/ctl/check.py b/infrahub_sdk/ctl/check.py index aa964807..a194fc1c 100644 --- a/infrahub_sdk/ctl/check.py +++ b/infrahub_sdk/ctl/check.py @@ -1,23 +1,27 @@ +from __future__ import annotations + import logging import sys from asyncio import run as aiorun from dataclasses import dataclass from pathlib import Path -from typing import Optional, Type +from typing import TYPE_CHECKING import typer from rich.console import Console from rich.logging import RichHandler -from .. import InfrahubClient -from ..checks import InfrahubCheck from ..ctl import config from ..ctl.client import initialize_client from ..ctl.exceptions import QueryNotFoundError from ..ctl.repository import get_repository_config from ..ctl.utils import catch_exception, execute_graphql_query from ..exceptions import ModuleImportError -from ..schema.repository import InfrahubCheckDefinitionConfig, InfrahubRepositoryConfig + +if TYPE_CHECKING: + from .. import InfrahubClient + from ..checks import InfrahubCheck + from ..schema.repository import InfrahubCheckDefinitionConfig, InfrahubRepositoryConfig app = typer.Typer() console = Console() @@ -26,7 +30,7 @@ @dataclass class CheckModule: name: str - check_class: Type[InfrahubCheck] + check_class: type[InfrahubCheck] definition: InfrahubCheckDefinitionConfig @@ -46,8 +50,8 @@ def run( format_json: bool, list_available: bool, variables: dict[str, str], - name: Optional[str] = None, - branch: Optional[str] = None, + name: str | None = None, + branch: str | None = None, ) -> None: """Locate and execute all checks under the defined path.""" @@ -84,8 +88,8 @@ async def run_check( format_json: bool, path: str, repository_config: InfrahubRepositoryConfig, - branch: Optional[str] = None, - params: Optional[dict] = None, + branch: str | None = None, + params: dict | None = None, ) -> bool: module_name = check_module.name output = "stdout" if format_json else None @@ -131,7 +135,7 @@ async def run_targeted_check( path: str, repository_config: InfrahubRepositoryConfig, variables: dict[str, str], - branch: Optional[str] = None, + branch: str | None = None, ) -> bool: filters = {} param_value = list(check_module.definition.parameters.values()) @@ -183,7 +187,7 @@ async def run_checks( path: str, variables: dict[str, str], repository_config: InfrahubRepositoryConfig, - branch: Optional[str] = None, + branch: str | None = None, ) -> None: log = logging.getLogger("infrahub") diff --git a/infrahub_sdk/ctl/cli_commands.py b/infrahub_sdk/ctl/cli_commands.py index 945a24f6..c0eecf79 100644 --- a/infrahub_sdk/ctl/cli_commands.py +++ b/infrahub_sdk/ctl/cli_commands.py @@ -1,10 +1,12 @@ +from __future__ import annotations + import asyncio import functools import importlib import logging import sys from pathlib import Path -from typing import Any, Callable, Optional +from typing import TYPE_CHECKING, Any, Callable import jinja2 import typer @@ -39,13 +41,15 @@ from ..exceptions import GraphQLError, ModuleImportError from ..jinja2 import identify_faulty_jinja_code from ..schema import MainSchemaTypesAll, SchemaRoot -from ..schema.repository import InfrahubRepositoryConfig from ..utils import get_branch, write_to_file from ..yaml import SchemaFile from .exporter import dump from .importer import load from .parameters import CONFIG_PARAM +if TYPE_CHECKING: + from ..schema.repository import InfrahubRepositoryConfig + app = AsyncTyper(pretty_exceptions_show_locals=False) app.add_typer(branch_app, name="branch") @@ -65,13 +69,13 @@ @catch_exception(console=console) def check( check_name: str = typer.Argument(default="", help="Name of the Python check"), - branch: Optional[str] = None, + branch: str | None = None, path: str = typer.Option(".", help="Root directory"), debug: bool = False, format_json: bool = False, _: str = CONFIG_PARAM, list_available: bool = typer.Option(False, "--list", help="Show available Python checks"), - variables: Optional[list[str]] = typer.Argument( + variables: list[str] | None = typer.Argument( None, help="Variables to pass along with the query. Format key=value key=value." ), ) -> None: @@ -93,12 +97,12 @@ def check( @catch_exception(console=console) async def generator( generator_name: str = typer.Argument(default="", help="Name of the Generator"), - branch: Optional[str] = None, + branch: str | None = None, path: str = typer.Option(".", help="Root directory"), debug: bool = False, _: str = CONFIG_PARAM, list_available: bool = typer.Option(False, "--list", help="Show available Generators"), - variables: Optional[list[str]] = typer.Argument( + variables: list[str] | None = typer.Argument( None, help="Variables to pass along with the query. Format key=value key=value." ), ) -> None: @@ -127,7 +131,7 @@ async def run( envvar="INFRAHUBCTL_CONCURRENT_EXECUTION", ), timeout: int = typer.Option(60, help="Timeout in sec", envvar="INFRAHUBCTL_TIMEOUT"), - variables: Optional[list[str]] = typer.Argument( + variables: list[str] | None = typer.Argument( None, help="Variables to pass along with the query. Format key=value key=value." ), ) -> None: @@ -250,7 +254,7 @@ def _run_transform( @catch_exception(console=console) def render( transform_name: str = typer.Argument(default="", help="Name of the Python transformation", show_default=False), - variables: Optional[list[str]] = typer.Argument( + variables: list[str] | None = typer.Argument( None, help="Variables to pass along with the query. Format key=value key=value." ), branch: str = typer.Option(None, help="Branch on which to render the transform."), @@ -300,7 +304,7 @@ def render( @catch_exception(console=console) def transform( transform_name: str = typer.Argument(default="", help="Name of the Python transformation", show_default=False), - variables: Optional[list[str]] = typer.Argument( + variables: list[str] | None = typer.Argument( None, help="Variables to pass along with the query. Format key=value key=value." ), branch: str = typer.Option(None, help="Branch on which to run the transformation"), diff --git a/infrahub_sdk/ctl/client.py b/infrahub_sdk/ctl/client.py index 1285fb33..3932b8b1 100644 --- a/infrahub_sdk/ctl/client.py +++ b/infrahub_sdk/ctl/client.py @@ -1,4 +1,6 @@ -from typing import Any, Optional +from __future__ import annotations + +from typing import Any from .. import InfrahubClient, InfrahubClientSync from ..config import Config @@ -6,11 +8,11 @@ def initialize_client( - branch: Optional[str] = None, - identifier: Optional[str] = None, - timeout: Optional[int] = None, - max_concurrent_execution: Optional[int] = None, - retry_on_failure: Optional[bool] = None, + branch: str | None = None, + identifier: str | None = None, + timeout: int | None = None, + max_concurrent_execution: int | None = None, + retry_on_failure: bool | None = None, ) -> InfrahubClient: return InfrahubClient( config=_define_config( @@ -24,11 +26,11 @@ def initialize_client( def initialize_client_sync( - branch: Optional[str] = None, - identifier: Optional[str] = None, - timeout: Optional[int] = None, - max_concurrent_execution: Optional[int] = None, - retry_on_failure: Optional[bool] = None, + branch: str | None = None, + identifier: str | None = None, + timeout: int | None = None, + max_concurrent_execution: int | None = None, + retry_on_failure: bool | None = None, ) -> InfrahubClientSync: return InfrahubClientSync( config=_define_config( @@ -42,11 +44,11 @@ def initialize_client_sync( def _define_config( - branch: Optional[str] = None, - identifier: Optional[str] = None, - timeout: Optional[int] = None, - max_concurrent_execution: Optional[int] = None, - retry_on_failure: Optional[bool] = None, + branch: str | None = None, + identifier: str | None = None, + timeout: int | None = None, + max_concurrent_execution: int | None = None, + retry_on_failure: bool | None = None, ) -> Config: client_config: dict[str, Any] = { "address": config.SETTINGS.active.server_address, diff --git a/infrahub_sdk/ctl/config.py b/infrahub_sdk/ctl/config.py index cfeb2fb7..9d3b6488 100644 --- a/infrahub_sdk/ctl/config.py +++ b/infrahub_sdk/ctl/config.py @@ -1,7 +1,8 @@ """Config Class.""" +from __future__ import annotations + from pathlib import Path -from typing import Optional, Union import toml import typer @@ -18,7 +19,7 @@ class Settings(BaseSettings): model_config = SettingsConfigDict(env_prefix="INFRAHUB_", populate_by_name=True, extra="allow") server_address: str = Field(default="http://localhost:8000", validation_alias="infrahub_address") - api_token: Optional[str] = Field(default=None) + api_token: str | None = Field(default=None) default_branch: str = Field(default="main") @field_validator("server_address") @@ -29,7 +30,7 @@ def cleanup_server_address(cls, v: str) -> str: class ConfiguredSettings: def __init__(self) -> None: - self._settings: Optional[Settings] = None + self._settings: Settings | None = None @property def active(self) -> Settings: @@ -39,7 +40,7 @@ def active(self) -> Settings: print("Configuration not properly loaded") raise typer.Abort() - def load(self, config_file: Union[str, Path] = "infrahubctl.toml", config_data: Optional[dict] = None) -> None: + def load(self, config_file: str | Path = "infrahubctl.toml", config_data: dict | None = None) -> None: """Load configuration. Configuration is loaded from a config file in toml format that contains the settings, @@ -65,9 +66,7 @@ def load(self, config_file: Union[str, Path] = "infrahubctl.toml", config_data: self._settings = Settings() - def load_and_exit( - self, config_file: Union[str, Path] = "infrahubctl.toml", config_data: Optional[dict] = None - ) -> None: + def load_and_exit(self, config_file: str | Path = "infrahubctl.toml", config_data: dict | None = None) -> None: """Calls load, but wraps it in a try except block. This is done to handle a ValidationErorr which is raised when settings are specified but invalid. diff --git a/infrahub_sdk/ctl/exporter.py b/infrahub_sdk/ctl/exporter.py index c94da8c9..8b5a6bc3 100644 --- a/infrahub_sdk/ctl/exporter.py +++ b/infrahub_sdk/ctl/exporter.py @@ -1,7 +1,6 @@ from asyncio import run as aiorun from datetime import datetime, timezone from pathlib import Path -from typing import List import typer from rich.console import Console @@ -19,7 +18,7 @@ def directory_name_with_timestamp() -> str: def dump( - namespace: List[str] = typer.Option([], help="Namespace(s) to export"), + namespace: list[str] = typer.Option([], help="Namespace(s) to export"), directory: Path = typer.Option(directory_name_with_timestamp, help="Directory path to store export"), quiet: bool = typer.Option(False, help="No console output"), _: str = CONFIG_PARAM, @@ -30,7 +29,7 @@ def dump( envvar="INFRAHUBCTL_CONCURRENT_EXECUTION", ), timeout: int = typer.Option(60, help="Timeout in sec", envvar="INFRAHUBCTL_TIMEOUT"), - exclude: List[str] = typer.Option( + exclude: list[str] = typer.Option( ["CoreAccount"], help="Prevent node kind(s) from being exported, CoreAccount is excluded by default", ), diff --git a/infrahub_sdk/ctl/generator.py b/infrahub_sdk/ctl/generator.py index 5f737f67..ea895ef0 100644 --- a/infrahub_sdk/ctl/generator.py +++ b/infrahub_sdk/ctl/generator.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from pathlib import Path -from typing import Optional +from typing import TYPE_CHECKING import typer from rich.console import Console @@ -10,7 +12,9 @@ from ..ctl.utils import execute_graphql_query, parse_cli_vars from ..exceptions import ModuleImportError from ..node import InfrahubNode -from ..schema.repository import InfrahubRepositoryConfig + +if TYPE_CHECKING: + from ..schema.repository import InfrahubRepositoryConfig async def run( @@ -18,8 +22,8 @@ async def run( path: str, debug: bool, list_available: bool, - branch: Optional[str] = None, - variables: Optional[list[str]] = None, + branch: str | None = None, + variables: list[str] | None = None, ) -> None: # pylint: disable=unused-argument repository_config = get_repository_config(Path(config.INFRAHUB_REPO_CONFIG_FILE)) diff --git a/infrahub_sdk/ctl/repository.py b/infrahub_sdk/ctl/repository.py index 08fcd571..bd16e57b 100644 --- a/infrahub_sdk/ctl/repository.py +++ b/infrahub_sdk/ctl/repository.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from pathlib import Path -from typing import Optional import typer import yaml @@ -67,7 +68,7 @@ async def add( name: str, location: str, description: str = "", - username: Optional[str] = None, + username: str | None = None, password: str = "", commit: str = "", read_only: bool = False, diff --git a/infrahub_sdk/ctl/schema.py b/infrahub_sdk/ctl/schema.py index 3e5d8ce0..3c9557c5 100644 --- a/infrahub_sdk/ctl/schema.py +++ b/infrahub_sdk/ctl/schema.py @@ -1,14 +1,15 @@ +from __future__ import annotations + import asyncio import time from pathlib import Path -from typing import Any, Optional +from typing import TYPE_CHECKING, Any import typer import yaml from pydantic import ValidationError from rich.console import Console -from .. import InfrahubClient from ..async_typer import AsyncTyper from ..ctl.client import initialize_client from ..ctl.utils import catch_exception, init_logging @@ -17,6 +18,9 @@ from .parameters import CONFIG_PARAM from .utils import load_yamlfile_from_disk_and_exit +if TYPE_CHECKING: + from .. import InfrahubClient + app = AsyncTyper() console = Console() @@ -93,7 +97,7 @@ def valid_error_path(loc_path: list[Any]) -> bool: return len(loc_path) >= 6 and loc_path[0] == "body" and loc_path[1] == "schemas" -def get_node(schemas_data: list[dict], schema_index: int, node_index: int) -> Optional[dict]: +def get_node(schemas_data: list[dict], schema_index: int, node_index: int) -> dict | None: if schema_index < len(schemas_data) and node_index < len(schemas_data[schema_index].content["nodes"]): return schemas_data[schema_index].content["nodes"][node_index] return None diff --git a/infrahub_sdk/ctl/utils.py b/infrahub_sdk/ctl/utils.py index 2016283e..38e9ce1c 100644 --- a/infrahub_sdk/ctl/utils.py +++ b/infrahub_sdk/ctl/utils.py @@ -1,10 +1,12 @@ +from __future__ import annotations + import asyncio import logging import traceback from collections.abc import Coroutine from functools import wraps from pathlib import Path -from typing import Any, Callable, NoReturn, Optional, TypeVar, Union +from typing import TYPE_CHECKING, Any, Callable, NoReturn, TypeVar import pendulum import typer @@ -26,10 +28,12 @@ ServerNotReachableError, ServerNotResponsiveError, ) -from ..schema.repository import InfrahubRepositoryConfig from ..yaml import YamlFile from .client import initialize_client_sync +if TYPE_CHECKING: + from ..schema.repository import InfrahubRepositoryConfig + YamlFileVar = TypeVar("YamlFileVar", bound=YamlFile) T = TypeVar("T") @@ -71,13 +75,13 @@ def handle_exception(exc: Exception, console: Console, exit_code: int) -> NoRetu def catch_exception( - console: Optional[Console] = None, exit_code: int = 1 -) -> Callable[[Callable[..., T]], Callable[..., Union[T, Coroutine[Any, Any, T]]]]: + console: Console | None = None, exit_code: int = 1 +) -> Callable[[Callable[..., T]], Callable[..., T | Coroutine[Any, Any, T]]]: """Decorator to handle exception for commands.""" if not console: console = Console() - def decorator(func: Callable[..., T]) -> Callable[..., Union[T, Coroutine[Any, Any, T]]]: + def decorator(func: Callable[..., T]) -> Callable[..., T | Coroutine[Any, Any, T]]: if asyncio.iscoroutinefunction(func): @wraps(func) @@ -105,7 +109,7 @@ def execute_graphql_query( query: str, variables_dict: dict[str, Any], repository_config: InfrahubRepositoryConfig, - branch: Optional[str] = None, + branch: str | None = None, debug: bool = False, ) -> dict: console = Console() @@ -140,14 +144,14 @@ def print_graphql_errors(console: Console, errors: list) -> None: console.print(f"[red]{escape(str(error))}") -def parse_cli_vars(variables: Optional[list[str]]) -> dict[str, str]: +def parse_cli_vars(variables: list[str] | None) -> dict[str, str]: if not variables: return {} return {var.split("=")[0]: var.split("=")[1] for var in variables if "=" in var} -def calculate_time_diff(value: str) -> Optional[str]: +def calculate_time_diff(value: str) -> str | None: """Calculate the time in human format between a timedate in string format and now.""" try: time_value = pendulum.parse(value) @@ -161,7 +165,7 @@ def calculate_time_diff(value: str) -> Optional[str]: return time_value.diff_for_humans(other=pendulum.now(), absolute=True) -def find_graphql_query(name: str, directory: Union[str, Path] = ".") -> str: +def find_graphql_query(name: str, directory: str | Path = ".") -> str: if isinstance(directory, str): directory = Path(directory) diff --git a/infrahub_sdk/ctl/validate.py b/infrahub_sdk/ctl/validate.py index 8b88b115..d93260b2 100644 --- a/infrahub_sdk/ctl/validate.py +++ b/infrahub_sdk/ctl/validate.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import sys from pathlib import Path -from typing import Optional import typer import ujson @@ -56,7 +57,7 @@ async def validate_schema(schema: Path, _: str = CONFIG_PARAM) -> None: @catch_exception(console=console) def validate_graphql( query: str, - variables: Optional[list[str]] = typer.Argument( + variables: list[str] | None = typer.Argument( None, help="Variables to pass along with the query. Format key=value key=value." ), debug: bool = typer.Option(False, help="Display more troubleshooting information."), diff --git a/infrahub_sdk/data.py b/infrahub_sdk/data.py index fc4af907..cc7ecba0 100644 --- a/infrahub_sdk/data.py +++ b/infrahub_sdk/data.py @@ -1,8 +1,8 @@ -from typing import Optional +from __future__ import annotations from pydantic import BaseModel, ConfigDict, Field -from .node import InfrahubNode +from .node import InfrahubNode # noqa: TCH001 class RepositoryBranchInfo(BaseModel): @@ -18,7 +18,7 @@ class RepositoryData(BaseModel): branch_info: dict[str, RepositoryBranchInfo] = Field(default_factory=dict) - def get_staging_branch(self) -> Optional[str]: + def get_staging_branch(self) -> str | None: for branch, info in self.branch_info.items(): # pylint: disable=no-member if info.internal_status == "staging": return branch diff --git a/infrahub_sdk/exceptions.py b/infrahub_sdk/exceptions.py index 9d6e5407..f8eff9cc 100644 --- a/infrahub_sdk/exceptions.py +++ b/infrahub_sdk/exceptions.py @@ -1,17 +1,17 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, Optional +from typing import Any class Error(Exception): - def __init__(self, message: Optional[str] = None): + def __init__(self, message: str | None = None): self.message = message super().__init__(self.message) class JsonDecodeError(Error): - def __init__(self, message: Optional[str] = None, content: Optional[str] = None, url: Optional[str] = None): + def __init__(self, message: str | None = None, content: str | None = None, url: str | None = None): self.message = message self.content = content self.url = url @@ -21,14 +21,14 @@ def __init__(self, message: Optional[str] = None, content: Optional[str] = None, class ServerNotReachableError(Error): - def __init__(self, address: str, message: Optional[str] = None): + def __init__(self, address: str, message: str | None = None): self.address = address self.message = message or f"Unable to connect to '{address}'." super().__init__(self.message) class ServerNotResponsiveError(Error): - def __init__(self, url: str, timeout: Optional[int] = None, message: Optional[str] = None): + def __init__(self, url: str, timeout: int | None = None, message: str | None = None): self.url = url self.timeout = timeout self.message = message or f"Unable to read from '{url}'." @@ -38,7 +38,7 @@ def __init__(self, url: str, timeout: Optional[int] = None, message: Optional[st class GraphQLError(Error): - def __init__(self, errors: list[dict[str, Any]], query: Optional[str] = None, variables: Optional[dict] = None): + def __init__(self, errors: list[dict[str, Any]], query: str | None = None, variables: dict | None = None): self.query = query self.variables = variables self.errors = errors @@ -47,21 +47,21 @@ def __init__(self, errors: list[dict[str, Any]], query: Optional[str] = None, va class BranchNotFoundError(Error): - def __init__(self, identifier: str, message: Optional[str] = None): + def __init__(self, identifier: str, message: str | None = None): self.identifier = identifier self.message = message or f"Unable to find the branch '{identifier}' in the Database." super().__init__(self.message) class SchemaNotFoundError(Error): - def __init__(self, identifier: str, message: Optional[str] = None): + def __init__(self, identifier: str, message: str | None = None): self.identifier = identifier self.message = message or f"Unable to find the schema '{identifier}'." super().__init__(self.message) class ModuleImportError(Error): - def __init__(self, message: Optional[str] = None): + def __init__(self, message: str | None = None): self.message = message or "Unable to import the module" super().__init__(self.message) @@ -72,7 +72,7 @@ def __init__( node_type: str, identifier: Mapping[str, list[str]], message: str = "Unable to find the node in the database.", - branch_name: Optional[str] = None, + branch_name: str | None = None, ): self.node_type = node_type self.identifier = identifier @@ -91,19 +91,19 @@ def __str__(self) -> str: class ResourceNotDefinedError(Error): """Raised when trying to access a resource that hasn't been defined.""" - def __init__(self, message: Optional[str] = None): + def __init__(self, message: str | None = None): self.message = message or "The requested resource was not found" super().__init__(self.message) class InfrahubCheckNotFoundError(Error): - def __init__(self, name: str, message: Optional[str] = None): + def __init__(self, name: str, message: str | None = None): self.message = message or f"The requested InfrahubCheck '{name}' was not found." super().__init__(self.message) class InfrahubTransformNotFoundError(Error): - def __init__(self, name: str, message: Optional[str] = None): + def __init__(self, name: str, message: str | None = None): self.message = message or f"The requested InfrahubTransform '{name}' was not found." super().__init__(self.message) @@ -116,7 +116,7 @@ def __init__(self, identifier: str, message: str): class AuthenticationError(Error): - def __init__(self, message: Optional[str] = None): + def __init__(self, message: str | None = None): self.message = message or "Authentication Error, unable to execute the query." super().__init__(self.message) diff --git a/infrahub_sdk/generator.py b/infrahub_sdk/generator.py index c7665fa6..b1f59986 100644 --- a/infrahub_sdk/generator.py +++ b/infrahub_sdk/generator.py @@ -2,7 +2,7 @@ import os from abc import abstractmethod -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from git.repo import Repo @@ -22,21 +22,21 @@ def __init__( query: str, client: InfrahubClient, infrahub_node: type[InfrahubNode], - branch: Optional[str] = None, + branch: str | None = None, root_directory: str = "", generator_instance: str = "", - params: Optional[dict] = None, + params: dict | None = None, convert_query_response: bool = False, ) -> None: self.query = query self.branch = branch - self.git: Optional[Repo] = None + self.git: Repo | None = None self.params = params or {} self.root_directory = root_directory or os.getcwd() self.generator_instance = generator_instance self._init_client = client.clone() self._init_client.config.default_branch = self._init_client.default_branch = self.branch_name - self._client: Optional[InfrahubClient] = None + self._client: InfrahubClient | None = None self._nodes: list[InfrahubNode] = [] self._related_nodes: list[InfrahubNode] = [] self.infrahub_node = infrahub_node @@ -58,7 +58,7 @@ def related_nodes(self) -> list[InfrahubNode]: return self._related_nodes @property - def subscribers(self) -> Optional[list[str]]: + def subscribers(self) -> list[str] | None: if self.generator_instance: return [self.generator_instance] return None @@ -101,7 +101,7 @@ async def collect_data(self) -> dict: await self.process_nodes(data=unpacked) return data - async def run(self, identifier: str, data: Optional[dict] = None) -> None: + async def run(self, identifier: str, data: dict | None = None) -> None: """Execute the generator after collecting the data from the GraphQL query.""" if not data: diff --git a/infrahub_sdk/graphql.py b/infrahub_sdk/graphql.py index fcda2a49..d706c64f 100644 --- a/infrahub_sdk/graphql.py +++ b/infrahub_sdk/graphql.py @@ -1,11 +1,11 @@ from __future__ import annotations -from typing import Any, Optional, Union +from typing import Any VARIABLE_TYPE_MAPPING = ((str, "String!"), (int, "Int!"), (float, "Float!"), (bool, "Boolean!")) -def convert_to_graphql_as_string(value: Union[str, bool, list]) -> str: +def convert_to_graphql_as_string(value: str | bool | list) -> str: if isinstance(value, str) and value.startswith("$"): return value if isinstance(value, str): @@ -19,7 +19,7 @@ def convert_to_graphql_as_string(value: Union[str, bool, list]) -> str: return str(value) -def render_variables_to_string(data: dict[str, type[Union[str, int, float, bool]]]) -> str: +def render_variables_to_string(data: dict[str, type[str | int | float | bool]]) -> str: """Render a dict into a variable string that will be used in a GraphQL Query. The $ sign will be automatically added to the name of the query. @@ -100,7 +100,7 @@ class BaseGraphQLQuery: query_type: str = "not-defined" indentation: int = 4 - def __init__(self, query: dict, variables: Optional[dict] = None, name: Optional[str] = None): + def __init__(self, query: dict, variables: dict | None = None, name: str | None = None): self.query = query self.variables = variables self.name = name or "" diff --git a/infrahub_sdk/groups.py b/infrahub_sdk/groups.py index f3fa341b..9c39003d 100644 --- a/infrahub_sdk/groups.py +++ b/infrahub_sdk/groups.py @@ -1,11 +1,9 @@ -from typing import List - from infrahub_sdk import InfrahubClient from infrahub_sdk.node import InfrahubNode async def group_add_subscriber( - client: InfrahubClient, group: InfrahubNode, subscribers: List[str], branch: str + client: InfrahubClient, group: InfrahubNode, subscribers: list[str], branch: str ) -> dict: subscribers_str = ["{ id: " + f'"{subscriber}"' + " }" for subscriber in subscribers] query = """ diff --git a/infrahub_sdk/node.py b/infrahub_sdk/node.py index 275cc76a..42d3a0a6 100644 --- a/infrahub_sdk/node.py +++ b/infrahub_sdk/node.py @@ -4,7 +4,7 @@ import re from collections.abc import Iterable from copy import copy -from typing import TYPE_CHECKING, Any, Callable, Optional, Union, get_args +from typing import TYPE_CHECKING, Any, Callable, Union, get_args from .constants import InfrahubClientMode from .exceptions import ( @@ -46,7 +46,7 @@ class Attribute: """Represents an attribute of a Node, including its schema, value, and properties.""" - def __init__(self, name: str, schema: AttributeSchemaAPI, data: Union[Any, dict]): + def __init__(self, name: str, schema: AttributeSchemaAPI, data: Any | dict): """ Args: name (str): The name of the attribute. @@ -65,11 +65,11 @@ def __init__(self, name: str, schema: AttributeSchemaAPI, data: Union[Any, dict] self._read_only = ["updated_at", "is_inherited"] - self.id: Optional[str] = data.get("id", None) + self.id: str | None = data.get("id", None) - self.value: Optional[Any] = data.get("value", None) - self.is_default: Optional[bool] = data.get("is_default", None) - self.is_from_profile: Optional[bool] = data.get("is_from_profile", None) + self.value: Any | None = data.get("value", None) + self.is_default: bool | None = data.get("is_default", None) + self.is_from_profile: bool | None = data.get("is_from_profile", None) if self.value: value_mapper: dict[str, Callable] = { @@ -79,20 +79,20 @@ def __init__(self, name: str, schema: AttributeSchemaAPI, data: Union[Any, dict] mapper = value_mapper.get(schema.kind, lambda value: value) self.value = mapper(data.get("value")) - self.is_inherited: Optional[bool] = data.get("is_inherited", None) - self.updated_at: Optional[str] = data.get("updated_at", None) + self.is_inherited: bool | None = data.get("is_inherited", None) + self.updated_at: str | None = data.get("updated_at", None) - self.is_visible: Optional[bool] = data.get("is_visible", None) - self.is_protected: Optional[bool] = data.get("is_protected", None) + self.is_visible: bool | None = data.get("is_visible", None) + self.is_protected: bool | None = data.get("is_protected", None) - self.source: Optional[NodeProperty] = None - self.owner: Optional[NodeProperty] = None + self.source: NodeProperty | None = None + self.owner: NodeProperty | None = None for prop_name in self._properties_object: if data.get(prop_name): setattr(self, prop_name, NodeProperty(data=data.get(prop_name))) # type: ignore[arg-type] - def _generate_input_data(self) -> Optional[dict]: + def _generate_input_data(self) -> dict | None: data: dict[str, Any] = {} variables: dict[str, Any] = {} @@ -123,7 +123,7 @@ def _generate_input_data(self) -> Optional[dict]: return {"data": data, "variables": variables} - def _generate_query_data(self) -> Optional[dict]: + def _generate_query_data(self) -> dict | None: data: dict[str, Any] = {"value": None, "is_default": None, "is_from_profile": None} for prop_name in self._properties_flag: @@ -143,7 +143,7 @@ def _generate_mutation_query(self) -> dict[str, Any]: class RelatedNodeBase: """Base class for representing a related node in a relationship.""" - def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Union[Any, dict], name: Optional[str] = None): + def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Any | dict, name: str | None = None): """ Args: branch (str): The branch where the related node resides. @@ -161,10 +161,10 @@ def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Union[Any, self._properties = self._properties_flag + self._properties_object self._peer = None - self._id: Optional[str] = None - self._hfid: Optional[list[str]] = None - self._display_label: Optional[str] = None - self._typename: Optional[str] = None + self._id: str | None = None + self._hfid: list[str] | None = None + self._display_label: str | None = None + self._typename: str | None = None if isinstance(data, (InfrahubNode, InfrahubNodeSync)): self._peer = data @@ -187,7 +187,7 @@ def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Union[Any, self._display_label = node_data.get("display_label", None) self._typename = node_data.get("__typename", None) - self.updated_at: Optional[str] = data.get("updated_at", data.get("_relation__updated_at", None)) + self.updated_at: str | None = data.get("updated_at", data.get("_relation__updated_at", None)) # FIXME, we won't need that once we are only supporting paginated results if self._typename and self._typename.startswith("Related"): @@ -203,19 +203,19 @@ def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Union[Any, setattr(self, prop, None) @property - def id(self) -> Optional[str]: + def id(self) -> str | None: if self._peer: return self._peer.id return self._id @property - def hfid(self) -> Optional[list[Any]]: + def hfid(self) -> list[Any] | None: if self._peer: return self._peer.hfid return self._hfid @property - def hfid_str(self) -> Optional[str]: + def hfid_str(self) -> str | None: if self._peer and self.hfid: return self._peer.get_human_friendly_id_as_string(include_kind=True) return None @@ -231,13 +231,13 @@ def initialized(self) -> bool: return bool(self.id) or bool(self.hfid) @property - def display_label(self) -> Optional[str]: + def display_label(self) -> str | None: if self._peer: return self._peer.display_label return self._display_label @property - def typename(self) -> Optional[str]: + def typename(self) -> str | None: if self._peer: return self._peer.typename return self._typename @@ -266,7 +266,7 @@ def _generate_mutation_query(self) -> dict[str, Any]: return {} @classmethod - def _generate_query_data(cls, peer_data: Optional[dict[str, Any]] = None) -> dict: + def _generate_query_data(cls, peer_data: dict[str, Any] | None = None) -> dict: """Generates the basic structure of a GraphQL query for a single relationship. Args: @@ -301,8 +301,8 @@ def __init__( client: InfrahubClient, branch: str, schema: RelationshipSchemaAPI, - data: Union[Any, dict], - name: Optional[str] = None, + data: Any | dict, + name: str | None = None, ): """ Args: @@ -315,7 +315,7 @@ def __init__( self._client = client super().__init__(branch=branch, schema=schema, data=data, name=name) - async def fetch(self, timeout: Optional[int] = None) -> None: + async def fetch(self, timeout: int | None = None) -> None: if not self.id or not self.typename: raise Error("Unable to fetch the peer, id and/or typename are not defined") @@ -348,8 +348,8 @@ def __init__( client: InfrahubClientSync, branch: str, schema: RelationshipSchemaAPI, - data: Union[Any, dict], - name: Optional[str] = None, + data: Any | dict, + name: str | None = None, ): """ Args: @@ -362,7 +362,7 @@ def __init__( self._client = client super().__init__(branch=branch, schema=schema, data=data, name=name) - def fetch(self, timeout: Optional[int] = None) -> None: + def fetch(self, timeout: int | None = None) -> None: if not self.id or not self.typename: raise Error("Unable to fetch the peer, id and/or typename are not defined") @@ -407,7 +407,7 @@ def __init__(self, name: str, branch: str, schema: RelationshipSchemaAPI): self._properties_object = PROPERTIES_OBJECT self._properties = self._properties_flag + self._properties_object - self.peers: list[Union[RelatedNode, RelatedNodeSync]] = [] + self.peers: list[RelatedNode | RelatedNodeSync] = [] @property def peer_ids(self) -> list[str]: @@ -433,7 +433,7 @@ def _generate_mutation_query(self) -> dict[str, Any]: return {} @classmethod - def _generate_query_data(cls, peer_data: Optional[dict[str, Any]] = None) -> dict: + def _generate_query_data(cls, peer_data: dict[str, Any] | None = None) -> dict: """Generates the basic structure of a GraphQL query for relationships with multiple nodes. Args: @@ -474,7 +474,7 @@ def __init__( node: InfrahubNode, branch: str, schema: RelationshipSchemaAPI, - data: Union[Any, dict], + data: Any | dict, ): """ Args: @@ -530,7 +530,7 @@ async def fetch(self) -> None: for peer in self.peers: await peer.fetch() # type: ignore[misc] - def add(self, data: Union[str, RelatedNode, dict]) -> None: + def add(self, data: str | RelatedNode | dict) -> None: """Add a new peer to this relationship.""" if not self.initialized: raise UninitializedError("Must call fetch() on RelationshipManager before editing members") @@ -540,12 +540,12 @@ def add(self, data: Union[str, RelatedNode, dict]) -> None: self.peers.append(new_node) self._has_update = True - def extend(self, data: Iterable[Union[str, RelatedNode, dict]]) -> None: + def extend(self, data: Iterable[str | RelatedNode | dict]) -> None: """Add new peers to this relationship.""" for d in data: self.add(d) - def remove(self, data: Union[str, RelatedNode, dict]) -> None: + def remove(self, data: str | RelatedNode | dict) -> None: if not self.initialized: raise UninitializedError("Must call fetch() on RelationshipManager before editing members") node_to_remove = RelatedNode(schema=self.schema, client=self.client, branch=self.branch, data=data) @@ -569,7 +569,7 @@ def __init__( node: InfrahubNodeSync, branch: str, schema: RelationshipSchemaAPI, - data: Union[Any, dict], + data: Any | dict, ): """ Args: @@ -625,7 +625,7 @@ def fetch(self) -> None: for peer in self.peers: peer.fetch() - def add(self, data: Union[str, RelatedNodeSync, dict]) -> None: + def add(self, data: str | RelatedNodeSync | dict) -> None: """Add a new peer to this relationship.""" if not self.initialized: raise UninitializedError("Must call fetch() on RelationshipManager before editing members") @@ -635,12 +635,12 @@ def add(self, data: Union[str, RelatedNodeSync, dict]) -> None: self.peers.append(new_node) self._has_update = True - def extend(self, data: Iterable[Union[str, RelatedNodeSync, dict]]) -> None: + def extend(self, data: Iterable[str | RelatedNodeSync | dict]) -> None: """Add new peers to this relationship.""" for d in data: self.add(d) - def remove(self, data: Union[str, RelatedNodeSync, dict]) -> None: + def remove(self, data: str | RelatedNodeSync | dict) -> None: if not self.initialized: raise UninitializedError("Must call fetch() on RelationshipManager before editing members") node_to_remove = RelatedNodeSync(schema=self.schema, client=self.client, branch=self.branch, data=data) @@ -657,7 +657,7 @@ def remove(self, data: Union[str, RelatedNodeSync, dict]) -> None: class InfrahubNodeBase: """Base class for InfrahubNode and InfrahubNodeSync""" - def __init__(self, schema: MainSchemaTypesAPI, branch: str, data: Optional[dict] = None) -> None: + def __init__(self, schema: MainSchemaTypesAPI, branch: str, data: dict | None = None) -> None: """ Args: schema: The schema of the node. @@ -670,8 +670,8 @@ def __init__(self, schema: MainSchemaTypesAPI, branch: str, data: Optional[dict] self._existing: bool = True self.id = data.get("id", None) if isinstance(data, dict) else None - self.display_label: Optional[str] = data.get("display_label", None) if isinstance(data, dict) else None - self.typename: Optional[str] = data.get("__typename", schema.kind) if isinstance(data, dict) else schema.kind + self.display_label: str | None = data.get("display_label", None) if isinstance(data, dict) else None + self.typename: str | None = data.get("__typename", schema.kind) if isinstance(data, dict) else schema.kind self._attributes = [item.name for item in self._schema.attributes] self._relationships = [item.name for item in self._schema.relationships] @@ -722,7 +722,7 @@ def get_path_value(self, path: str) -> Any: return return_value - def get_human_friendly_id(self) -> Optional[list[str]]: + def get_human_friendly_id(self) -> list[str] | None: if not hasattr(self._schema, "human_friendly_id"): return None @@ -735,7 +735,7 @@ def get_human_friendly_id(self) -> Optional[list[str]]: return None return [str(hfid) for hfid in hfid_components] - def get_human_friendly_id_as_string(self, include_kind: bool = False) -> Optional[str]: + def get_human_friendly_id_as_string(self, include_kind: bool = False) -> str | None: hfid = self.get_human_friendly_id() if not hfid: return None @@ -744,14 +744,14 @@ def get_human_friendly_id_as_string(self, include_kind: bool = False) -> Optiona return "__".join(hfid) @property - def hfid(self) -> Optional[list[str]]: + def hfid(self) -> list[str] | None: return self.get_human_friendly_id() @property - def hfid_str(self) -> Optional[str]: + def hfid_str(self) -> str | None: return self.get_human_friendly_id_as_string(include_kind=True) - def _init_attributes(self, data: Optional[dict] = None) -> None: + def _init_attributes(self, data: dict | None = None) -> None: for attr_name in self._attributes: attr_schema = [attr for attr in self._schema.attributes if attr.name == attr_name][0] attr_data = data.get(attr_name, None) if isinstance(data, dict) else None @@ -761,7 +761,7 @@ def _init_attributes(self, data: Optional[dict] = None) -> None: Attribute(name=attr_name, schema=attr_schema, data=attr_data), ) - def _init_relationships(self, data: Optional[dict] = None) -> None: + def _init_relationships(self, data: dict | None = None) -> None: pass def __repr__(self) -> str: @@ -786,7 +786,7 @@ def is_ip_address(self) -> bool: def is_resource_pool(self) -> bool: return hasattr(self._schema, "inherit_from") and "CoreResourcePool" in self._schema.inherit_from # type: ignore[union-attr] - def get_raw_graphql_data(self) -> Optional[dict]: + def get_raw_graphql_data(self) -> dict | None: return self._data def _generate_input_data(self, exclude_unmodified: bool = False, exclude_hfid: bool = False) -> dict[str, dict]: # noqa: C901 @@ -824,7 +824,7 @@ def _generate_input_data(self, exclude_unmodified: bool = False, exclude_hfid: b if not rel_schema or rel_schema.read_only: continue - rel: Union[RelatedNodeBase, RelationshipManagerBase] = getattr(self, item_name) + rel: RelatedNodeBase | RelationshipManagerBase = getattr(self, item_name) # BLOCKED by https://github.com/opsmill/infrahub/issues/330 # if ( @@ -966,13 +966,13 @@ def _validate_artifact_definition_support(self, message: str) -> None: def generate_query_data_init( self, - filters: Optional[dict[str, Any]] = None, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + filters: dict[str, Any] | None = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, partial_match: bool = False, - ) -> dict[str, Union[Any, dict]]: + ) -> dict[str, Any | dict]: data: dict[str, Any] = { "count": None, "edges": {"node": {"id": None, "hfid": None, "display_label": None, "__typename": None}}, @@ -1036,8 +1036,8 @@ def __init__( self, client: InfrahubClient, schema: MainSchemaTypesAPI, - branch: Optional[str] = None, - data: Optional[dict] = None, + branch: str | None = None, + data: dict | None = None, ) -> None: """ Args: @@ -1060,8 +1060,8 @@ async def from_graphql( client: InfrahubClient, branch: str, data: dict, - schema: Optional[MainSchemaTypesAPI] = None, - timeout: Optional[int] = None, + schema: MainSchemaTypesAPI | None = None, + timeout: int | None = None, ) -> Self: if not schema: node_kind = data.get("__typename", None) or data.get("node", {}).get("__typename", None) @@ -1071,7 +1071,7 @@ async def from_graphql( return cls(client=client, schema=schema, branch=branch, data=cls._strip_alias(data)) - def _init_relationships(self, data: Optional[dict] = None) -> None: + def _init_relationships(self, data: dict | None = None) -> None: for rel_name in self._relationships: rel_schema = [rel for rel in self._schema.relationships if rel.name == rel_name][0] rel_data = data.get(rel_name, None) if isinstance(data, dict) else None @@ -1098,7 +1098,7 @@ def _init_relationships(self, data: Optional[dict] = None) -> None: ), ) - async def generate(self, nodes: Optional[list[str]] = None) -> None: + async def generate(self, nodes: list[str] | None = None) -> None: self._validate_artifact_definition_support(ARTIFACT_DEFINITION_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE) nodes = nodes or [] @@ -1113,14 +1113,14 @@ async def artifact_generate(self, name: str) -> None: await artifact.definition.fetch() # type: ignore[attr-defined] await artifact.definition.peer.generate([artifact.id]) # type: ignore[attr-defined] - async def artifact_fetch(self, name: str) -> Union[str, dict[str, Any]]: + async def artifact_fetch(self, name: str) -> str | dict[str, Any]: self._validate_artifact_support(ARTIFACT_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE) artifact = await self._client.get(kind="CoreArtifact", definition__name__value=name, object__ids=[self.id]) content = await self._client.object_store.get(identifier=artifact.storage_id.value) # type: ignore[attr-defined] return content - async def delete(self, timeout: Optional[int] = None) -> None: + async def delete(self, timeout: int | None = None) -> None: input_data = {"data": {"id": self.id}} mutation_query = {"ok": None} query = Mutation( @@ -1136,7 +1136,7 @@ async def delete(self, timeout: Optional[int] = None) -> None: ) async def save( - self, allow_upsert: bool = False, update_group_context: Optional[bool] = None, timeout: Optional[int] = None + self, allow_upsert: bool = False, update_group_context: bool | None = None, timeout: int | None = None ) -> None: if self._existing is False or allow_upsert is True: await self.create(allow_upsert=allow_upsert, timeout=timeout) @@ -1162,15 +1162,15 @@ async def save( async def generate_query_data( self, - filters: Optional[dict[str, Any]] = None, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + filters: dict[str, Any] | None = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, fragment: bool = False, prefetch_relationships: bool = False, partial_match: bool = False, - ) -> dict[str, Union[Any, dict]]: + ) -> dict[str, Any | dict]: data = self.generate_query_data_init( filters=filters, offset=offset, limit=limit, include=include, exclude=exclude, partial_match=partial_match ) @@ -1211,12 +1211,12 @@ async def generate_query_data( async def generate_query_data_node( self, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + include: list[str] | None = None, + exclude: list[str] | None = None, inherited: bool = True, insert_alias: bool = False, prefetch_relationships: bool = False, - ) -> dict[str, Union[Any, dict]]: + ) -> dict[str, Any | dict]: """Generate the node part of a GraphQL Query with attributes and nodes. Args: @@ -1325,7 +1325,7 @@ def _generate_mutation_query(self) -> dict[str, Any]: return query_result async def _process_mutation_result( - self, mutation_name: str, response: dict[str, Any], timeout: Optional[int] = None + self, mutation_name: str, response: dict[str, Any], timeout: int | None = None ) -> None: object_response: dict[str, Any] = response[mutation_name]["object"] self.id = object_response["id"] @@ -1356,7 +1356,7 @@ async def _process_mutation_result( await related_node.fetch(timeout=timeout) setattr(self, rel_name, related_node) - async def create(self, allow_upsert: bool = False, timeout: Optional[int] = None) -> None: + async def create(self, allow_upsert: bool = False, timeout: int | None = None) -> None: mutation_query = self._generate_mutation_query() if allow_upsert: @@ -1382,7 +1382,7 @@ async def create(self, allow_upsert: bool = False, timeout: Optional[int] = None ) await self._process_mutation_result(mutation_name=mutation_name, response=response, timeout=timeout) - async def update(self, do_full_update: bool = False, timeout: Optional[int] = None) -> None: + async def update(self, do_full_update: bool = False, timeout: int | None = None) -> None: input_data = self._generate_input_data(exclude_unmodified=not do_full_update) mutation_query = self._generate_mutation_query() mutation_name = f"{self._schema.kind}Update" @@ -1403,7 +1403,7 @@ async def update(self, do_full_update: bool = False, timeout: Optional[int] = No await self._process_mutation_result(mutation_name=mutation_name, response=response, timeout=timeout) async def _process_relationships( - self, node_data: dict[str, Any], branch: str, related_nodes: list[InfrahubNode], timeout: Optional[int] = None + self, node_data: dict[str, Any], branch: str, related_nodes: list[InfrahubNode], timeout: int | None = None ) -> None: """Processes the Relationships of a InfrahubNode and add Related Nodes to a list. @@ -1541,8 +1541,8 @@ def __init__( self, client: InfrahubClientSync, schema: MainSchemaTypesAPI, - branch: Optional[str] = None, - data: Optional[dict] = None, + branch: str | None = None, + data: dict | None = None, ) -> None: """ Args: @@ -1565,8 +1565,8 @@ def from_graphql( client: InfrahubClientSync, branch: str, data: dict, - schema: Optional[MainSchemaTypesAPI] = None, - timeout: Optional[int] = None, + schema: MainSchemaTypesAPI | None = None, + timeout: int | None = None, ) -> Self: if not schema: node_kind = data.get("__typename", None) or data.get("node", {}).get("__typename", None) @@ -1576,7 +1576,7 @@ def from_graphql( return cls(client=client, schema=schema, branch=branch, data=cls._strip_alias(data)) - def _init_relationships(self, data: Optional[dict] = None) -> None: + def _init_relationships(self, data: dict | None = None) -> None: for rel_name in self._relationships: rel_schema = [rel for rel in self._schema.relationships if rel.name == rel_name][0] rel_data = data.get(rel_name, None) if isinstance(data, dict) else None @@ -1603,7 +1603,7 @@ def _init_relationships(self, data: Optional[dict] = None) -> None: ), ) - def generate(self, nodes: Optional[list[str]] = None) -> None: + def generate(self, nodes: list[str] | None = None) -> None: self._validate_artifact_definition_support(ARTIFACT_DEFINITION_GENERATE_FEATURE_NOT_SUPPORTED_MESSAGE) nodes = nodes or [] payload = {"nodes": nodes} @@ -1616,13 +1616,13 @@ def artifact_generate(self, name: str) -> None: artifact.definition.fetch() # type: ignore[attr-defined] artifact.definition.peer.generate([artifact.id]) # type: ignore[attr-defined] - def artifact_fetch(self, name: str) -> Union[str, dict[str, Any]]: + def artifact_fetch(self, name: str) -> str | dict[str, Any]: self._validate_artifact_support(ARTIFACT_FETCH_FEATURE_NOT_SUPPORTED_MESSAGE) artifact = self._client.get(kind="CoreArtifact", definition__name__value=name, object__ids=[self.id]) content = self._client.object_store.get(identifier=artifact.storage_id.value) # type: ignore[attr-defined] return content - def delete(self, timeout: Optional[int] = None) -> None: + def delete(self, timeout: int | None = None) -> None: input_data = {"data": {"id": self.id}} mutation_query = {"ok": None} query = Mutation( @@ -1638,7 +1638,7 @@ def delete(self, timeout: Optional[int] = None) -> None: ) def save( - self, allow_upsert: bool = False, update_group_context: Optional[bool] = None, timeout: Optional[int] = None + self, allow_upsert: bool = False, update_group_context: bool | None = None, timeout: int | None = None ) -> None: if self._existing is False or allow_upsert is True: self.create(allow_upsert=allow_upsert, timeout=timeout) @@ -1660,15 +1660,15 @@ def save( def generate_query_data( self, - filters: Optional[dict[str, Any]] = None, - offset: Optional[int] = None, - limit: Optional[int] = None, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + filters: dict[str, Any] | None = None, + offset: int | None = None, + limit: int | None = None, + include: list[str] | None = None, + exclude: list[str] | None = None, fragment: bool = False, prefetch_relationships: bool = False, partial_match: bool = False, - ) -> dict[str, Union[Any, dict]]: + ) -> dict[str, Any | dict]: data = self.generate_query_data_init( filters=filters, offset=offset, limit=limit, include=include, exclude=exclude, partial_match=partial_match ) @@ -1708,12 +1708,12 @@ def generate_query_data( def generate_query_data_node( self, - include: Optional[list[str]] = None, - exclude: Optional[list[str]] = None, + include: list[str] | None = None, + exclude: list[str] | None = None, inherited: bool = True, insert_alias: bool = False, prefetch_relationships: bool = False, - ) -> dict[str, Union[Any, dict]]: + ) -> dict[str, Any | dict]: """Generate the node part of a GraphQL Query with attributes and nodes. Args: @@ -1826,7 +1826,7 @@ def _generate_mutation_query(self) -> dict[str, Any]: return query_result def _process_mutation_result( - self, mutation_name: str, response: dict[str, Any], timeout: Optional[int] = None + self, mutation_name: str, response: dict[str, Any], timeout: int | None = None ) -> None: object_response: dict[str, Any] = response[mutation_name]["object"] self.id = object_response["id"] @@ -1857,7 +1857,7 @@ def _process_mutation_result( related_node.fetch(timeout=timeout) setattr(self, rel_name, related_node) - def create(self, allow_upsert: bool = False, timeout: Optional[int] = None) -> None: + def create(self, allow_upsert: bool = False, timeout: int | None = None) -> None: mutation_query = self._generate_mutation_query() if allow_upsert: @@ -1884,7 +1884,7 @@ def create(self, allow_upsert: bool = False, timeout: Optional[int] = None) -> N ) self._process_mutation_result(mutation_name=mutation_name, response=response, timeout=timeout) - def update(self, do_full_update: bool = False, timeout: Optional[int] = None) -> None: + def update(self, do_full_update: bool = False, timeout: int | None = None) -> None: input_data = self._generate_input_data(exclude_unmodified=not do_full_update) mutation_query = self._generate_mutation_query() mutation_name = f"{self._schema.kind}Update" @@ -1910,7 +1910,7 @@ def _process_relationships( node_data: dict[str, Any], branch: str, related_nodes: list[InfrahubNodeSync], - timeout: Optional[int] = None, + timeout: int | None = None, ) -> None: """Processes the Relationships of a InfrahubNodeSync and add Related Nodes to a list. @@ -2045,7 +2045,7 @@ def get_pool_resources_utilization(self) -> list[dict[str, Any]]: class NodeProperty: """Represents a property of a node, typically used for metadata like display labels.""" - def __init__(self, data: Union[dict, str]): + def __init__(self, data: dict | str): """ Args: data (Union[dict, str]): Data representing the node property. @@ -2061,11 +2061,11 @@ def __init__(self, data: Union[dict, str]): self.display_label = data.get("display_label", None) self.typename = data.get("__typename", None) - def _generate_input_data(self) -> Union[str, None]: + def _generate_input_data(self) -> str | None: return self.id -def generate_relationship_property(node: Union[InfrahubNode, InfrahubNodeSync], name: str) -> property: +def generate_relationship_property(node: InfrahubNode | InfrahubNodeSync, name: str) -> property: """Generates a property that stores values under a private non-public name. Args: diff --git a/infrahub_sdk/object_store.py b/infrahub_sdk/object_store.py index 31034bfe..b62d0d9e 100644 --- a/infrahub_sdk/object_store.py +++ b/infrahub_sdk/object_store.py @@ -1,7 +1,7 @@ from __future__ import annotations import copy -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING import httpx @@ -19,7 +19,7 @@ class ObjectStore(ObjectStoreBase): def __init__(self, client: InfrahubClient): self.client = client - async def get(self, identifier: str, tracker: Optional[str] = None) -> str: + async def get(self, identifier: str, tracker: str | None = None) -> str: url = f"{self.client.address}/api/storage/object/{identifier}" headers = copy.copy(self.client.headers or {}) if self.client.insert_tracker and tracker: @@ -41,7 +41,7 @@ async def get(self, identifier: str, tracker: Optional[str] = None) -> str: return resp.text - async def upload(self, content: str, tracker: Optional[str] = None) -> dict[str, str]: + async def upload(self, content: str, tracker: str | None = None) -> dict[str, str]: url = f"{self.client.address}/api/storage/upload/content" headers = copy.copy(self.client.headers or {}) if self.client.insert_tracker and tracker: @@ -67,7 +67,7 @@ class ObjectStoreSync(ObjectStoreBase): def __init__(self, client: InfrahubClientSync): self.client = client - def get(self, identifier: str, tracker: Optional[str] = None) -> str: + def get(self, identifier: str, tracker: str | None = None) -> str: url = f"{self.client.address}/api/storage/object/{identifier}" headers = copy.copy(self.client.headers or {}) if self.client.insert_tracker and tracker: @@ -89,7 +89,7 @@ def get(self, identifier: str, tracker: Optional[str] = None) -> str: return resp.text - def upload(self, content: str, tracker: Optional[str] = None) -> dict[str, str]: + def upload(self, content: str, tracker: str | None = None) -> dict[str, str]: url = f"{self.client.address}/api/storage/upload/content" headers = copy.copy(self.client.headers or {}) if self.client.insert_tracker and tracker: diff --git a/infrahub_sdk/playback.py b/infrahub_sdk/playback.py index a8775dc7..63503704 100644 --- a/infrahub_sdk/playback.py +++ b/infrahub_sdk/playback.py @@ -1,15 +1,19 @@ +from __future__ import annotations + import json from pathlib import Path -from typing import Any, Optional +from typing import TYPE_CHECKING, Any import httpx import ujson from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict -from .types import HTTPMethod from .utils import generate_request_filename +if TYPE_CHECKING: + from .types import HTTPMethod + class JSONPlayback(BaseSettings): model_config = SettingsConfigDict(env_prefix="INFRAHUB_PLAYBACK_") @@ -21,7 +25,7 @@ async def async_request( method: HTTPMethod, headers: dict[str, Any], timeout: int, - payload: Optional[dict] = None, + payload: dict | None = None, ) -> httpx.Response: return self._read_request(url=url, method=method, headers=headers, payload=payload, timeout=timeout) @@ -31,7 +35,7 @@ def sync_request( method: HTTPMethod, headers: dict[str, Any], timeout: int, - payload: Optional[dict] = None, + payload: dict | None = None, ) -> httpx.Response: return self._read_request(url=url, method=method, headers=headers, payload=payload, timeout=timeout) @@ -41,9 +45,9 @@ def _read_request( method: HTTPMethod, headers: dict[str, Any], timeout: int, # pylint: disable=unused-argument - payload: Optional[dict] = None, + payload: dict | None = None, ) -> httpx.Response: - content: Optional[bytes] = None + content: bytes | None = None if payload: content = str(json.dumps(payload)).encode("UTF-8") request = httpx.Request(method=method.value, url=url, headers=headers, content=content) diff --git a/infrahub_sdk/protocols_base.py b/infrahub_sdk/protocols_base.py index df6a9000..4c227117 100644 --- a/infrahub_sdk/protocols_base.py +++ b/infrahub_sdk/protocols_base.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Optional, Protocol, Union, runtime_checkable +from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable if TYPE_CHECKING: import ipaddress @@ -19,13 +19,13 @@ class RelatedNodeSync(Protocol): ... @runtime_checkable class Attribute(Protocol): name: str - id: Optional[str] - is_default: Optional[bool] - is_from_profile: Optional[bool] - is_inherited: Optional[bool] - updated_at: Optional[str] - is_visible: Optional[bool] - is_protected: Optional[bool] + id: str | None + is_default: bool | None + is_from_profile: bool | None + is_inherited: bool | None + updated_at: str | None + is_visible: bool | None + is_protected: bool | None class String(Attribute): @@ -33,7 +33,7 @@ class String(Attribute): class StringOptional(Attribute): - value: Optional[str] + value: str | None class DateTime(Attribute): @@ -41,7 +41,7 @@ class DateTime(Attribute): class DateTimeOptional(Attribute): - value: Optional[str] + value: str | None class HashedPassword(Attribute): @@ -57,7 +57,7 @@ class URL(Attribute): class URLOptional(Attribute): - value: Optional[str] + value: str | None class MacAddress(Attribute): @@ -65,7 +65,7 @@ class MacAddress(Attribute): class MacAddressOptional(Attribute): - value: Optional[str] + value: str | None class Dropdown(Attribute): @@ -73,7 +73,7 @@ class Dropdown(Attribute): class DropdownOptional(Attribute): - value: Optional[str] + value: str | None class Enum(Attribute): @@ -81,7 +81,7 @@ class Enum(Attribute): class EnumOptional(Attribute): - value: Optional[str] + value: str | None class Integer(Attribute): @@ -89,23 +89,23 @@ class Integer(Attribute): class IntegerOptional(Attribute): - value: Optional[int] + value: int | None class IPHost(Attribute): - value: Union[ipaddress.IPv4Address, ipaddress.IPv6Address] + value: ipaddress.IPv4Address | ipaddress.IPv6Address class IPHostOptional(Attribute): - value: Optional[Union[ipaddress.IPv4Address, ipaddress.IPv6Address]] + value: ipaddress.IPv4Address | ipaddress.IPv6Address | None class IPNetwork(Attribute): - value: Union[ipaddress.IPv4Network, ipaddress.IPv6Network] + value: ipaddress.IPv4Network | ipaddress.IPv6Network class IPNetworkOptional(Attribute): - value: Optional[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]] + value: ipaddress.IPv4Network | ipaddress.IPv6Network | None class Boolean(Attribute): @@ -113,7 +113,7 @@ class Boolean(Attribute): class BooleanOptional(Attribute): - value: Optional[bool] + value: bool | None class ListAttribute(Attribute): @@ -121,7 +121,7 @@ class ListAttribute(Attribute): class ListAttributeOptional(Attribute): - value: Optional[list[Any]] + value: list[Any] | None class JSONAttribute(Attribute): @@ -129,7 +129,7 @@ class JSONAttribute(Attribute): class JSONAttributeOptional(Attribute): - value: Optional[Any] + value: Any | None class AnyAttribute(Attribute): @@ -137,22 +137,22 @@ class AnyAttribute(Attribute): class AnyAttributeOptional(Attribute): - value: Optional[float] + value: float | None @runtime_checkable class CoreNodeBase(Protocol): _schema: MainSchemaTypes id: str - display_label: Optional[str] + display_label: str | None @property - def hfid(self) -> Optional[list[str]]: ... + def hfid(self) -> list[str] | None: ... @property - def hfid_str(self) -> Optional[str]: ... + def hfid_str(self) -> str | None: ... - def get_human_friendly_id_as_string(self, include_kind: bool = False) -> Optional[str]: ... + def get_human_friendly_id_as_string(self, include_kind: bool = False) -> str | None: ... def get_kind(self) -> str: ... @@ -162,14 +162,14 @@ def is_ip_address(self) -> bool: ... def is_resource_pool(self) -> bool: ... - def get_raw_graphql_data(self) -> Optional[dict]: ... + def get_raw_graphql_data(self) -> dict | None: ... def extract(self, params: dict[str, str]) -> dict[str, Any]: ... @runtime_checkable class CoreNode(CoreNodeBase, Protocol): - async def save(self, allow_upsert: bool = False, update_group_context: Optional[bool] = None) -> None: ... + async def save(self, allow_upsert: bool = False, update_group_context: bool | None = None) -> None: ... async def delete(self) -> None: ... @@ -184,7 +184,7 @@ async def remove_relationships(self, relation_to_update: str, related_nodes: lis @runtime_checkable class CoreNodeSync(CoreNodeBase, Protocol): - def save(self, allow_upsert: bool = False, update_group_context: Optional[bool] = None) -> None: ... + def save(self, allow_upsert: bool = False, update_group_context: bool | None = None) -> None: ... def delete(self) -> None: ... diff --git a/infrahub_sdk/pytest_plugin/items/base.py b/infrahub_sdk/pytest_plugin/items/base.py index a27948c7..0847f41e 100644 --- a/infrahub_sdk/pytest_plugin/items/base.py +++ b/infrahub_sdk/pytest_plugin/items/base.py @@ -2,7 +2,7 @@ import difflib from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Any import pytest import ujson @@ -42,7 +42,7 @@ def validate_resource_config(self) -> None: if self.resource_config is None: raise InvalidResourceConfigError(self.resource_name) - def get_result_differences(self, computed: Any) -> Optional[str]: + def get_result_differences(self, computed: Any) -> str | None: """Compute the differences between the computed result and the expected one. If the results are not JSON parsable, this method must be redefined to handle them. @@ -67,13 +67,13 @@ def get_result_differences(self, computed: Any) -> Optional[str]: def runtest(self) -> None: """Run the test logic.""" - def repr_failure(self, excinfo: pytest.ExceptionInfo, style: Optional[str] = None) -> str: + def repr_failure(self, excinfo: pytest.ExceptionInfo, style: str | None = None) -> str: if isinstance(excinfo.value, InvalidGitRepositoryError): return f"Invalid Git repository at {excinfo.value}" return str(excinfo.value) - def reportinfo(self) -> tuple[Union[Path, str], Optional[int], str]: + def reportinfo(self) -> tuple[Path | str, int | None, str]: return self.path, 0, f"resource: {self.name}" @property diff --git a/infrahub_sdk/pytest_plugin/items/check.py b/infrahub_sdk/pytest_plugin/items/check.py index 551cc50e..518487fa 100644 --- a/infrahub_sdk/pytest_plugin/items/check.py +++ b/infrahub_sdk/pytest_plugin/items/check.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import ujson from httpx import HTTPStatusError @@ -45,7 +45,7 @@ def run_check(self, variables: dict[str, Any]) -> Any: self.instantiate_check() return asyncio.run(self.check_instance.run(data=variables)) - def repr_failure(self, excinfo: ExceptionInfo, style: Optional[str] = None) -> str: + def repr_failure(self, excinfo: ExceptionInfo, style: str | None = None) -> str: if isinstance(excinfo.value, HTTPStatusError): try: response_content = ujson.dumps(excinfo.value.response.json(), indent=4) diff --git a/infrahub_sdk/pytest_plugin/items/graphql_query.py b/infrahub_sdk/pytest_plugin/items/graphql_query.py index d77fc9e7..3e196ace 100644 --- a/infrahub_sdk/pytest_plugin/items/graphql_query.py +++ b/infrahub_sdk/pytest_plugin/items/graphql_query.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import ujson from httpx import HTTPStatusError @@ -25,7 +25,7 @@ def execute_query(self) -> Any: variables=self.test.spec.get_variables_data(), # type: ignore[union-attr] ) - def repr_failure(self, excinfo: ExceptionInfo, style: Optional[str] = None) -> str: + def repr_failure(self, excinfo: ExceptionInfo, style: str | None = None) -> str: if isinstance(excinfo.value, HTTPStatusError): try: response_content = ujson.dumps(excinfo.value.response.json(), indent=4) diff --git a/infrahub_sdk/pytest_plugin/items/jinja2_transform.py b/infrahub_sdk/pytest_plugin/items/jinja2_transform.py index 59befec4..48497c09 100644 --- a/infrahub_sdk/pytest_plugin/items/jinja2_transform.py +++ b/infrahub_sdk/pytest_plugin/items/jinja2_transform.py @@ -1,7 +1,7 @@ from __future__ import annotations import difflib -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import jinja2 import ujson @@ -28,7 +28,7 @@ def get_jinja2_environment(self) -> jinja2.Environment: def get_jinja2_template(self) -> jinja2.Template: return self.get_jinja2_environment().get_template(str(self.resource_config.template_path)) # type: ignore[attr-defined] - def render_jinja2_template(self, variables: dict[str, Any]) -> Optional[str]: + def render_jinja2_template(self, variables: dict[str, Any]) -> str | None: try: return self.get_jinja2_template().render(**variables) except jinja2.UndefinedError as exc: @@ -48,7 +48,7 @@ def render_jinja2_template(self, variables: dict[str, Any]) -> Optional[str]: ) from exc return None - def get_result_differences(self, computed: Any) -> Optional[str]: + def get_result_differences(self, computed: Any) -> str | None: if not isinstance(self.test.spec, InfrahubInputOutputTest) or not self.test.spec.output or computed is None: return None @@ -61,7 +61,7 @@ def get_result_differences(self, computed: Any) -> Optional[str]: ) return "\n".join(differences) - def repr_failure(self, excinfo: ExceptionInfo, style: Optional[str] = None) -> str: + def repr_failure(self, excinfo: ExceptionInfo, style: str | None = None) -> str: if isinstance(excinfo.value, HTTPStatusError): try: response_content = ujson.dumps(excinfo.value.response.json(), indent=4, sort_keys=True) @@ -98,7 +98,7 @@ def runtest(self) -> None: if computed is not None and differences and self.test.expect == InfrahubTestExpectedResult.PASS: raise OutputMatchError(name=self.name, differences=differences) - def repr_failure(self, excinfo: ExceptionInfo, style: Optional[str] = None) -> str: + def repr_failure(self, excinfo: ExceptionInfo, style: str | None = None) -> str: if isinstance(excinfo.value, (Jinja2TransformUndefinedError, Jinja2TransformError)): return excinfo.value.message diff --git a/infrahub_sdk/pytest_plugin/items/python_transform.py b/infrahub_sdk/pytest_plugin/items/python_transform.py index 28a92e14..eed2afbf 100644 --- a/infrahub_sdk/pytest_plugin/items/python_transform.py +++ b/infrahub_sdk/pytest_plugin/items/python_transform.py @@ -2,7 +2,7 @@ import asyncio from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import ujson from httpx import HTTPStatusError @@ -44,7 +44,7 @@ def run_transform(self, variables: dict[str, Any]) -> Any: self.instantiate_transform() return asyncio.run(self.transform_instance.run(data=variables)) - def repr_failure(self, excinfo: ExceptionInfo, style: Optional[str] = None) -> str: + def repr_failure(self, excinfo: ExceptionInfo, style: str | None = None) -> str: if isinstance(excinfo.value, HTTPStatusError): try: response_content = ujson.dumps(excinfo.value.response.json(), indent=4) diff --git a/infrahub_sdk/pytest_plugin/loader.py b/infrahub_sdk/pytest_plugin/loader.py index b8b62875..33040293 100644 --- a/infrahub_sdk/pytest_plugin/loader.py +++ b/infrahub_sdk/pytest_plugin/loader.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Iterable -from typing import Any, Optional +from typing import Any import pytest import yaml @@ -53,7 +53,7 @@ class InfrahubYamlFile(pytest.File): - def get_resource_config(self, group: InfrahubTestGroup) -> Optional[Any]: + def get_resource_config(self, group: InfrahubTestGroup) -> Any | None: """Retrieve the resource configuration to apply to all tests in a group.""" resource_config_function = CONFIG_MAPPING.get(group.resource) diff --git a/infrahub_sdk/pytest_plugin/models.py b/infrahub_sdk/pytest_plugin/models.py index fd759c82..122b3687 100644 --- a/infrahub_sdk/pytest_plugin/models.py +++ b/infrahub_sdk/pytest_plugin/models.py @@ -2,7 +2,7 @@ from enum import Enum from pathlib import Path -from typing import Any, Literal, Optional, Union +from typing import Any, Literal, Union import ujson import yaml @@ -28,20 +28,20 @@ class InfrahubBaseTest(BaseModel): class InfrahubInputOutputTest(InfrahubBaseTest): - directory: Optional[Path] = Field( + directory: Path | None = Field( None, description="Path to the directory where the input and output files are located" ) input: Path = Field( Path("input.json"), description="Path to the file with the input data for the test, can be a relative path from the config file or from the directory.", ) - output: Optional[Path] = Field( + output: Path | None = Field( None, description="Path to the file with the expected output for the test, can be a relative path from the config file or from the directory.", ) @staticmethod - def parse_user_provided_data(path: Union[Path, None]) -> Any: + def parse_user_provided_data(path: Path | None) -> Any: """Read and parse user provided data depending on a file extension. This function handles JSON and YAML as they can be used to achieve the same goal. However some users may be more used to one format or @@ -69,7 +69,7 @@ def update_paths(self, base_dir: Path) -> None: self.directory = base_dir if not self.input or not self.input.is_file(): - search_input: Union[Path, str] = self.input or "input.*" + search_input: Path | str = self.input or "input.*" results = list(self.directory.rglob(str(search_input))) if not results: @@ -81,7 +81,7 @@ def update_paths(self, base_dir: Path) -> None: self.input = results[0] if not self.output or not self.output.is_file(): - search_output: Union[Path, str] = self.output or "output.*" + search_output: Path | str = self.output or "output.*" results = list(self.directory.rglob(str(search_output))) if results and len(results) != 1: @@ -99,7 +99,7 @@ def get_output_data(self) -> Any: class InfrahubIntegrationTest(InfrahubInputOutputTest): - variables: Union[Path, dict[str, Any]] = Field( + variables: Path | dict[str, Any] = Field( Path("variables.json"), description="Variables and corresponding values to pass to the GraphQL query" ) @@ -107,7 +107,7 @@ def update_paths(self, base_dir: Path) -> None: super().update_paths(base_dir) if self.variables and not isinstance(self.variables, dict) and not self.variables.is_file(): - search_variables: Union[Path, str] = self.variables or "variables.*" + search_variables: Path | str = self.variables or "variables.*" results = list(self.directory.rglob(str(search_variables))) # type: ignore[union-attr] if not results: @@ -176,7 +176,7 @@ class InfrahubTest(BaseModel): InfrahubTestExpectedResult.PASS, description="Expected outcome of the test, can be either PASS (default) or FAIL", ) - spec: Union[ + spec: Union[ # noqa: UP007 InfrahubCheckSmokeTest, InfrahubCheckUnitProcessTest, InfrahubCheckIntegrationTest, @@ -199,5 +199,5 @@ class InfrahubTestGroup(BaseModel): class InfrahubTestFileV1(BaseModel): model_config = ConfigDict(extra="forbid") - version: Optional[str] = "1.0" + version: str | None = "1.0" infrahub_tests: list[InfrahubTestGroup] diff --git a/infrahub_sdk/pytest_plugin/plugin.py b/infrahub_sdk/pytest_plugin/plugin.py index 98b864a7..871ba45b 100644 --- a/infrahub_sdk/pytest_plugin/plugin.py +++ b/infrahub_sdk/pytest_plugin/plugin.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import os from pathlib import Path -from typing import Optional, Union from pytest import Collector, Config, Item, Parser, Session from pytest import exit as exit_test @@ -85,7 +86,7 @@ def pytest_sessionstart(session: Session) -> None: session.infrahub_client = infrahub_client # type: ignore[attr-defined] -def pytest_collect_file(parent: Union[Collector, Item], file_path: Path) -> Optional[InfrahubYamlFile]: +def pytest_collect_file(parent: Collector | Item, file_path: Path) -> InfrahubYamlFile | None: if file_path.suffix in [".yml", ".yaml"] and file_path.name.startswith("test_"): return InfrahubYamlFile.from_parent(parent, path=file_path) return None diff --git a/infrahub_sdk/query_groups.py b/infrahub_sdk/query_groups.py index 4a21165e..b1b4687a 100644 --- a/infrahub_sdk/query_groups.py +++ b/infrahub_sdk/query_groups.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Optional +from typing import TYPE_CHECKING from .constants import InfrahubClientMode from .exceptions import NodeNotFoundError @@ -18,11 +18,11 @@ class InfrahubGroupContextBase: def __init__(self) -> None: self.related_node_ids: list[str] = [] self.related_group_ids: list[str] = [] - self.unused_member_ids: Optional[list[str]] = None - self.unused_child_ids: Optional[list[str]] = None - self.previous_members: Optional[list[RelatedNodeBase]] = None - self.previous_children: Optional[list[RelatedNodeBase]] = None - self.identifier: Optional[str] = None + self.unused_member_ids: list[str] | None = None + self.unused_child_ids: list[str] | None = None + self.previous_members: list[RelatedNodeBase] | None = None + self.previous_children: list[RelatedNodeBase] | None = None + self.identifier: str | None = None self.params: dict[str, str] = {} self.delete_unused_nodes: bool = False self.group_type: str = "CoreStandardGroup" @@ -30,9 +30,9 @@ def __init__(self) -> None: def set_properties( self, identifier: str, - params: Optional[dict[str, str]] = None, + params: dict[str, str] | None = None, delete_unused_nodes: bool = False, - group_type: Optional[str] = None, + group_type: str | None = None, ) -> None: """Setter method to set the values of identifier and params. @@ -52,7 +52,7 @@ def _get_params_as_str(self) -> str: params_as_str.append(f"{key}: {value!s}") return ", ".join(params_as_str) - def _generate_group_name(self, suffix: Optional[str] = None) -> str: + def _generate_group_name(self, suffix: str | None = None) -> str: group_name = self.identifier or "sdk" if suffix: @@ -85,7 +85,7 @@ def __init__(self, client: InfrahubClient) -> None: super().__init__() self.client = client - async def get_group(self, store_peers: bool = False) -> Optional[InfrahubNode]: + async def get_group(self, store_peers: bool = False) -> InfrahubNode | None: group_name = self._generate_group_name() try: group = await self.client.get(kind=self.group_type, name__value=group_name, include=["members", "children"]) @@ -110,7 +110,7 @@ async def delete_unused(self) -> None: if child.id in self.unused_child_ids and child.typename: await self.client.delete(kind=child.typename, id=child.id) - async def add_related_nodes(self, ids: list[str], update_group_context: Optional[bool] = None) -> None: + async def add_related_nodes(self, ids: list[str], update_group_context: bool | None = None) -> None: """ Add related Nodes IDs to the context. @@ -123,7 +123,7 @@ async def add_related_nodes(self, ids: list[str], update_group_context: Optional ): self.related_node_ids.extend(ids) - async def add_related_groups(self, ids: list[str], update_group_context: Optional[bool] = None) -> None: + async def add_related_groups(self, ids: list[str], update_group_context: bool | None = None) -> None: """ Add related Groups IDs to the context. @@ -191,7 +191,7 @@ def __init__(self, client: InfrahubClientSync) -> None: super().__init__() self.client = client - def get_group(self, store_peers: bool = False) -> Optional[InfrahubNodeSync]: + def get_group(self, store_peers: bool = False) -> InfrahubNodeSync | None: group_name = self._generate_group_name() try: group = self.client.get(kind=self.group_type, name__value=group_name, include=["members", "children"]) @@ -216,7 +216,7 @@ def delete_unused(self) -> None: if child.id in self.unused_child_ids and child.typename: self.client.delete(kind=child.typename, id=child.id) - def add_related_nodes(self, ids: list[str], update_group_context: Optional[bool] = None) -> None: + def add_related_nodes(self, ids: list[str], update_group_context: bool | None = None) -> None: """ Add related Nodes IDs to the context. @@ -229,7 +229,7 @@ def add_related_nodes(self, ids: list[str], update_group_context: Optional[bool] ): self.related_node_ids.extend(ids) - def add_related_groups(self, ids: list[str], update_group_context: Optional[bool] = None) -> None: + def add_related_groups(self, ids: list[str], update_group_context: bool | None = None) -> None: """ Add related Groups IDs to the context. diff --git a/infrahub_sdk/schema/__init__.py b/infrahub_sdk/schema/__init__.py index e69fa407..1b334fa0 100644 --- a/infrahub_sdk/schema/__init__.py +++ b/infrahub_sdk/schema/__init__.py @@ -5,7 +5,7 @@ from collections.abc import MutableMapping from enum import Enum from time import sleep -from typing import TYPE_CHECKING, Any, Optional, TypedDict, Union +from typing import TYPE_CHECKING, Any, TypedDict, Union from urllib.parse import urlencode import httpx @@ -65,9 +65,9 @@ class DropdownMutationOptionalArgs(TypedDict): - color: Optional[str] - description: Optional[str] - label: Optional[str] + color: str | None + description: str | None + label: str | None class DropdownMutation(str, Enum): @@ -102,10 +102,10 @@ def generate_payload_create( self, schema: MainSchemaTypesAPI, data: dict, - source: Optional[str] = None, - owner: Optional[str] = None, - is_protected: Optional[bool] = None, - is_visible: Optional[bool] = None, + source: str | None = None, + owner: str | None = None, + is_protected: bool | None = None, + is_visible: bool | None = None, ) -> dict[str, Any]: obj_data: dict[str, Any] = {} item_metadata: dict[str, Any] = {} @@ -155,7 +155,7 @@ def _validate_load_schema_response(response: httpx.Response) -> SchemaLoadRespon raise InvalidResponseError(message=f"Invalid response received from server HTTP {response.status_code}") @staticmethod - def _get_schema_name(schema: Union[type[Union[SchemaType, SchemaTypeSync]], str]) -> str: + def _get_schema_name(schema: type[SchemaType | SchemaTypeSync] | str) -> str: if hasattr(schema, "_is_runtime_protocol") and schema._is_runtime_protocol: # type: ignore[union-attr] return schema.__name__ # type: ignore[union-attr] @@ -172,10 +172,10 @@ def __init__(self, client: InfrahubClient): async def get( self, - kind: Union[type[Union[SchemaType, SchemaTypeSync]], str], - branch: Optional[str] = None, + kind: type[SchemaType | SchemaTypeSync] | str, + branch: str | None = None, refresh: bool = False, - timeout: Optional[int] = None, + timeout: int | None = None, ) -> MainSchemaTypesAPI: branch = branch or self.client.default_branch @@ -198,7 +198,7 @@ async def get( raise SchemaNotFoundError(identifier=kind_str) async def all( - self, branch: Optional[str] = None, refresh: bool = False, namespaces: Optional[list[str]] = None + self, branch: str | None = None, refresh: bool = False, namespaces: list[str] | None = None ) -> MutableMapping[str, MainSchemaTypesAPI]: """Retrieve the entire schema for a given branch. @@ -219,7 +219,7 @@ async def all( return self.cache[branch] async def load( - self, schemas: list[dict], branch: Optional[str] = None, wait_until_converged: bool = False + self, schemas: list[dict], branch: str | None = None, wait_until_converged: bool = False ) -> SchemaLoadResponse: branch = branch or self.client.default_branch url = f"{self.client.address}/api/schema/load?branch={branch}" @@ -232,7 +232,7 @@ async def load( return self._validate_load_schema_response(response=response) - async def wait_until_converged(self, branch: Optional[str] = None) -> None: + async def wait_until_converged(self, branch: str | None = None) -> None: """Wait until the schema has converged on the selected branch or the timeout has been reached""" waited = 0 while True: @@ -247,12 +247,12 @@ async def wait_until_converged(self, branch: Optional[str] = None) -> None: waited += 1 await asyncio.sleep(delay=1) - async def in_sync(self, branch: Optional[str] = None) -> bool: + async def in_sync(self, branch: str | None = None) -> bool: """Indicate if the schema is in sync across all workers for the provided branch""" response = await self.client.execute_graphql(query=SCHEMA_HASH_SYNC_STATUS, branch_name=branch) return response["InfrahubStatus"]["summary"]["schema_hash_synced"] - async def check(self, schemas: list[dict], branch: Optional[str] = None) -> tuple[bool, Optional[dict]]: + async def check(self, schemas: list[dict], branch: str | None = None) -> tuple[bool, dict | None]: branch = branch or self.client.default_branch url = f"{self.client.address}/api/schema/check?branch={branch}" response = await self.client._post( @@ -269,7 +269,7 @@ async def check(self, schemas: list[dict], branch: Optional[str] = None) -> tupl return False, None async def _get_kind_and_attribute_schema( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, branch: str | None = None ) -> tuple[str, AttributeSchema]: node_kind: str = kind._schema.kind if not isinstance(kind, str) else kind node_schema = await self.client.schema.get(kind=node_kind, branch=branch) @@ -283,10 +283,10 @@ async def _get_kind_and_attribute_schema( async def _mutate_enum_attribute( self, mutation: EnumMutation, - kind: Union[str, InfrahubNodeTypes], + kind: str | InfrahubNodeTypes, attribute: str, - option: Union[str, int], - branch: Optional[str] = None, + option: str | int, + branch: str | None = None, ) -> None: node_kind, schema_attr = await self._get_kind_and_attribute_schema( kind=kind, attribute=attribute, branch=branch @@ -306,14 +306,14 @@ async def _mutate_enum_attribute( ) async def add_enum_option( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, option: Union[str, int], branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, option: str | int, branch: str | None = None ) -> None: await self._mutate_enum_attribute( mutation=EnumMutation.add, kind=kind, attribute=attribute, option=option, branch=branch ) async def remove_enum_option( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, option: Union[str, int], branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, option: str | int, branch: str | None = None ) -> None: await self._mutate_enum_attribute( mutation=EnumMutation.remove, kind=kind, attribute=attribute, option=option, branch=branch @@ -322,11 +322,11 @@ async def remove_enum_option( async def _mutate_dropdown_attribute( self, mutation: DropdownMutation, - kind: Union[str, InfrahubNodeTypes], + kind: str | InfrahubNodeTypes, attribute: str, option: str, - branch: Optional[str] = None, - dropdown_optional_args: Optional[DropdownMutationOptionalArgs] = None, + branch: str | None = None, + dropdown_optional_args: DropdownMutationOptionalArgs | None = None, ) -> None: dropdown_optional_args = dropdown_optional_args or DropdownMutationOptionalArgs( color="", description="", label="" @@ -358,7 +358,7 @@ async def _mutate_dropdown_attribute( ) async def remove_dropdown_option( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, option: str, branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, option: str, branch: str | None = None ) -> None: await self._mutate_dropdown_attribute( mutation=DropdownMutation.remove, kind=kind, attribute=attribute, option=option, branch=branch @@ -366,13 +366,13 @@ async def remove_dropdown_option( async def add_dropdown_option( self, - kind: Union[str, InfrahubNodeTypes], + kind: str | InfrahubNodeTypes, attribute: str, option: str, - color: Optional[str] = "", - description: Optional[str] = "", - label: Optional[str] = "", - branch: Optional[str] = None, + color: str | None = "", + description: str | None = "", + label: str | None = "", + branch: str | None = None, ) -> None: dropdown_optional_args = DropdownMutationOptionalArgs(color=color, description=description, label=label) await self._mutate_dropdown_attribute( @@ -385,7 +385,7 @@ async def add_dropdown_option( ) async def fetch( - self, branch: str, namespaces: Optional[list[str]] = None, timeout: Optional[int] = None + self, branch: str, namespaces: list[str] | None = None, timeout: int | None = None ) -> MutableMapping[str, MainSchemaTypesAPI]: """Fetch the schema from the server for a given branch. @@ -429,7 +429,7 @@ def __init__(self, client: InfrahubClientSync): self.cache: dict = defaultdict(lambda: dict) def all( - self, branch: Optional[str] = None, refresh: bool = False, namespaces: Optional[list[str]] = None + self, branch: str | None = None, refresh: bool = False, namespaces: list[str] | None = None ) -> MutableMapping[str, MainSchemaTypesAPI]: """Retrieve the entire schema for a given branch. @@ -451,10 +451,10 @@ def all( def get( self, - kind: Union[type[Union[SchemaType, SchemaTypeSync]], str], - branch: Optional[str] = None, + kind: type[SchemaType | SchemaTypeSync] | str, + branch: str | None = None, refresh: bool = False, - timeout: Optional[int] = None, + timeout: int | None = None, ) -> MainSchemaTypesAPI: branch = branch or self.client.default_branch @@ -477,7 +477,7 @@ def get( raise SchemaNotFoundError(identifier=kind_str) def _get_kind_and_attribute_schema( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, branch: str | None = None ) -> tuple[str, AttributeSchemaAPI]: node_kind: str = kind._schema.kind if not isinstance(kind, str) else kind node_schema = self.client.schema.get(kind=node_kind, branch=branch) @@ -491,10 +491,10 @@ def _get_kind_and_attribute_schema( def _mutate_enum_attribute( self, mutation: EnumMutation, - kind: Union[str, InfrahubNodeTypes], + kind: str | InfrahubNodeTypes, attribute: str, - option: Union[str, int], - branch: Optional[str] = None, + option: str | int, + branch: str | None = None, ) -> None: node_kind, schema_attr = self._get_kind_and_attribute_schema(kind=kind, attribute=attribute, branch=branch) @@ -512,14 +512,14 @@ def _mutate_enum_attribute( ) def add_enum_option( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, option: Union[str, int], branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, option: str | int, branch: str | None = None ) -> None: self._mutate_enum_attribute( mutation=EnumMutation.add, kind=kind, attribute=attribute, option=option, branch=branch ) def remove_enum_option( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, option: Union[str, int], branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, option: str | int, branch: str | None = None ) -> None: self._mutate_enum_attribute( mutation=EnumMutation.remove, kind=kind, attribute=attribute, option=option, branch=branch @@ -528,11 +528,11 @@ def remove_enum_option( def _mutate_dropdown_attribute( self, mutation: DropdownMutation, - kind: Union[str, InfrahubNodeTypes], + kind: str | InfrahubNodeTypes, attribute: str, option: str, - branch: Optional[str] = None, - dropdown_optional_args: Optional[DropdownMutationOptionalArgs] = None, + branch: str | None = None, + dropdown_optional_args: DropdownMutationOptionalArgs | None = None, ) -> None: dropdown_optional_args = dropdown_optional_args or DropdownMutationOptionalArgs( color="", description="", label="" @@ -562,7 +562,7 @@ def _mutate_dropdown_attribute( ) def remove_dropdown_option( - self, kind: Union[str, InfrahubNodeTypes], attribute: str, option: str, branch: Optional[str] = None + self, kind: str | InfrahubNodeTypes, attribute: str, option: str, branch: str | None = None ) -> None: self._mutate_dropdown_attribute( mutation=DropdownMutation.remove, kind=kind, attribute=attribute, option=option, branch=branch @@ -570,13 +570,13 @@ def remove_dropdown_option( def add_dropdown_option( self, - kind: Union[str, InfrahubNodeTypes], + kind: str | InfrahubNodeTypes, attribute: str, option: str, - color: Optional[str] = "", - description: Optional[str] = "", - label: Optional[str] = "", - branch: Optional[str] = None, + color: str | None = "", + description: str | None = "", + label: str | None = "", + branch: str | None = None, ) -> None: dropdown_optional_args = DropdownMutationOptionalArgs(color=color, description=description, label=label) self._mutate_dropdown_attribute( @@ -589,7 +589,7 @@ def add_dropdown_option( ) def fetch( - self, branch: str, namespaces: Optional[list[str]] = None, timeout: Optional[int] = None + self, branch: str, namespaces: list[str] | None = None, timeout: int | None = None ) -> MutableMapping[str, MainSchemaTypesAPI]: """Fetch the schema from the server for a given branch. @@ -627,7 +627,7 @@ def fetch( return nodes def load( - self, schemas: list[dict], branch: Optional[str] = None, wait_until_converged: bool = False + self, schemas: list[dict], branch: str | None = None, wait_until_converged: bool = False ) -> SchemaLoadResponse: branch = branch or self.client.default_branch url = f"{self.client.address}/api/schema/load?branch={branch}" @@ -640,7 +640,7 @@ def load( return self._validate_load_schema_response(response=response) - def wait_until_converged(self, branch: Optional[str] = None) -> None: + def wait_until_converged(self, branch: str | None = None) -> None: """Wait until the schema has converged on the selected branch or the timeout has been reached""" waited = 0 while True: @@ -655,12 +655,12 @@ def wait_until_converged(self, branch: Optional[str] = None) -> None: waited += 1 sleep(1) - def in_sync(self, branch: Optional[str] = None) -> bool: + def in_sync(self, branch: str | None = None) -> bool: """Indicate if the schema is in sync across all workers for the provided branch""" response = self.client.execute_graphql(query=SCHEMA_HASH_SYNC_STATUS, branch_name=branch) return response["InfrahubStatus"]["summary"]["schema_hash_synced"] - def check(self, schemas: list[dict], branch: Optional[str] = None) -> tuple[bool, Optional[dict]]: + def check(self, schemas: list[dict], branch: str | None = None) -> tuple[bool, dict | None]: branch = branch or self.client.default_branch url = f"{self.client.address}/api/schema/check?branch={branch}" response = self.client._post( diff --git a/infrahub_sdk/schema/main.py b/infrahub_sdk/schema/main.py index 9fedd234..7f6c7d66 100644 --- a/infrahub_sdk/schema/main.py +++ b/infrahub_sdk/schema/main.py @@ -2,7 +2,7 @@ import warnings from enum import Enum -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Any, Union from pydantic import BaseModel, ConfigDict, Field @@ -91,22 +91,22 @@ class RelationshipDeleteBehavior(str, Enum): class AttributeSchema(BaseModel): model_config = ConfigDict(use_enum_values=True) - id: Optional[str] = None + id: str | None = None state: SchemaState = SchemaState.PRESENT name: str kind: AttributeKind - label: Optional[str] = None - description: Optional[str] = None - default_value: Optional[Any] = None + label: str | None = None + description: str | None = None + default_value: Any | None = None unique: bool = False - branch: Optional[BranchSupportType] = None + branch: BranchSupportType | None = None optional: bool = False - choices: Optional[list[dict[str, Any]]] = None - enum: Optional[list[Union[str, int]]] = None - max_length: Optional[int] = None - min_length: Optional[int] = None - regex: Optional[str] = None - order_weight: Optional[int] = None + choices: list[dict[str, Any]] | None = None + enum: list[str | int] | None = None + max_length: int | None = None + min_length: int | None = None + regex: str | None = None + order_weight: int | None = None class AttributeSchemaAPI(AttributeSchema): @@ -120,22 +120,22 @@ class AttributeSchemaAPI(AttributeSchema): class RelationshipSchema(BaseModel): model_config = ConfigDict(use_enum_values=True) - id: Optional[str] = None + id: str | None = None state: SchemaState = SchemaState.PRESENT name: str peer: str kind: RelationshipKind = RelationshipKind.GENERIC - label: Optional[str] = None - description: Optional[str] = None - identifier: Optional[str] = None - min_count: Optional[int] = None - max_count: Optional[int] = None + label: str | None = None + description: str | None = None + identifier: str | None = None + min_count: int | None = None + max_count: int | None = None direction: RelationshipDirection = RelationshipDirection.BIDIR - on_delete: Optional[RelationshipDeleteBehavior] = None + on_delete: RelationshipDeleteBehavior | None = None cardinality: str = "many" - branch: Optional[BranchSupportType] = None + branch: BranchSupportType | None = None optional: bool = True - order_weight: Optional[int] = None + order_weight: int | None = None class RelationshipSchemaAPI(RelationshipSchema): @@ -143,7 +143,7 @@ class RelationshipSchemaAPI(RelationshipSchema): inherited: bool = False read_only: bool = False - hierarchical: Optional[str] = None + hierarchical: str | None = None allow_override: AllowOverrideType = AllowOverrideType.ANY @@ -156,9 +156,7 @@ class BaseSchemaAttrRelAPI(BaseModel): attributes: list[AttributeSchemaAPI] = Field(default_factory=list) relationships: list[RelationshipSchemaAPI] = Field(default_factory=list) - def get_field( - self, name: str, raise_on_error: bool = True - ) -> Union[AttributeSchemaAPI, RelationshipSchemaAPI, None]: + def get_field(self, name: str, raise_on_error: bool = True) -> AttributeSchemaAPI | RelationshipSchemaAPI | None: if attribute_field := self.get_attribute_or_none(name=name): return attribute_field @@ -176,7 +174,7 @@ def get_attribute(self, name: str) -> AttributeSchemaAPI: return item raise ValueError(f"Unable to find the attribute {name}") - def get_attribute_or_none(self, name: str) -> Optional[AttributeSchemaAPI]: + def get_attribute_or_none(self, name: str) -> AttributeSchemaAPI | None: for item in self.attributes: if item.name == name: return item @@ -188,15 +186,13 @@ def get_relationship(self, name: str) -> RelationshipSchemaAPI: return item raise ValueError(f"Unable to find the relationship {name}") - def get_relationship_or_none(self, name: str) -> Optional[RelationshipSchemaAPI]: + def get_relationship_or_none(self, name: str) -> RelationshipSchemaAPI | None: for item in self.relationships: if item.name == name: return item return None - def get_relationship_by_identifier( - self, id: str, raise_on_error: bool = True - ) -> Union[RelationshipSchemaAPI, None]: + def get_relationship_by_identifier(self, id: str, raise_on_error: bool = True) -> RelationshipSchemaAPI | None: for item in self.relationships: if item.identifier == id: return item @@ -255,17 +251,17 @@ def unique_attributes(self) -> list[AttributeSchemaAPI]: class BaseSchema(BaseModel): model_config = ConfigDict(use_enum_values=True) - id: Optional[str] = None + id: str | None = None state: SchemaState = SchemaState.PRESENT name: str - label: Optional[str] = None + label: str | None = None namespace: str - description: Optional[str] = None - include_in_menu: Optional[bool] = None - menu_placement: Optional[str] = None - icon: Optional[str] = None - uniqueness_constraints: Optional[list[list[str]]] = None - documentation: Optional[str] = None + description: str | None = None + include_in_menu: bool | None = None + menu_placement: str | None = None + icon: str | None = None + uniqueness_constraints: list[list[str]] | None = None + documentation: str | None = None @property def kind(self) -> str: @@ -280,7 +276,7 @@ def convert_api(self) -> GenericSchemaAPI: class GenericSchemaAPI(BaseSchema, BaseSchemaAttrRelAPI): """A Generic can be either an Interface or a Union depending if there are some Attributes or Relationships defined.""" - hash: Optional[str] = None + hash: str | None = None used_by: list[str] = Field(default_factory=list) @@ -288,12 +284,12 @@ class BaseNodeSchema(BaseSchema): model_config = ConfigDict(use_enum_values=True) inherit_from: list[str] = Field(default_factory=list) - branch: Optional[BranchSupportType] = None - default_filter: Optional[str] = None - human_friendly_id: Optional[list[str]] = None - generate_profile: Optional[bool] = None - parent: Optional[str] = None - children: Optional[str] = None + branch: BranchSupportType | None = None + default_filter: str | None = None + human_friendly_id: list[str] | None = None + generate_profile: bool | None = None + parent: str | None = None + children: str | None = None class NodeSchema(BaseNodeSchema, BaseSchemaAttrRel): @@ -302,8 +298,8 @@ def convert_api(self) -> NodeSchemaAPI: class NodeSchemaAPI(BaseNodeSchema, BaseSchemaAttrRelAPI): - hash: Optional[str] = None - hierarchy: Optional[str] = None + hash: str | None = None + hierarchy: str | None = None class ProfileSchemaAPI(BaseSchema, BaseSchemaAttrRelAPI): @@ -313,13 +309,13 @@ class ProfileSchemaAPI(BaseSchema, BaseSchemaAttrRelAPI): class NodeExtensionSchema(BaseModel): model_config = ConfigDict(use_enum_values=True) - name: Optional[str] = None + name: str | None = None kind: str - description: Optional[str] = None - label: Optional[str] = None + description: str | None = None + label: str | None = None inherit_from: list[str] = Field(default_factory=list) - branch: Optional[BranchSupportType] = None - default_filter: Optional[str] = None + branch: BranchSupportType | None = None + default_filter: str | None = None attributes: list[AttributeSchema] = Field(default_factory=list) relationships: list[RelationshipSchema] = Field(default_factory=list) diff --git a/infrahub_sdk/schema/repository.py b/infrahub_sdk/schema/repository.py index 6d32f727..275a6ddc 100644 --- a/infrahub_sdk/schema/repository.py +++ b/infrahub_sdk/schema/repository.py @@ -1,7 +1,7 @@ from __future__ import annotations from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union +from typing import TYPE_CHECKING, Any, TypeVar, Union from pydantic import BaseModel, ConfigDict, Field, field_validator @@ -30,7 +30,7 @@ class InfrahubRepositoryConfigElement(BaseModel): class InfrahubRepositoryArtifactDefinitionConfig(InfrahubRepositoryConfigElement): model_config = ConfigDict(extra="forbid") name: str = Field(..., description="The name of the artifact definition") - artifact_name: Optional[str] = Field(default=None, description="Name of the artifact created from this definition") + artifact_name: str | None = Field(default=None, description="Name of the artifact created from this definition") parameters: dict[str, Any] = Field(..., description="The input parameters required to render this artifact") content_type: str = Field(..., description="The content type of the rendered artifact") targets: str = Field(..., description="The group to target when creating artifacts") @@ -42,7 +42,7 @@ class InfrahubJinja2TransformConfig(InfrahubRepositoryConfigElement): name: str = Field(..., description="The name of the transform") query: str = Field(..., description="The name of the GraphQL Query") template_path: Path = Field(..., description="The path within the repository of the template file") - description: Optional[str] = Field(default=None, description="Description for this transform") + description: str | None = Field(default=None, description="Description for this transform") @property def template_path_value(self) -> str: @@ -62,12 +62,12 @@ class InfrahubCheckDefinitionConfig(InfrahubRepositoryConfigElement): parameters: dict[str, Any] = Field( default_factory=dict, description="The input parameters required to run this check" ) - targets: Optional[str] = Field( + targets: str | None = Field( default=None, description="The group to target when running this check, leave blank for global checks" ) class_name: str = Field(default="Check", description="The name of the check class to run.") - def load_class(self, import_root: Optional[str] = None, relative_path: Optional[str] = None) -> type[InfrahubCheck]: + def load_class(self, import_root: str | None = None, relative_path: str | None = None) -> type[InfrahubCheck]: module = import_module(module_path=self.file_path, import_root=import_root, relative_path=relative_path) if self.class_name not in dir(module): @@ -96,9 +96,7 @@ class InfrahubGeneratorDefinitionConfig(InfrahubRepositoryConfigElement): description="Decide if the generator should convert the result of the GraphQL query to SDK InfrahubNode objects.", ) - def load_class( - self, import_root: Optional[str] = None, relative_path: Optional[str] = None - ) -> type[InfrahubGenerator]: + def load_class(self, import_root: str | None = None, relative_path: str | None = None) -> type[InfrahubGenerator]: module = import_module(module_path=self.file_path, import_root=import_root, relative_path=relative_path) if self.class_name not in dir(module): @@ -118,9 +116,7 @@ class InfrahubPythonTransformConfig(InfrahubRepositoryConfigElement): file_path: Path = Field(..., description="The file within the repository with the transform code.") class_name: str = Field(default="Transform", description="The name of the transform class to run.") - def load_class( - self, import_root: Optional[str] = None, relative_path: Optional[str] = None - ) -> type[InfrahubTransform]: + def load_class(self, import_root: str | None = None, relative_path: str | None = None) -> type[InfrahubTransform]: module = import_module(module_path=self.file_path, import_root=import_root, relative_path=relative_path) if self.class_name not in dir(module): diff --git a/infrahub_sdk/spec/menu.py b/infrahub_sdk/spec/menu.py index 407c53ca..87b73354 100644 --- a/infrahub_sdk/spec/menu.py +++ b/infrahub_sdk/spec/menu.py @@ -1,4 +1,4 @@ -from typing import Optional +from __future__ import annotations from ..yaml import InfrahubFile, InfrahubFileKind from .object import InfrahubObjectFileData @@ -19,7 +19,7 @@ def enrich_node(cls, data: dict, context: dict) -> dict: class MenuFile(InfrahubFile): - _spec: Optional[InfrahubMenuFileData] = None + _spec: InfrahubMenuFileData | None = None @property def spec(self) -> InfrahubMenuFileData: diff --git a/infrahub_sdk/spec/object.py b/infrahub_sdk/spec/object.py index 5650752d..dddb16db 100644 --- a/infrahub_sdk/spec/object.py +++ b/infrahub_sdk/spec/object.py @@ -1,11 +1,15 @@ -from typing import Any, Optional +from __future__ import annotations + +from typing import TYPE_CHECKING, Any from pydantic import BaseModel, Field -from ..client import InfrahubClient -from ..schema import MainSchemaTypesAPI from ..yaml import InfrahubFile, InfrahubFileKind +if TYPE_CHECKING: + from ..client import InfrahubClient + from ..schema import MainSchemaTypesAPI + class InfrahubObjectFileData(BaseModel): kind: str @@ -21,9 +25,9 @@ async def create_node( client: InfrahubClient, schema: MainSchemaTypesAPI, data: dict, - context: Optional[dict] = None, - branch: Optional[str] = None, - default_schema_kind: Optional[str] = None, + context: dict | None = None, + branch: str | None = None, + default_schema_kind: str | None = None, ) -> None: # First validate of all mandatory fields are present for element in schema.mandatory_attribute_names + schema.mandatory_relationship_names: @@ -113,7 +117,7 @@ async def create_node( class ObjectFile(InfrahubFile): - _spec: Optional[InfrahubObjectFileData] = None + _spec: InfrahubObjectFileData | None = None @property def spec(self) -> InfrahubObjectFileData: diff --git a/infrahub_sdk/store.py b/infrahub_sdk/store.py index fe5ba48c..624722e2 100644 --- a/infrahub_sdk/store.py +++ b/infrahub_sdk/store.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections import defaultdict -from typing import TYPE_CHECKING, Any, Literal, Optional, Union, overload +from typing import TYPE_CHECKING, Any, Literal, overload from .exceptions import NodeNotFoundError @@ -10,7 +10,7 @@ from .node import InfrahubNode, InfrahubNodeSync -def get_schema_name(schema: Optional[Union[str, type[SchemaType]]] = None) -> Optional[str]: +def get_schema_name(schema: str | type[SchemaType] | None = None) -> str | None: if isinstance(schema, str): return schema @@ -31,7 +31,7 @@ def __init__(self) -> None: self._store: dict[str, dict] = defaultdict(dict) self._store_by_hfid: dict[str, Any] = defaultdict(dict) - def _set(self, node: Union[InfrahubNode, InfrahubNodeSync, SchemaType], key: Optional[str] = None) -> None: + def _set(self, node: InfrahubNode | InfrahubNodeSync | SchemaType, key: str | None = None) -> None: hfid = node.get_human_friendly_id_as_string(include_kind=True) if not key and not hfid: @@ -44,7 +44,7 @@ def _set(self, node: Union[InfrahubNode, InfrahubNodeSync, SchemaType], key: Opt if hfid: self._store_by_hfid[hfid] = node - def _get(self, key: str, kind: Optional[Union[str, type[SchemaType]]] = None, raise_when_missing: bool = True): # type: ignore[no-untyped-def] + def _get(self, key: str, kind: str | type[SchemaType] | None = None, raise_when_missing: bool = True): # type: ignore[no-untyped-def] kind_name = get_schema_name(schema=kind) if kind_name and kind_name not in self._store and key not in self._store[kind_name]: # type: ignore[attr-defined] if not raise_when_missing: @@ -90,62 +90,60 @@ def get(self, key: str, kind: type[SchemaType], raise_when_missing: Literal[True @overload def get( self, key: str, kind: type[SchemaType], raise_when_missing: Literal[False] = False - ) -> Optional[SchemaType]: ... + ) -> SchemaType | None: ... @overload def get(self, key: str, kind: type[SchemaType], raise_when_missing: bool = ...) -> SchemaType: ... @overload def get( - self, key: str, kind: Optional[str] = ..., raise_when_missing: Literal[False] = False - ) -> Optional[InfrahubNode]: ... + self, key: str, kind: str | None = ..., raise_when_missing: Literal[False] = False + ) -> InfrahubNode | None: ... @overload - def get(self, key: str, kind: Optional[str] = ..., raise_when_missing: Literal[True] = True) -> InfrahubNode: ... + def get(self, key: str, kind: str | None = ..., raise_when_missing: Literal[True] = True) -> InfrahubNode: ... @overload - def get(self, key: str, kind: Optional[str] = ..., raise_when_missing: bool = ...) -> InfrahubNode: ... + def get(self, key: str, kind: str | None = ..., raise_when_missing: bool = ...) -> InfrahubNode: ... def get( - self, key: str, kind: Optional[Union[str, type[SchemaType]]] = None, raise_when_missing: bool = True - ) -> Optional[Union[InfrahubNode, SchemaType]]: + self, key: str, kind: str | type[SchemaType] | None = None, raise_when_missing: bool = True + ) -> InfrahubNode | SchemaType | None: return self._get(key=key, kind=kind, raise_when_missing=raise_when_missing) @overload def get_by_hfid(self, key: str, raise_when_missing: Literal[True] = True) -> InfrahubNode: ... @overload - def get_by_hfid(self, key: str, raise_when_missing: Literal[False] = False) -> Optional[InfrahubNode]: ... + def get_by_hfid(self, key: str, raise_when_missing: Literal[False] = False) -> InfrahubNode | None: ... - def get_by_hfid(self, key: str, raise_when_missing: bool = True) -> Optional[InfrahubNode]: + def get_by_hfid(self, key: str, raise_when_missing: bool = True) -> InfrahubNode | None: return self._get_by_hfid(key=key, raise_when_missing=raise_when_missing) - def set(self, node: Any, key: Optional[str] = None) -> None: + def set(self, node: Any, key: str | None = None) -> None: return self._set(node=node, key=key) class NodeStoreSync(NodeStoreBase): @overload - def get( - self, key: str, kind: Optional[str] = None, raise_when_missing: Literal[True] = True - ) -> InfrahubNodeSync: ... + def get(self, key: str, kind: str | None = None, raise_when_missing: Literal[True] = True) -> InfrahubNodeSync: ... @overload def get( - self, key: str, kind: Optional[str] = None, raise_when_missing: Literal[False] = False - ) -> Optional[InfrahubNodeSync]: ... + self, key: str, kind: str | None = None, raise_when_missing: Literal[False] = False + ) -> InfrahubNodeSync | None: ... - def get(self, key: str, kind: Optional[str] = None, raise_when_missing: bool = True) -> Optional[InfrahubNodeSync]: + def get(self, key: str, kind: str | None = None, raise_when_missing: bool = True) -> InfrahubNodeSync | None: return self._get(key=key, kind=kind, raise_when_missing=raise_when_missing) @overload def get_by_hfid(self, key: str, raise_when_missing: Literal[True] = True) -> InfrahubNodeSync: ... @overload - def get_by_hfid(self, key: str, raise_when_missing: Literal[False] = False) -> Optional[InfrahubNodeSync]: ... + def get_by_hfid(self, key: str, raise_when_missing: Literal[False] = False) -> InfrahubNodeSync | None: ... - def get_by_hfid(self, key: str, raise_when_missing: bool = True) -> Optional[InfrahubNodeSync]: + def get_by_hfid(self, key: str, raise_when_missing: bool = True) -> InfrahubNodeSync | None: return self._get_by_hfid(key=key, raise_when_missing=raise_when_missing) - def set(self, node: InfrahubNodeSync, key: Optional[str] = None) -> None: + def set(self, node: InfrahubNodeSync, key: str | None = None) -> None: return self._set(node=node, key=key) diff --git a/infrahub_sdk/task_report.py b/infrahub_sdk/task_report.py index f2130895..317c296a 100644 --- a/infrahub_sdk/task_report.py +++ b/infrahub_sdk/task_report.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Final, Optional, Protocol, TypedDict, Union, runtime_checkable +from typing import TYPE_CHECKING, Any, Final, Protocol, TypedDict, Union, runtime_checkable from typing_extensions import Self @@ -27,8 +27,8 @@ def __init__( logger: InfrahubLogger, related_node: str, title: str, - task_id: Optional[str] = None, - created_by: Optional[str] = None, + task_id: str | None = None, + created_by: str | None = None, create_with_context: bool = True, ): self.client = client @@ -49,9 +49,9 @@ async def __aenter__(self) -> Self: async def __aexit__( self, - exc_type: Optional[type[BaseException]], - exc_value: Optional[BaseException], - traceback: Optional[TracebackType], + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, ) -> None: if exc_type: self.finalized = True @@ -63,9 +63,7 @@ async def __aexit__( conclusion = "FAILURE" if self.has_failures else "SUCCESS" await self.update(conclusion=conclusion) - async def create( - self, title: Optional[str] = None, conclusion: str = "UNKNOWN", logs: Optional[TaskLogs] = None - ) -> None: + async def create(self, title: str | None = None, conclusion: str = "UNKNOWN", logs: TaskLogs | None = None) -> None: variables: dict[str, Any] = { "related_node": self.related_node, "task_id": self.task_id, @@ -107,13 +105,13 @@ async def exception(self, event: str, *args: Any, **kw: Any) -> None: await self.update(logs={"severity": "CRITICAL", "message": event}) async def finalise( - self, title: Optional[str] = None, conclusion: str = "SUCCESS", logs: Optional[TaskLogs] = None + self, title: str | None = None, conclusion: str = "SUCCESS", logs: TaskLogs | None = None ) -> None: self.finalized = True await self.update(title=title, conclusion=conclusion, logs=logs) async def update( - self, title: Optional[str] = None, conclusion: Optional[str] = None, logs: Optional[TaskLogs] = None + self, title: str | None = None, conclusion: str | None = None, logs: TaskLogs | None = None ) -> None: if not self.created: await self.create() @@ -128,40 +126,40 @@ async def update( class InfrahubLogger(Protocol): - def debug(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def debug(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a debug event""" - def info(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def info(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an info event""" - def warning(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def warning(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a warning event""" - def error(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def error(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an error event.""" - def critical(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def critical(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a critical event.""" - def exception(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def exception(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an exception event.""" @runtime_checkable class InfrahubTaskReportLogger(Protocol): - async def info(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + async def info(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an info event""" - async def warning(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + async def warning(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a warning event""" - async def error(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + async def error(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an error event.""" - async def critical(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + async def critical(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a critical event.""" - async def exception(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + async def exception(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an exception event.""" diff --git a/infrahub_sdk/testing/repository.py b/infrahub_sdk/testing/repository.py index 28d770a3..dcdb7875 100644 --- a/infrahub_sdk/testing/repository.py +++ b/infrahub_sdk/testing/repository.py @@ -1,16 +1,20 @@ +from __future__ import annotations + import asyncio import shutil from dataclasses import dataclass, field from enum import Enum from pathlib import Path -from typing import Optional +from typing import TYPE_CHECKING from git.repo import Repo -from infrahub_sdk import InfrahubClient from infrahub_sdk.graphql import Mutation from infrahub_sdk.protocols import CoreGenericRepository +if TYPE_CHECKING: + from infrahub_sdk import InfrahubClient + # NOTE we shouldn't duplicate this, need to figure out a better solution class RepositorySyncStatus(str, Enum): @@ -33,7 +37,7 @@ class GitRepo: type: GitRepoType = GitRepoType.INTEGRATED - _repo: Optional[Repo] = None + _repo: Repo | None = None initial_branch: str = "main" directories_to_ignore: list[str] = field(default_factory=list) remote_directory_name: str = "/remote" @@ -65,7 +69,7 @@ def init(self) -> None: self.repo.git.checkout(self.initial_branch) - async def add_to_infrahub(self, client: InfrahubClient, branch: Optional[str] = None) -> dict: + async def add_to_infrahub(self, client: InfrahubClient, branch: str | None = None) -> dict: input_data = { "data": { "name": {"value": self.name}, @@ -84,7 +88,7 @@ async def add_to_infrahub(self, client: InfrahubClient, branch: Optional[str] = ) async def wait_for_sync_to_complete( - self, client: InfrahubClient, branch: Optional[str] = None, interval: int = 5, retries: int = 6 + self, client: InfrahubClient, branch: str | None = None, interval: int = 5, retries: int = 6 ) -> bool: for _ in range(retries): repo = await client.get( diff --git a/infrahub_sdk/timestamp.py b/infrahub_sdk/timestamp.py index d85dcbed..5a2f58d5 100644 --- a/infrahub_sdk/timestamp.py +++ b/infrahub_sdk/timestamp.py @@ -1,7 +1,6 @@ from __future__ import annotations import re -from typing import Optional, Union import pendulum from pendulum.datetime import DateTime @@ -17,7 +16,7 @@ class TimestampFormatError(ValueError): ... class Timestamp: - def __init__(self, value: Optional[Union[str, DateTime, Timestamp]] = None): + def __init__(self, value: str | DateTime | Timestamp | None = None): if value and isinstance(value, DateTime): self.obj = value elif value and isinstance(value, self.__class__): diff --git a/infrahub_sdk/transfer/exporter/interface.py b/infrahub_sdk/transfer/exporter/interface.py index 3a46027c..dcc90682 100644 --- a/infrahub_sdk/transfer/exporter/interface.py +++ b/infrahub_sdk/transfer/exporter/interface.py @@ -1,10 +1,11 @@ +from __future__ import annotations + from abc import ABC, abstractmethod from pathlib import Path -from typing import Optional class ExporterInterface(ABC): @abstractmethod async def export( - self, export_directory: Path, namespaces: list[str], branch: str, exclude: Optional[list[str]] = None + self, export_directory: Path, namespaces: list[str], branch: str, exclude: list[str] | None = None ) -> None: ... diff --git a/infrahub_sdk/transfer/exporter/json.py b/infrahub_sdk/transfer/exporter/json.py index fadda9b2..1234b931 100644 --- a/infrahub_sdk/transfer/exporter/json.py +++ b/infrahub_sdk/transfer/exporter/json.py @@ -1,13 +1,13 @@ +from __future__ import annotations + from collections.abc import Generator from contextlib import contextmanager from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import ujson -from rich.console import Console from rich.progress import Progress -from ...client import InfrahubClient from ...queries import QUERY_RELATIONSHIPS from ...schema import MainSchemaTypesAPI, NodeSchemaAPI from ..constants import ILLEGAL_NAMESPACES @@ -15,11 +15,14 @@ from .interface import ExporterInterface if TYPE_CHECKING: + from rich.console import Console + + from ...client import InfrahubClient from ...node import InfrahubNode class LineDelimitedJSONExporter(ExporterInterface): - def __init__(self, client: InfrahubClient, console: Optional[Console] = None): + def __init__(self, client: InfrahubClient, console: Console | None = None): self.client = client self.console = console @@ -96,7 +99,7 @@ async def retrieve_many_to_many_relationships( # FIXME: Split in smaller functions async def export( # pylint: disable=too-many-branches - self, export_directory: Path, namespaces: list[str], branch: str, exclude: Optional[list[str]] = None + self, export_directory: Path, namespaces: list[str], branch: str, exclude: list[str] | None = None ) -> None: illegal_namespaces = set(ILLEGAL_NAMESPACES) node_file = export_directory / "nodes.json" diff --git a/infrahub_sdk/transfer/importer/json.py b/infrahub_sdk/transfer/importer/json.py index 752cd2cd..9803d338 100644 --- a/infrahub_sdk/transfer/importer/json.py +++ b/infrahub_sdk/transfer/importer/json.py @@ -1,24 +1,27 @@ +from __future__ import annotations + from collections import defaultdict from collections.abc import Generator, Mapping, Sequence from contextlib import contextmanager from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any import pyarrow.json as pa_json import ujson -from rich.console import Console from rich.progress import Progress -from ...batch import InfrahubBatch -from ...client import InfrahubClient from ...exceptions import GraphQLError from ...node import InfrahubNode, RelatedNode, RelationshipManager -from ...transfer.schema_sorter import InfrahubSchemaTopologicalSorter from ..exceptions import TransferFileNotFoundError from .interface import ImporterInterface if TYPE_CHECKING: + from rich.console import Console + + from ...batch import InfrahubBatch + from ...client import InfrahubClient from ...schema import NodeSchema, RelationshipSchema + from ...transfer.schema_sorter import InfrahubSchemaTopologicalSorter class LineDelimitedJSONImporter(ImporterInterface): @@ -27,7 +30,7 @@ def __init__( client: InfrahubClient, topological_sorter: InfrahubSchemaTopologicalSorter, continue_on_error: bool = False, - console: Optional[Console] = None, + console: Console | None = None, ): self.client = client self.topological_sorter = topological_sorter diff --git a/infrahub_sdk/transfer/schema_sorter.py b/infrahub_sdk/transfer/schema_sorter.py index 8b4c5d85..fc1ba34d 100644 --- a/infrahub_sdk/transfer/schema_sorter.py +++ b/infrahub_sdk/transfer/schema_sorter.py @@ -1,17 +1,21 @@ +from __future__ import annotations + from collections.abc import Sequence -from typing import Optional +from typing import TYPE_CHECKING -from ..schema import NodeSchema from ..topological_sort import DependencyCycleExistsError, topological_sort from .exceptions import SchemaImportError +if TYPE_CHECKING: + from ..schema import NodeSchema + class InfrahubSchemaTopologicalSorter: def get_sorted_node_schema( self, schemas: Sequence[NodeSchema], required_relationships_only: bool = True, - include: Optional[list[str]] = None, + include: list[str] | None = None, ) -> list[set[str]]: relationship_graph: dict[str, set[str]] = {} for node_schema in schemas: diff --git a/infrahub_sdk/transforms.py b/infrahub_sdk/transforms.py index eb145783..c7270825 100644 --- a/infrahub_sdk/transforms.py +++ b/infrahub_sdk/transforms.py @@ -4,7 +4,7 @@ import importlib import os from abc import abstractmethod -from typing import TYPE_CHECKING, Any, Optional +from typing import TYPE_CHECKING, Any from git import Repo @@ -20,7 +20,7 @@ class InfrahubTransform: - name: Optional[str] = None + name: str | None = None query: str timeout: int = 10 @@ -29,7 +29,7 @@ def __init__( branch: str = "", root_directory: str = "", server_url: str = "", - client: Optional[InfrahubClient] = None, + client: InfrahubClient | None = None, ): self.git: Repo @@ -75,7 +75,7 @@ async def collect_data(self) -> dict: return await self.client.query_gql_query(name=self.query, branch_name=self.branch_name) - async def run(self, data: Optional[dict] = None) -> Any: + async def run(self, data: dict | None = None) -> Any: """Execute the transformation after collecting the data from the GraphQL query. The result of the check is determined based on the presence or not of ERROR log messages. @@ -99,9 +99,9 @@ async def run(self, data: Optional[dict] = None) -> Any: def get_transform_class_instance( transform_config: InfrahubPythonTransformConfig, - search_path: Optional[Path] = None, + search_path: Path | None = None, branch: str = "", - client: Optional[InfrahubClient] = None, + client: InfrahubClient | None = None, ) -> InfrahubTransform: """Gets an instance of the InfrahubTransform class. diff --git a/infrahub_sdk/types.py b/infrahub_sdk/types.py index 481103f6..e885d2dc 100644 --- a/infrahub_sdk/types.py +++ b/infrahub_sdk/types.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import enum from logging import Logger -from typing import Any, Optional, Protocol, Union, runtime_checkable +from typing import TYPE_CHECKING, Any, Protocol, Union, runtime_checkable -import httpx +if TYPE_CHECKING: + import httpx class HTTPMethod(str, enum.Enum): @@ -23,7 +26,7 @@ def __call__( method: HTTPMethod, headers: dict[str, Any], timeout: int, - payload: Optional[dict] = None, + payload: dict | None = None, ) -> httpx.Response: ... @@ -35,28 +38,28 @@ async def __call__( method: HTTPMethod, headers: dict[str, Any], timeout: int, - payload: Optional[dict] = None, + payload: dict | None = None, ) -> httpx.Response: ... @runtime_checkable class InfrahubLogger(Protocol): - def debug(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def debug(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a debug event""" - def info(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def info(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an info event""" - def warning(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def warning(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a warning event""" - def error(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def error(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an error event.""" - def critical(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def critical(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send a critical event.""" - def exception(self, event: Optional[str] = None, *args: Any, **kw: Any) -> Any: + def exception(self, event: str | None = None, *args: Any, **kw: Any) -> Any: """Send an exception event.""" diff --git a/infrahub_sdk/utils.py b/infrahub_sdk/utils.py index ae2e8800..339c66ea 100644 --- a/infrahub_sdk/utils.py +++ b/infrahub_sdk/utils.py @@ -4,7 +4,7 @@ import json from itertools import groupby from pathlib import Path -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Any from uuid import UUID, uuid4 import httpx @@ -125,7 +125,7 @@ def compare_lists(list1: list[Any], list2: list[Any]) -> tuple[list[Any], list[A return sorted(in_both), sorted(in_list_1), sorted(in_list_2) -def deep_merge_dict(dicta: dict, dictb: dict, path: Optional[list] = None) -> dict: +def deep_merge_dict(dicta: dict, dictb: dict, path: list | None = None) -> dict: """Deep Merge Dictionary B into Dictionary A. Code is inspired by https://stackoverflow.com/a/7205107 """ @@ -226,7 +226,7 @@ def is_valid_url(url: str) -> bool: return False -def find_files(extension: Union[str, list[str]], directory: Union[str, Path] = ".") -> list[Path]: +def find_files(extension: str | list[str], directory: str | Path = ".") -> list[Path]: files: list[Path] = [] if isinstance(extension, str): @@ -241,7 +241,7 @@ def find_files(extension: Union[str, list[str]], directory: Union[str, Path] = " return files -def get_branch(branch: Optional[str] = None, directory: Union[str, Path] = ".") -> str: +def get_branch(branch: str | None = None, directory: str | Path = ".") -> str: """If branch isn't provide, return the name of the local Git branch.""" if branch: return branch @@ -276,7 +276,7 @@ def calculate_dict_height(data: dict, cnt: int = 0) -> int: return cnt -async def extract_fields(selection_set: Optional[SelectionSetNode]) -> Optional[dict[str, dict]]: +async def extract_fields(selection_set: SelectionSetNode | None) -> dict[str, dict] | None: """This function extract all the requested fields in a tree of Dict from a SelectionSetNode The goal of this function is to limit the fields that we need to query from the backend. diff --git a/infrahub_sdk/uuidt.py b/infrahub_sdk/uuidt.py index 1aa39307..2a0efdb4 100644 --- a/infrahub_sdk/uuidt.py +++ b/infrahub_sdk/uuidt.py @@ -4,7 +4,6 @@ import socket import time from pathlib import Path -from typing import Optional from uuid import UUID from .utils import base16encode @@ -36,10 +35,10 @@ def encode_number(number: int, min_length: int) -> str: class UUIDT: def __init__( self, - namespace: Optional[str] = None, - timestamp: Optional[int] = None, - hostname: Optional[str] = None, - random_chars: Optional[str] = None, + namespace: str | None = None, + timestamp: int | None = None, + hostname: str | None = None, + random_chars: str | None = None, ) -> None: self.namespace = namespace or DEFAULT_NAMESPACE self.timestamp = timestamp or time.time_ns() @@ -61,5 +60,5 @@ def short(self) -> str: return str(self)[-8:] @classmethod - def new(cls, namespace: Optional[str] = None) -> UUID: + def new(cls, namespace: str | None = None) -> UUID: return UUID(str(cls(namespace=namespace))) diff --git a/infrahub_sdk/yaml.py b/infrahub_sdk/yaml.py index 92ebeed4..5cfd5bce 100644 --- a/infrahub_sdk/yaml.py +++ b/infrahub_sdk/yaml.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from enum import Enum from pathlib import Path -from typing import Any, Optional +from typing import Any import yaml from pydantic import BaseModel, Field @@ -24,15 +26,15 @@ class InfrahubFileData(BaseModel): api_version: InfrahubFileApiVersion = Field(InfrahubFileApiVersion.V1, alias="apiVersion") kind: InfrahubFileKind spec: dict - metadata: Optional[dict] = Field(default_factory=dict) + metadata: dict | None = Field(default_factory=dict) class LocalFile(BaseModel): - identifier: Optional[str] = None + identifier: str | None = None location: Path - content: Optional[dict] = None + content: dict | None = None valid: bool = True - error_message: Optional[str] = None + error_message: str | None = None class YamlFile(LocalFile): @@ -77,7 +79,7 @@ def load_from_disk(cls, paths: list[Path]) -> list[Self]: class InfrahubFile(YamlFile): - _data: Optional[InfrahubFileData] = None + _data: InfrahubFileData | None = None @property def data(self) -> InfrahubFileData: diff --git a/poetry.lock b/poetry.lock index 68ba393d..06a1762f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -357,6 +357,20 @@ docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] ssh = ["paramiko (>=2.4.3)"] websockets = ["websocket-client (>=1.3.0)"] +[[package]] +name = "eval-type-backport" +version = "0.2.2" +description = "Like `typing._eval_type`, but lets older Python versions use newer typing features." +optional = false +python-versions = ">=3.8" +files = [ + {file = "eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"}, + {file = "eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -2261,4 +2275,4 @@ tests = ["Jinja2", "pytest", "pyyaml", "rich"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "03566b615c5d853f4a90a262c472fb5e0260108bd1a99cd0fa902eb93aeef2bb" +content-hash = "cae97798f6142170ad6b96630b186ed082a57bda016b5ec3b05aa346462b050a" diff --git a/pyproject.toml b/pyproject.toml index 6d21d410..5f70c19f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ toml = { version = "^0.10", optional = true } typer = { version = "^0.12.3", optional = true } pytest = { version = "*", optional = true } pyyaml = { version = "^6", optional = true } +eval-type-backport = { version = "^0.2.2", python = "~3.9" } [tool.poetry.group.dev.dependencies] pytest = "*" @@ -217,16 +218,15 @@ ignore = [ "CPY", # flake8-copyright "T201", # use of `print` "ISC", # flake8-implicit-str-concat + "COM812", # missing-trailing-comma ################################################################################################## # Rules below needs to be Investigated # ################################################################################################## - "COM", # flake8-commas "ARG", # flake8-unused-arguments "PT", # flake8-pytest-style "PGH", # pygrep-hooks "ERA", # eradicate commented-out code - "FA", # flake8-future-annotations "SLF001", # flake8-self "EM", # flake8-errmsg "TRY", # tryceratops @@ -245,7 +245,7 @@ ignore = [ # like this so that we can reactivate them one by one. Alternatively ignored after further # # investigation if they are deemed to not make sense. # ################################################################################################## - "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 + "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 "C408", # Unnecessary `dict` call (rewrite as a literal) "FURB110", # Replace ternary `if` expression with `or` operator @@ -282,10 +282,7 @@ ignore = [ "SIM118", # Use `key in dict` instead of `key in dict.keys) "SIM910", # Use `data.get(key)` instead of `data.get(key, None)` "TCH003", # Move standard library import `collections.abc.Iterable` into a type-checking block - "UP006", # Use `dict` instead of `Dict` for type annotation - "UP007", # Use X | Y for type annotations "UP031", # Use format specifiers instead of percent format - "UP035", # `typing.Dict` is deprecated, use `dict` instead ] diff --git a/tests/unit/ctl/test_cli.py b/tests/unit/ctl/test_cli.py index 8132305b..a6df7f9e 100644 --- a/tests/unit/ctl/test_cli.py +++ b/tests/unit/ctl/test_cli.py @@ -1,10 +1,16 @@ +import sys + +import pytest from typer.testing import CliRunner from infrahub_sdk.ctl.cli import app runner = CliRunner() +requires_python_310 = pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10 or higher") + +@requires_python_310 def test_main_app(): result = runner.invoke(app, ["--help"]) assert result.exit_code == 0 diff --git a/tests/unit/ctl/test_repository_app.py b/tests/unit/ctl/test_repository_app.py index fd558dc2..6b14d866 100644 --- a/tests/unit/ctl/test_repository_app.py +++ b/tests/unit/ctl/test_repository_app.py @@ -1,5 +1,6 @@ """Integration tests for infrahubctl commands.""" +import sys from unittest import mock import pytest @@ -10,6 +11,8 @@ runner = CliRunner() +requires_python_310 = pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10 or higher") + @pytest.fixture def mock_client() -> mock.Mock: @@ -25,6 +28,7 @@ def mock_client() -> mock.Mock: class TestInfrahubctlRepository: """Groups the 'infrahubctl repository' test cases.""" + @requires_python_310 def test_repo_no_username(self, mock_init_client, mock_client) -> None: """Case allow no username to be passed in and set it as None rather than blank string that fails.""" mock_cred = mock.AsyncMock() @@ -84,6 +88,7 @@ def test_repo_no_username(self, mock_init_client, mock_client) -> None: tracker="mutation-repository-create", ) + @requires_python_310 def test_repo_username(self, mock_init_client, mock_client) -> None: """Case allow no username to be passed in and set it as None rather than blank string that fails.""" mock_cred = mock.AsyncMock() @@ -145,6 +150,7 @@ def test_repo_username(self, mock_init_client, mock_client) -> None: tracker="mutation-repository-create", ) + @requires_python_310 def test_repo_readonly_true(self, mock_init_client, mock_client) -> None: """Case allow no username to be passed in and set it as None rather than blank string that fails.""" mock_cred = mock.AsyncMock() @@ -205,6 +211,7 @@ def test_repo_readonly_true(self, mock_init_client, mock_client) -> None: tracker="mutation-repository-create", ) + @requires_python_310 def test_repo_description_commit_branch(self, mock_init_client, mock_client) -> None: """Case allow no username to be passed in and set it as None rather than blank string that fails.""" mock_cred = mock.AsyncMock() diff --git a/tests/unit/ctl/test_transform_app.py b/tests/unit/ctl/test_transform_app.py index a9fead5e..ea452893 100644 --- a/tests/unit/ctl/test_transform_app.py +++ b/tests/unit/ctl/test_transform_app.py @@ -22,6 +22,8 @@ Path(os.path.abspath(__file__)).parent / ".." / ".." / "fixtures" / "integration" / "test_infrahubctl" ) +requires_python_310 = pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10 or higher") + def read_fixture(file_name: str, fixture_subdir: str = ".") -> str: """Read the contents of a fixture.""" @@ -57,6 +59,7 @@ class TestInfrahubctlTransform: """Groups the 'infrahubctl transform' test cases.""" @staticmethod + @requires_python_310 def test_transform_not_exist_in_infrahub_yml(tags_transform_dir: str) -> None: """Case transform is not specified in the infrahub.yml file.""" transform_name = "not_existing_transform" @@ -66,7 +69,7 @@ def test_transform_not_exist_in_infrahub_yml(tags_transform_dir: str) -> None: assert output.exit_code == 1 @staticmethod - @pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher") + @requires_python_310 def test_transform_python_file_not_defined(tags_transform_dir: str) -> None: """Case transform python file not defined.""" # Remove transform file @@ -81,7 +84,7 @@ def test_transform_python_file_not_defined(tags_transform_dir: str) -> None: assert output.exit_code == 1 @staticmethod - @pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher") + @requires_python_310 def test_transform_python_class_not_defined(tags_transform_dir: str) -> None: """Case transform python class not defined.""" # Rename transform inside of python file so the class name searched for no longer exists @@ -101,7 +104,7 @@ def test_transform_python_class_not_defined(tags_transform_dir: str) -> None: assert output.exit_code == 1 @staticmethod - @pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher") + @requires_python_310 def test_gql_query_not_defined(tags_transform_dir: str) -> None: """Case GraphQL Query is not defined""" # Remove GraphQL Query file @@ -115,7 +118,7 @@ def test_gql_query_not_defined(tags_transform_dir: str) -> None: assert output.exit_code == 1 @staticmethod - @pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher") + @requires_python_310 def test_infrahubctl_transform_cmd_success(httpx_mock: HTTPXMock, tags_transform_dir: str) -> None: """Case infrahubctl transform command executes successfully""" httpx_mock.add_response( diff --git a/tests/unit/ctl/test_validate_app.py b/tests/unit/ctl/test_validate_app.py index 43d41ddb..3264b087 100644 --- a/tests/unit/ctl/test_validate_app.py +++ b/tests/unit/ctl/test_validate_app.py @@ -1,3 +1,5 @@ +import sys + import pytest from typer.testing import CliRunner @@ -7,7 +9,10 @@ runner = CliRunner() +requires_python_310 = pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10 or higher") + +@requires_python_310 def test_validate_schema_valid(): fixture_file = get_fixtures_dir() / "models" / "valid_model_01.json" @@ -16,6 +21,7 @@ def test_validate_schema_valid(): assert "Schema is valid" in result.stdout +@requires_python_310 def test_validate_schema_empty(): fixture_file = get_fixtures_dir() / "models" / "empty.json" @@ -24,6 +30,7 @@ def test_validate_schema_empty(): assert "Empty YAML/JSON file" in remove_ansi_color(result.stdout) +@requires_python_310 def test_validate_schema_non_valid(): fixture_file = get_fixtures_dir() / "models" / "non_valid_model_01.json" diff --git a/tests/unit/sdk/conftest.py b/tests/unit/sdk/conftest.py index 18279afa..1710fef7 100644 --- a/tests/unit/sdk/conftest.py +++ b/tests/unit/sdk/conftest.py @@ -1,19 +1,23 @@ +from __future__ import annotations + import re import sys from collections.abc import AsyncGenerator, Mapping from dataclasses import dataclass from inspect import Parameter from io import StringIO -from typing import Optional +from typing import TYPE_CHECKING import pytest import ujson -from pytest_httpx import HTTPXMock from infrahub_sdk import Config, InfrahubClient, InfrahubClientSync from infrahub_sdk.schema import BranchSupportType, NodeSchema, NodeSchemaAPI from infrahub_sdk.utils import get_fixtures_dir +if TYPE_CHECKING: + from pytest_httpx import HTTPXMock + # pylint: disable=redefined-outer-name,unused-argument @@ -21,7 +25,7 @@ class BothClients: sync: InfrahubClientSync standard: InfrahubClient - stdout: Optional[StringIO] = None + stdout: StringIO | None = None @pytest.fixture @@ -72,6 +76,14 @@ def return_annotation_map() -> dict[str, str]: "Optional[type[SchemaType]]": "Optional[type[SchemaTypeSync]]", "Optional[Union[CoreNode, SchemaType]]": "Optional[Union[CoreNodeSync, SchemaTypeSync]]", "InfrahubBatch": "InfrahubBatchSync", + "CoreNode | None": "CoreNodeSync | None", + "str | type[SchemaType]": "str | type[SchemaTypeSync]", + "InfrahubNode | SchemaType": "InfrahubNodeSync | SchemaTypeSync", + "InfrahubNode | SchemaType | None": "InfrahubNodeSync | SchemaTypeSync | None", + "list[InfrahubNode] | list[SchemaType]": "list[InfrahubNodeSync] | list[SchemaTypeSync]", + "InfrahubNode | None": "InfrahubNodeSync | None", + "type[SchemaType] | None": "type[SchemaTypeSync] | None", + "CoreNode | SchemaType | None": "CoreNodeSync | SchemaTypeSync | None", }