diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1c393efd..537c7969 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.14.10 + rev: v0.11.9 hooks: # Run the linter. - id: ruff diff --git a/infrahub_sdk/ctl/branch.py b/infrahub_sdk/ctl/branch.py index d169cb91..60d67e86 100644 --- a/infrahub_sdk/ctl/branch.py +++ b/infrahub_sdk/ctl/branch.py @@ -293,7 +293,7 @@ async def report( git_files_changed = await check_git_files_changed(client, branch=branch_name) proposed_changes = await client.filters( - kind=CoreProposedChange, + kind=CoreProposedChange, # type: ignore[type-abstract] source_branch__value=branch_name, include=["created_by"], prefetch_relationships=True, diff --git a/infrahub_sdk/node/related_node.py b/infrahub_sdk/node/related_node.py index 67171f99..5b46a8f7 100644 --- a/infrahub_sdk/node/related_node.py +++ b/infrahub_sdk/node/related_node.py @@ -1,7 +1,7 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, Any, cast +from typing import TYPE_CHECKING, Any from ..exceptions import Error from ..protocols_base import CoreNodeBase @@ -11,7 +11,7 @@ if TYPE_CHECKING: from ..client import InfrahubClient, InfrahubClientSync from ..schema import RelationshipSchemaAPI - from .node import InfrahubNode, InfrahubNodeBase, InfrahubNodeSync + from .node import InfrahubNode, InfrahubNodeSync class RelatedNodeBase: @@ -34,7 +34,7 @@ def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Any | dict, self._properties_object = PROPERTIES_OBJECT self._properties = self._properties_flag + self._properties_object - self._peer: InfrahubNodeBase | CoreNodeBase | None = None + self._peer = None self._id: str | None = None self._hfid: list[str] | None = None self._display_label: str | None = None @@ -43,10 +43,8 @@ def __init__(self, branch: str, schema: RelationshipSchemaAPI, data: Any | dict, self._source_typename: str | None = None self._relationship_metadata: RelationshipMetadata | None = None - # Check for InfrahubNodeBase instances using duck-typing (_schema attribute) - # to avoid circular imports, or CoreNodeBase instances - if isinstance(data, CoreNodeBase) or hasattr(data, "_schema"): - self._peer = cast("InfrahubNodeBase | CoreNodeBase", data) + if isinstance(data, (CoreNodeBase)): + self._peer = data for prop in self._properties: setattr(self, prop, None) self._relationship_metadata = None diff --git a/infrahub_sdk/protocols_base.py b/infrahub_sdk/protocols_base.py index ba920552..8a841b5b 100644 --- a/infrahub_sdk/protocols_base.py +++ b/infrahub_sdk/protocols_base.py @@ -171,7 +171,8 @@ class AnyAttributeOptional(Attribute): value: float | None -class CoreNodeBase: +@runtime_checkable +class CoreNodeBase(Protocol): _schema: MainSchemaTypes _internal_id: str id: str # NOTE this is incorrect, should be str | None @@ -188,28 +189,23 @@ def get_human_friendly_id(self) -> list[str] | None: ... def get_human_friendly_id_as_string(self, include_kind: bool = False) -> str | None: ... - def get_kind(self) -> str: - raise NotImplementedError() + def get_kind(self) -> str: ... - def get_all_kinds(self) -> list[str]: - raise NotImplementedError() + def get_all_kinds(self) -> list[str]: ... - def get_branch(self) -> str: - raise NotImplementedError() + def get_branch(self) -> str: ... - def is_ip_prefix(self) -> bool: - raise NotImplementedError() + def is_ip_prefix(self) -> bool: ... - def is_ip_address(self) -> bool: - raise NotImplementedError() + def is_ip_address(self) -> bool: ... - def is_resource_pool(self) -> bool: - raise NotImplementedError() + def is_resource_pool(self) -> bool: ... def get_raw_graphql_data(self) -> dict | None: ... -class CoreNode(CoreNodeBase): +@runtime_checkable +class CoreNode(CoreNodeBase, Protocol): async def save( self, allow_upsert: bool = False, @@ -233,7 +229,8 @@ async def add_relationships(self, relation_to_update: str, related_nodes: list[s async def remove_relationships(self, relation_to_update: str, related_nodes: list[str]) -> None: ... -class CoreNodeSync(CoreNodeBase): +@runtime_checkable +class CoreNodeSync(CoreNodeBase, Protocol): def save( self, allow_upsert: bool = False, diff --git a/infrahub_sdk/schema/__init__.py b/infrahub_sdk/schema/__init__.py index febb204b..3e61ad2a 100644 --- a/infrahub_sdk/schema/__init__.py +++ b/infrahub_sdk/schema/__init__.py @@ -21,7 +21,6 @@ ValidationError, ) from ..graphql import Mutation -from ..protocols_base import CoreNodeBase from ..queries import SCHEMA_HASH_SYNC_STATUS from .main import ( AttributeSchema, @@ -208,14 +207,14 @@ def _get_schema_name(schema: type[SchemaType | SchemaTypeSync] | str) -> str: if isinstance(schema, str): return schema - if issubclass(schema, CoreNodeBase): + if hasattr(schema, "_is_runtime_protocol") and getattr(schema, "_is_runtime_protocol", None): if inspect.iscoroutinefunction(schema.save): return schema.__name__ if schema.__name__[-4:] == "Sync": return schema.__name__[:-4] return schema.__name__ - raise ValueError("schema must be a CoreNode subclass or a string") + raise ValueError("schema must be a protocol or a string") @staticmethod def _parse_schema_response(response: httpx.Response, branch: str) -> MutableMapping[str, Any]: diff --git a/infrahub_sdk/testing/repository.py b/infrahub_sdk/testing/repository.py index d07d2b1a..9e974164 100644 --- a/infrahub_sdk/testing/repository.py +++ b/infrahub_sdk/testing/repository.py @@ -98,7 +98,7 @@ async def wait_for_sync_to_complete( ) -> bool: for _ in range(retries): repo = await client.get( - kind=CoreGenericRepository, + kind=CoreGenericRepository, # type: ignore[type-abstract] name__value=self.name, branch=branch or self.initial_branch, )