From f42cc6cdef723ad21cc7b1087e24df7b5b1362d7 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sun, 6 Oct 2024 07:50:02 +0200 Subject: [PATCH 1/5] tmp: happy mypy locally --- cognite/client/data_classes/assets.py | 2 +- cognite/client/utils/_concurrency.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cognite/client/data_classes/assets.py b/cognite/client/data_classes/assets.py index 146fa83998..beb3b3a9ae 100644 --- a/cognite/client/data_classes/assets.py +++ b/cognite/client/data_classes/assets.py @@ -890,7 +890,7 @@ def _count_subtree(xid: str, count: int = 0) -> int: counts.sort(key=lambda args: -args[-1]) # The count for the fictitious "root of roots" is just len(assets), so we remove it: (count_dct := dict(counts)).pop(None, None) - return count_dct + return count_dct # type: ignore[return-value] def _on_error(self, on_error: Literal["ignore", "warn", "raise"], message: str) -> None: if on_error == "warn": diff --git a/cognite/client/utils/_concurrency.py b/cognite/client/utils/_concurrency.py index e0684ad66e..b3277ab5a4 100644 --- a/cognite/client/utils/_concurrency.py +++ b/cognite/client/utils/_concurrency.py @@ -184,7 +184,7 @@ def uses_mainthread(cls) -> bool: @classmethod def get_executor(cls, max_workers: int) -> TaskExecutor: if cls.uses_threadpool(): - return cls.get_thread_pool_executor(max_workers) + return cls.get_thread_pool_executor(max_workers) # type: ignore[return-value] elif cls.uses_mainthread(): return cls.get_mainthread_executor() raise RuntimeError(f"Invalid executor type '{cls.executor_type}'") From 8e936c227f7a8f7bd378457e5eef9cdc69575c50 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sun, 6 Oct 2024 07:51:23 +0200 Subject: [PATCH 2/5] refactor: generated data and api classes --- cognite/client/_api/simulators/simulators.py | 133 +++++++ .../data_classes/simulators/simulators.py | 342 ++++++++++++++++++ 2 files changed, 475 insertions(+) create mode 100644 cognite/client/_api/simulators/simulators.py create mode 100644 cognite/client/data_classes/simulators/simulators.py diff --git a/cognite/client/_api/simulators/simulators.py b/cognite/client/_api/simulators/simulators.py new file mode 100644 index 0000000000..24a8e03c0d --- /dev/null +++ b/cognite/client/_api/simulators/simulators.py @@ -0,0 +1,133 @@ +from __future__ import annotations + +from collections.abc import Iterator +from typing import TYPE_CHECKING, Any, Sequence, overload + +from cognite.client._api_client import APIClient +from cognite.client._constants import DEFAULT_LIMIT_READ +from cognite_gen.client.data_classes.simulators.simulators import Simulator, SimulatorList, SimulatorUpdate, SimulatorWrite +from cognite.client.utils._experimental import FeaturePreviewWarning +from cognite.client.utils._identifier import IdentifierSequence +from cognite.client.utils.useful_types import SequenceNotStr + +if TYPE_CHECKING: + from cognite.client import ClientConfig, CogniteClient + + +class SimulatorsAPI(APIClient): + _RESOURCE_PATH = "/simulators" + def __init__(self, config: ClientConfig, api_version: str | None, cognite_client: CogniteClient) -> None: + super().__init__(config, api_version, cognite_client) + self._warning = FeaturePreviewWarning( + api_maturity="beta", sdk_maturity="alpha", feature_name="Simulators" + ) + + def create(self, simulator_create_command: SimulatorWrite | Sequence[SimulatorWrite]) -> Simulator: + """`Create Simulators `_ + + Create a simulator entry in the Simulator Integration framework. + + Args: + simulator_create_command (SimulatorWrite | Sequence[SimulatorWrite]): None + + Returns: + Simulator: None + + Examples: + + Create simulator: + + >>> from cognite.client import CogniteClient + >>> from cognite.client.data_classes.simulators import SimulatorWrite + >>> client = CogniteClient() + >>> simulator = SimulatorWrite() + >>> res = client.hosted_extractors.destinations.create(simulator) + + """ + self._warning.warn() + return self._create_multiple( + list_cls=SimulatorList, + resource_cls=Simulator, + items=simulator_create_command, + input_resource_cls=SimulatorWrite, + headers={"cdf-version": "beta"}, + ) + + def update(self, simulator_update_command: SimulatorUpdate | Sequence[SimulatorUpdate]) -> Simulator: + """`Update Simulators `_ + + Update simulators + + Args: + simulator_update_command (SimulatorUpdate | Sequence[SimulatorUpdate]): None + + Returns: + Simulator: None + + Examples: + + Update simulator: + + >>> from cognite.client import CogniteClient + >>> from cognite.client.data_classes.simulators import SimulatorUpdate + >>> client = CogniteClient() + >>> update = SimulatorUpdate('mySimulator'). + >>> res = client.simulators.update(update) + + """ + self._warning.warn() + return self._update_multiple( + items=simulator_update_command, + list_cls=SimulatorList, + resource_cls=Simulator, + update_cls=SimulatorUpdate, + headers={"cdf-version": "beta"}, + ) + + def delete(self, unknown: Unknown) -> EmptyResponse | None: + """`Delete Simulators `_ + + Delete simulators + + Args: + unknown (Unknown): None + + Returns: + EmptyResponse | None: None + + Examples: + + Delete simulator: + + >>> from cognite.client import CogniteClient + >>> client = CogniteClient() + >>> client.simulators.delete(["mySimulator", "mySimulator2"]) + + + """ + self._warning.warn() + return self._delete_multiple( + identifiers=IdentifierSequence.load(unknowns=unknown), + wrap_ids=False, + returns_items=False, + headers={"cdf-version": "beta"}, + ) + + def filter(self, limit: int, filter: ListSimulatorsFilters | None = None) -> Simulator: + """`Filter Simulators `_ + + List simulators + + Args: + limit (int): None + filter (ListSimulatorsFilters | None): None + + Returns: + Simulator: None + + Examples: + + + + """ + "" diff --git a/cognite/client/data_classes/simulators/simulators.py b/cognite/client/data_classes/simulators/simulators.py new file mode 100644 index 0000000000..cd459d9b2d --- /dev/null +++ b/cognite/client/data_classes/simulators/simulators.py @@ -0,0 +1,342 @@ +from __future__ import annotations + +from abc import ABC +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any, NoReturn, Sequence + +from typing_extensions import Self + +from cognite.client.utils.useful_types import SequenceNotStr +from cognite.client.data_classes._base import ( + CogniteObject, + CognitePrimitiveUpdate, + CogniteResource, + CogniteResourceList, + CogniteUpdate, + ExternalIDTransformerMixin, + PropertySpec, + WriteableCogniteResource, + WriteableCogniteResourceList, +) + +if TYPE_CHECKING: + from cognite.client import CogniteClient + + +@dataclass +class SimulatorUnitEntry(CogniteObject): + label: str + name: str + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + label=resource["label"], + name=resource["name"], + ) + + +@dataclass +class SimulatorStepOption(CogniteObject): + label: str + value: str + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + label=resource["label"], + value=resource["value"], + ) + + + + +@dataclass +class SimulatorModelType(CogniteObject): + name: str + key: str + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + name=resource["name"], + key=resource["key"], + ) + + + + +@dataclass +class SimulatorQuantity(CogniteObject): + name: str + label: str + units: SimulatorUnitEntry | Sequence[SimulatorUnitEntry] + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + name=resource["name"], + label=resource["label"], + units=SimulatorUnitEntry._load(resource["units"], cognite_client), + ) + + def dump(self, camel_case: bool = True) -> dict[str, Any]: + output = super().dump(camel_case=camel_case) + output["units"] = self.units.dump(camel_case=camel_case) + + return output + + + +@dataclass +class SimulatorStepField(CogniteObject): + name: str + label: str + info: str + options: SimulatorStepOption | Sequence[SimulatorStepOption] | None + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + name=resource["name"], + label=resource["label"], + info=resource["info"], + options=SimulatorStepOption._load(resource["options"], cognite_client) if "options" in resource else None, + ) + + def dump(self, camel_case: bool = True) -> dict[str, Any]: + output = super().dump(camel_case=camel_case) + if isinstance(self.options, SimulatorStepOption): + output["options"] = self.options.dump(camel_case=camel_case) + + return output + + + +@dataclass +class SimulatorStep(CogniteObject): + step_type: str + fields: SimulatorStepField | Sequence[SimulatorStepField] + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + step_type=resource["stepType"], + fields=SimulatorStepField._load(resource["fields"], cognite_client), + ) + + def dump(self, camel_case: bool = True) -> dict[str, Any]: + output = super().dump(camel_case=camel_case) + output["fields"] = self.fields.dump(camel_case=camel_case) + + return output + + +class _SimulatorCore(WriteableCogniteResource["SimulatorWrite"], ABC): + def __init__(self, external_id: str, name: str, file_extension_types: str | SequenceNotStr[str], model_types: SimulatorModelType | Sequence[SimulatorModelType], step_fields: SimulatorStep | Sequence[SimulatorStep], unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None) -> None: + self.external_id = external_id + self.name = name + self.file_extension_types = file_extension_types + self.model_types = model_types + self.step_fields = step_fields + self.unit_quantities = unit_quantities + + +class SimulatorWrite(_SimulatorCore): + """The simulator resource contains the definitions necessary for Cognite Data Fusion (CDF) to interact with a given simulator. + + It serves as a central contract that allows APIs, UIs, and integrations (connectors) to utilize the same definitions + when dealing with a specific simulator. Each simulator is uniquely identified and can be associated with various + file extension types, model types, step fields, and unit quantities. Simulators are essential for managing data + flows between CDF and external simulation tools, ensuring consistency and reliability in data handling. #### + Limitations: - A project can have a maximum of 100 simulators + + This is the write/request format of the simulator. + + Args: + external_id (str): External id of the simulator + name (str): Name of the simulator + file_extension_types (str | SequenceNotStr[str]): File extension types supported by the simulator + model_types (SimulatorModelType | Sequence[SimulatorModelType]): Model types supported by the simulator + step_fields (SimulatorStep | Sequence[SimulatorStep]): Step types supported by the simulator when creating routines + unit_quantities (SimulatorQuantity | Sequence[SimulatorQuantity] | None): Quantities and their units supported by the simulator + + """ + + def __init__(self, external_id: str, name: str, file_extension_types: str | SequenceNotStr[str], model_types: SimulatorModelType | Sequence[SimulatorModelType], step_fields: SimulatorStep | Sequence[SimulatorStep], unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None) -> None: + super().__init__( + external_id=external_id, + name=name, + file_extension_types=file_extension_types, + model_types=model_types, + step_fields=step_fields, + unit_quantities=unit_quantities, + ) + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + external_id=resource["externalId"], + name=resource["name"], + file_extension_types=resource["fileExtensionTypes"], + model_types=SimulatorModelType._load(resource["modelTypes"], cognite_client), + step_fields=SimulatorStep._load(resource["stepFields"], cognite_client), + unit_quantities=SimulatorQuantity._load(resource["unitQuantities"], cognite_client) if "unitQuantities" in resource else None, + ) + + def dump(self, camel_case: bool = True) -> dict[str, Any]: + output = super().dump(camel_case=camel_case) + output["modelTypes" if camel_case else "model_types"] = self.model_types.dump(camel_case=camel_case) + output["stepFields" if camel_case else "step_fields"] = self.step_fields.dump(camel_case=camel_case) + if isinstance(self.unit_quantities, SimulatorQuantity): + output["unitQuantities" if camel_case else "unit_quantities"] = self.unit_quantities.dump(camel_case=camel_case) + + return output + def as_write(self) -> SimulatorWrite: + return self + + + +class Simulator(_SimulatorCore): + """The simulator resource contains the definitions necessary for Cognite Data Fusion (CDF) to interact with a given simulator. + + It serves as a central contract that allows APIs, UIs, and integrations (connectors) to utilize the same definitions + when dealing with a specific simulator. Each simulator is uniquely identified and can be associated with various + file extension types, model types, step fields, and unit quantities. Simulators are essential for managing data + flows between CDF and external simulation tools, ensuring consistency and reliability in data handling. #### + Limitations: - A project can have a maximum of 100 simulators + + This is the read/response format of the simulator. + + Args: + id (int): A unique id of a simulator + external_id (str): External id of the simulator + name (str): Name of the simulator + file_extension_types (str | SequenceNotStr[str]): File extension types supported by the simulator + model_types (SimulatorModelType | Sequence[SimulatorModelType] | None): Model types supported by the simulator + step_fields (SimulatorStep | Sequence[SimulatorStep] | None): Step types supported by the simulator when creating routines + unit_quantities (SimulatorQuantity | Sequence[SimulatorQuantity] | None): Quantities and their units supported by the simulator + created_time (int): None + last_updated_time (int): None + + """ + + def __init__(self, id: int, external_id: str, name: str, file_extension_types: str | SequenceNotStr[str], created_time: int, last_updated_time: int, model_types: SimulatorModelType | Sequence[SimulatorModelType] | None = None, step_fields: SimulatorStep | Sequence[SimulatorStep] | None = None, unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None) -> None: + super().__init__( + external_id=external_id, + name=name, + file_extension_types=file_extension_types, + model_types=model_types, + step_fields=step_fields, + unit_quantities=unit_quantities, + ) + self.id = id + self.created_time = created_time + self.last_updated_time = last_updated_time + + @classmethod + def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: + return cls( + id=resource["id"], + external_id=resource["externalId"], + name=resource["name"], + file_extension_types=resource["fileExtensionTypes"], + created_time=resource["createdTime"], + last_updated_time=resource["lastUpdatedTime"], + model_types=SimulatorModelType._load(resource["modelTypes"], cognite_client) if "modelTypes" in resource else None, + step_fields=SimulatorStep._load(resource["stepFields"], cognite_client) if "stepFields" in resource else None, + unit_quantities=SimulatorQuantity._load(resource["unitQuantities"], cognite_client) if "unitQuantities" in resource else None, + ) + + def dump(self, camel_case: bool = True) -> dict[str, Any]: + output = super().dump(camel_case=camel_case) + if isinstance(self.model_types, SimulatorModelType): + output["modelTypes" if camel_case else "model_types"] = self.model_types.dump(camel_case=camel_case) + if isinstance(self.step_fields, SimulatorStep): + output["stepFields" if camel_case else "step_fields"] = self.step_fields.dump(camel_case=camel_case) + if isinstance(self.unit_quantities, SimulatorQuantity): + output["unitQuantities" if camel_case else "unit_quantities"] = self.unit_quantities.dump(camel_case=camel_case) + + return output + + + def as_write(self) -> SimulatorWrite: + return SimulatorWrite( + unit_quantities=self.unit_quantities, + name=self.name, + model_types=self.model_types, + external_id=self.external_id, + step_fields=self.step_fields, + file_extension_types=self.file_extension_types, + ) + + +class SimulatorUpdate(CogniteUpdate): + def __init__(self, id: int) -> None: + super().__init__( + id = id, + ) + + class _UpdateSetAnnotatedStringConstraintsUpdate(CognitePrimitiveUpdate): + def set(self, value: UpdateSetAnnotatedStringConstraints | None) -> SimulatorUpdate: + return self._set(value.dump() if isinstance(value, UpdateSetAnnotatedStringConstraints) else value) + + class _UpdateSetListUpdate(CognitePrimitiveUpdate): + def set(self, value: UpdateSetList | None) -> SimulatorUpdate: + return self._set(value.dump() if isinstance(value, UpdateSetList) else value) + + class _UpdateSetListSimulatorModelTypeUpdate(CognitePrimitiveUpdate): + def set(self, value: UpdateSetListSimulatorModelType | None) -> SimulatorUpdate: + return self._set(value.dump() if isinstance(value, UpdateSetListSimulatorModelType) else value) + + class _UpdateSetListSimulatorStepUpdate(CognitePrimitiveUpdate): + def set(self, value: UpdateSetListSimulatorStep | None) -> SimulatorUpdate: + return self._set(value.dump() if isinstance(value, UpdateSetListSimulatorStep) else value) + + class _UpdateSetList1kSimulatorQuantityUpdate(CognitePrimitiveUpdate): + def set(self, value: UpdateSetList1kSimulatorQuantity | None) -> SimulatorUpdate: + return self._set(value.dump() if isinstance(value, UpdateSetList1kSimulatorQuantity) else value) + + + @property + def name(self) -> SimulatorUpdate._UpdateSetAnnotatedStringConstraintsUpdate: + return self._UpdateSetAnnotatedStringConstraintsUpdate(self, "name") + + @property + def file_extension_types(self) -> SimulatorUpdate._UpdateSetListUpdate: + return self._UpdateSetListUpdate(self, "file_extension_types") + + @property + def model_types(self) -> SimulatorUpdate._UpdateSetListSimulatorModelTypeUpdate: + return self._UpdateSetListSimulatorModelTypeUpdate(self, "model_types") + + @property + def step_fields(self) -> SimulatorUpdate._UpdateSetListSimulatorStepUpdate: + return self._UpdateSetListSimulatorStepUpdate(self, "step_fields") + + @property + def unit_quantities(self) -> SimulatorUpdate._UpdateSetList1kSimulatorQuantityUpdate: + return self._UpdateSetList1kSimulatorQuantityUpdate(self, "unit_quantities") + + + @classmethod + def _get_update_properties(cls, item: CogniteResource | None = None) -> list[PropertySpec]: + return [ + PropertySpec("name", is_nullable=True), + PropertySpec("file_extension_types", is_nullable=True), + PropertySpec("model_types", is_nullable=True), + PropertySpec("step_fields", is_nullable=True), + PropertySpec("unit_quantities", is_nullable=True), + ] + + +class SimulatorWriteList(CogniteResourceList[SimulatorWrite]): + _RESOURCE = SimulatorWrite + + +class SimulatorList(WriteableCogniteResourceList[SimulatorWrite, Simulator]): + _RESOURCE = Simulator + + def as_write(self) -> SimulatorWriteList: + return SimulatorWriteList([item.as_write() for item in self.data]) + From 67f36801ca06834b4630698dce6a6d0e7b5948d9 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sun, 6 Oct 2024 08:01:31 +0200 Subject: [PATCH 3/5] refactor: remove crud methods --- cognite/client/_api/simulators/simulators.py | 121 +------- .../data_classes/simulators/simulators.py | 259 +++++------------- 2 files changed, 76 insertions(+), 304 deletions(-) diff --git a/cognite/client/_api/simulators/simulators.py b/cognite/client/_api/simulators/simulators.py index 24a8e03c0d..5499482e05 100644 --- a/cognite/client/_api/simulators/simulators.py +++ b/cognite/client/_api/simulators/simulators.py @@ -1,14 +1,11 @@ from __future__ import annotations -from collections.abc import Iterator -from typing import TYPE_CHECKING, Any, Sequence, overload +from typing import TYPE_CHECKING from cognite.client._api_client import APIClient from cognite.client._constants import DEFAULT_LIMIT_READ -from cognite_gen.client.data_classes.simulators.simulators import Simulator, SimulatorList, SimulatorUpdate, SimulatorWrite +from cognite.client.data_classes.simulators.simulators import Simulator, SimulatorList from cognite.client.utils._experimental import FeaturePreviewWarning -from cognite.client.utils._identifier import IdentifierSequence -from cognite.client.utils.useful_types import SequenceNotStr if TYPE_CHECKING: from cognite.client import ClientConfig, CogniteClient @@ -16,118 +13,30 @@ class SimulatorsAPI(APIClient): _RESOURCE_PATH = "/simulators" + def __init__(self, config: ClientConfig, api_version: str | None, cognite_client: CogniteClient) -> None: super().__init__(config, api_version, cognite_client) - self._warning = FeaturePreviewWarning( - api_maturity="beta", sdk_maturity="alpha", feature_name="Simulators" - ) - - def create(self, simulator_create_command: SimulatorWrite | Sequence[SimulatorWrite]) -> Simulator: - """`Create Simulators `_ - - Create a simulator entry in the Simulator Integration framework. - - Args: - simulator_create_command (SimulatorWrite | Sequence[SimulatorWrite]): None - - Returns: - Simulator: None - - Examples: - - Create simulator: - - >>> from cognite.client import CogniteClient - >>> from cognite.client.data_classes.simulators import SimulatorWrite - >>> client = CogniteClient() - >>> simulator = SimulatorWrite() - >>> res = client.hosted_extractors.destinations.create(simulator) - - """ - self._warning.warn() - return self._create_multiple( - list_cls=SimulatorList, - resource_cls=Simulator, - items=simulator_create_command, - input_resource_cls=SimulatorWrite, - headers={"cdf-version": "beta"}, - ) - - def update(self, simulator_update_command: SimulatorUpdate | Sequence[SimulatorUpdate]) -> Simulator: - """`Update Simulators `_ - - Update simulators - - Args: - simulator_update_command (SimulatorUpdate | Sequence[SimulatorUpdate]): None - - Returns: - Simulator: None - - Examples: - - Update simulator: - - >>> from cognite.client import CogniteClient - >>> from cognite.client.data_classes.simulators import SimulatorUpdate - >>> client = CogniteClient() - >>> update = SimulatorUpdate('mySimulator'). - >>> res = client.simulators.update(update) + self._warning = FeaturePreviewWarning(api_maturity="beta", sdk_maturity="alpha", feature_name="Simulators") - """ - self._warning.warn() - return self._update_multiple( - items=simulator_update_command, - list_cls=SimulatorList, - resource_cls=Simulator, - update_cls=SimulatorUpdate, - headers={"cdf-version": "beta"}, - ) + def list(self, limit: int = DEFAULT_LIMIT_READ) -> SimulatorList: + """`Filter Simulators `_ - def delete(self, unknown: Unknown) -> EmptyResponse | None: - """`Delete Simulators `_ + List simulators - Delete simulators + Args: + limit (int): The maximum number of simulators to return. Defaults to 25. Set to -1, float("inf") or None - Args: - unknown (Unknown): None - Returns: - EmptyResponse | None: None + SimulatorList: List of simulators Examples: - Delete simulator: - - >>> from cognite.client import CogniteClient - >>> client = CogniteClient() - >>> client.simulators.delete(["mySimulator", "mySimulator2"]) + List simulators: + >>> from cognite.client import CogniteClient + >>> client = CogniteClient() + >>> res = client.simulators.list() """ self._warning.warn() - return self._delete_multiple( - identifiers=IdentifierSequence.load(unknowns=unknown), - wrap_ids=False, - returns_items=False, - headers={"cdf-version": "beta"}, - ) - - def filter(self, limit: int, filter: ListSimulatorsFilters | None = None) -> Simulator: - """`Filter Simulators `_ - - List simulators - - Args: - limit (int): None - filter (ListSimulatorsFilters | None): None - - Returns: - Simulator: None - - Examples: - - - - """ - "" + return self._list(method="POST", limit=limit, resource_cls=Simulator, list_cls=SimulatorList) diff --git a/cognite/client/data_classes/simulators/simulators.py b/cognite/client/data_classes/simulators/simulators.py index cd459d9b2d..9571e182af 100644 --- a/cognite/client/data_classes/simulators/simulators.py +++ b/cognite/client/data_classes/simulators/simulators.py @@ -1,23 +1,16 @@ from __future__ import annotations -from abc import ABC from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, NoReturn, Sequence +from typing import TYPE_CHECKING, Any, Sequence from typing_extensions import Self -from cognite.client.utils.useful_types import SequenceNotStr from cognite.client.data_classes._base import ( CogniteObject, - CognitePrimitiveUpdate, CogniteResource, CogniteResourceList, - CogniteUpdate, - ExternalIDTransformerMixin, - PropertySpec, - WriteableCogniteResource, - WriteableCogniteResourceList, ) +from cognite.client.utils.useful_types import SequenceNotStr if TYPE_CHECKING: from cognite.client import CogniteClient @@ -27,7 +20,7 @@ class SimulatorUnitEntry(CogniteObject): label: str name: str - + @classmethod def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: return cls( @@ -40,52 +33,47 @@ def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = class SimulatorStepOption(CogniteObject): label: str value: str - + @classmethod def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: return cls( label=resource["label"], value=resource["value"], ) - - @dataclass class SimulatorModelType(CogniteObject): name: str key: str - + @classmethod def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: return cls( name=resource["name"], key=resource["key"], ) - - @dataclass class SimulatorQuantity(CogniteObject): name: str label: str - units: SimulatorUnitEntry | Sequence[SimulatorUnitEntry] - + units: Sequence[SimulatorUnitEntry] + @classmethod def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: return cls( name=resource["name"], label=resource["label"], - units=SimulatorUnitEntry._load(resource["units"], cognite_client), + units=[SimulatorUnitEntry._load(unit_, cognite_client) for unit_ in resource["units"]], ) - + def dump(self, camel_case: bool = True) -> dict[str, Any]: output = super().dump(camel_case=camel_case) - output["units"] = self.units.dump(camel_case=camel_case) - - return output + output["units"] = [unit_.dump(camel_case=camel_case) for unit_ in self.units] + return output @dataclass @@ -93,111 +81,47 @@ class SimulatorStepField(CogniteObject): name: str label: str info: str - options: SimulatorStepOption | Sequence[SimulatorStepOption] | None - + options: Sequence[SimulatorStepOption] | None = None + @classmethod def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: return cls( name=resource["name"], label=resource["label"], info=resource["info"], - options=SimulatorStepOption._load(resource["options"], cognite_client) if "options" in resource else None, + options=[SimulatorStepOption._load(option_, cognite_client) for option_ in resource["options"]] + if "options" in resource + else None, ) - + def dump(self, camel_case: bool = True) -> dict[str, Any]: output = super().dump(camel_case=camel_case) - if isinstance(self.options, SimulatorStepOption): - output["options"] = self.options.dump(camel_case=camel_case) - - return output + if self.options is not None: + output["options"] = [option_.dump(camel_case=camel_case) for option_ in self.options] + return output @dataclass class SimulatorStep(CogniteObject): step_type: str - fields: SimulatorStepField | Sequence[SimulatorStepField] - + fields: Sequence[SimulatorStepField] + @classmethod def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: return cls( step_type=resource["stepType"], - fields=SimulatorStepField._load(resource["fields"], cognite_client), + fields=[SimulatorStepField._load(field_, cognite_client) for field_ in resource["fields"]], ) - - def dump(self, camel_case: bool = True) -> dict[str, Any]: - output = super().dump(camel_case=camel_case) - output["fields"] = self.fields.dump(camel_case=camel_case) - - return output - -class _SimulatorCore(WriteableCogniteResource["SimulatorWrite"], ABC): - def __init__(self, external_id: str, name: str, file_extension_types: str | SequenceNotStr[str], model_types: SimulatorModelType | Sequence[SimulatorModelType], step_fields: SimulatorStep | Sequence[SimulatorStep], unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None) -> None: - self.external_id = external_id - self.name = name - self.file_extension_types = file_extension_types - self.model_types = model_types - self.step_fields = step_fields - self.unit_quantities = unit_quantities - - -class SimulatorWrite(_SimulatorCore): - """The simulator resource contains the definitions necessary for Cognite Data Fusion (CDF) to interact with a given simulator. - - It serves as a central contract that allows APIs, UIs, and integrations (connectors) to utilize the same definitions - when dealing with a specific simulator. Each simulator is uniquely identified and can be associated with various - file extension types, model types, step fields, and unit quantities. Simulators are essential for managing data - flows between CDF and external simulation tools, ensuring consistency and reliability in data handling. #### - Limitations: - A project can have a maximum of 100 simulators - - This is the write/request format of the simulator. - - Args: - external_id (str): External id of the simulator - name (str): Name of the simulator - file_extension_types (str | SequenceNotStr[str]): File extension types supported by the simulator - model_types (SimulatorModelType | Sequence[SimulatorModelType]): Model types supported by the simulator - step_fields (SimulatorStep | Sequence[SimulatorStep]): Step types supported by the simulator when creating routines - unit_quantities (SimulatorQuantity | Sequence[SimulatorQuantity] | None): Quantities and their units supported by the simulator - - """ - - def __init__(self, external_id: str, name: str, file_extension_types: str | SequenceNotStr[str], model_types: SimulatorModelType | Sequence[SimulatorModelType], step_fields: SimulatorStep | Sequence[SimulatorStep], unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None) -> None: - super().__init__( - external_id=external_id, - name=name, - file_extension_types=file_extension_types, - model_types=model_types, - step_fields=step_fields, - unit_quantities=unit_quantities, - ) - - @classmethod - def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = None) -> Self: - return cls( - external_id=resource["externalId"], - name=resource["name"], - file_extension_types=resource["fileExtensionTypes"], - model_types=SimulatorModelType._load(resource["modelTypes"], cognite_client), - step_fields=SimulatorStep._load(resource["stepFields"], cognite_client), - unit_quantities=SimulatorQuantity._load(resource["unitQuantities"], cognite_client) if "unitQuantities" in resource else None, - ) - def dump(self, camel_case: bool = True) -> dict[str, Any]: output = super().dump(camel_case=camel_case) - output["modelTypes" if camel_case else "model_types"] = self.model_types.dump(camel_case=camel_case) - output["stepFields" if camel_case else "step_fields"] = self.step_fields.dump(camel_case=camel_case) - if isinstance(self.unit_quantities, SimulatorQuantity): - output["unitQuantities" if camel_case else "unit_quantities"] = self.unit_quantities.dump(camel_case=camel_case) - - return output - def as_write(self) -> SimulatorWrite: - return self + output["fields"] = [field_.dump(camel_case=camel_case) for field_ in self.fields] + return output -class Simulator(_SimulatorCore): +class Simulator(CogniteResource): """The simulator resource contains the definitions necessary for Cognite Data Fusion (CDF) to interact with a given simulator. It serves as a central contract that allows APIs, UIs, and integrations (connectors) to utilize the same definitions @@ -213,23 +137,32 @@ class Simulator(_SimulatorCore): external_id (str): External id of the simulator name (str): Name of the simulator file_extension_types (str | SequenceNotStr[str]): File extension types supported by the simulator + created_time (int): None + last_updated_time (int): None model_types (SimulatorModelType | Sequence[SimulatorModelType] | None): Model types supported by the simulator step_fields (SimulatorStep | Sequence[SimulatorStep] | None): Step types supported by the simulator when creating routines unit_quantities (SimulatorQuantity | Sequence[SimulatorQuantity] | None): Quantities and their units supported by the simulator - created_time (int): None - last_updated_time (int): None """ - def __init__(self, id: int, external_id: str, name: str, file_extension_types: str | SequenceNotStr[str], created_time: int, last_updated_time: int, model_types: SimulatorModelType | Sequence[SimulatorModelType] | None = None, step_fields: SimulatorStep | Sequence[SimulatorStep] | None = None, unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None) -> None: - super().__init__( - external_id=external_id, - name=name, - file_extension_types=file_extension_types, - model_types=model_types, - step_fields=step_fields, - unit_quantities=unit_quantities, - ) + def __init__( + self, + id: int, + external_id: str, + name: str, + file_extension_types: str | SequenceNotStr[str], + created_time: int, + last_updated_time: int, + model_types: SimulatorModelType | Sequence[SimulatorModelType] | None = None, + step_fields: SimulatorStep | Sequence[SimulatorStep] | None = None, + unit_quantities: SimulatorQuantity | Sequence[SimulatorQuantity] | None = None, + ) -> None: + self.external_id = external_id + self.name = name + self.file_extension_types = file_extension_types + self.model_types = model_types + self.step_fields = step_fields + self.unit_quantities = unit_quantities self.id = id self.created_time = created_time self.last_updated_time = last_updated_time @@ -243,10 +176,16 @@ def _load(cls, resource: dict[str, Any], cognite_client: CogniteClient | None = file_extension_types=resource["fileExtensionTypes"], created_time=resource["createdTime"], last_updated_time=resource["lastUpdatedTime"], - model_types=SimulatorModelType._load(resource["modelTypes"], cognite_client) if "modelTypes" in resource else None, - step_fields=SimulatorStep._load(resource["stepFields"], cognite_client) if "stepFields" in resource else None, - unit_quantities=SimulatorQuantity._load(resource["unitQuantities"], cognite_client) if "unitQuantities" in resource else None, - ) + model_types=SimulatorModelType._load(resource["modelTypes"], cognite_client) + if "modelTypes" in resource + else None, + step_fields=SimulatorStep._load(resource["stepFields"], cognite_client) + if "stepFields" in resource + else None, + unit_quantities=SimulatorQuantity._load(resource["unitQuantities"], cognite_client) + if "unitQuantities" in resource + else None, + ) def dump(self, camel_case: bool = True) -> dict[str, Any]: output = super().dump(camel_case=camel_case) @@ -255,88 +194,12 @@ def dump(self, camel_case: bool = True) -> dict[str, Any]: if isinstance(self.step_fields, SimulatorStep): output["stepFields" if camel_case else "step_fields"] = self.step_fields.dump(camel_case=camel_case) if isinstance(self.unit_quantities, SimulatorQuantity): - output["unitQuantities" if camel_case else "unit_quantities"] = self.unit_quantities.dump(camel_case=camel_case) - - return output - + output["unitQuantities" if camel_case else "unit_quantities"] = self.unit_quantities.dump( + camel_case=camel_case + ) - def as_write(self) -> SimulatorWrite: - return SimulatorWrite( - unit_quantities=self.unit_quantities, - name=self.name, - model_types=self.model_types, - external_id=self.external_id, - step_fields=self.step_fields, - file_extension_types=self.file_extension_types, - ) - - -class SimulatorUpdate(CogniteUpdate): - def __init__(self, id: int) -> None: - super().__init__( - id = id, - ) - - class _UpdateSetAnnotatedStringConstraintsUpdate(CognitePrimitiveUpdate): - def set(self, value: UpdateSetAnnotatedStringConstraints | None) -> SimulatorUpdate: - return self._set(value.dump() if isinstance(value, UpdateSetAnnotatedStringConstraints) else value) - - class _UpdateSetListUpdate(CognitePrimitiveUpdate): - def set(self, value: UpdateSetList | None) -> SimulatorUpdate: - return self._set(value.dump() if isinstance(value, UpdateSetList) else value) - - class _UpdateSetListSimulatorModelTypeUpdate(CognitePrimitiveUpdate): - def set(self, value: UpdateSetListSimulatorModelType | None) -> SimulatorUpdate: - return self._set(value.dump() if isinstance(value, UpdateSetListSimulatorModelType) else value) - - class _UpdateSetListSimulatorStepUpdate(CognitePrimitiveUpdate): - def set(self, value: UpdateSetListSimulatorStep | None) -> SimulatorUpdate: - return self._set(value.dump() if isinstance(value, UpdateSetListSimulatorStep) else value) - - class _UpdateSetList1kSimulatorQuantityUpdate(CognitePrimitiveUpdate): - def set(self, value: UpdateSetList1kSimulatorQuantity | None) -> SimulatorUpdate: - return self._set(value.dump() if isinstance(value, UpdateSetList1kSimulatorQuantity) else value) - - - @property - def name(self) -> SimulatorUpdate._UpdateSetAnnotatedStringConstraintsUpdate: - return self._UpdateSetAnnotatedStringConstraintsUpdate(self, "name") - - @property - def file_extension_types(self) -> SimulatorUpdate._UpdateSetListUpdate: - return self._UpdateSetListUpdate(self, "file_extension_types") - - @property - def model_types(self) -> SimulatorUpdate._UpdateSetListSimulatorModelTypeUpdate: - return self._UpdateSetListSimulatorModelTypeUpdate(self, "model_types") - - @property - def step_fields(self) -> SimulatorUpdate._UpdateSetListSimulatorStepUpdate: - return self._UpdateSetListSimulatorStepUpdate(self, "step_fields") - - @property - def unit_quantities(self) -> SimulatorUpdate._UpdateSetList1kSimulatorQuantityUpdate: - return self._UpdateSetList1kSimulatorQuantityUpdate(self, "unit_quantities") - - - @classmethod - def _get_update_properties(cls, item: CogniteResource | None = None) -> list[PropertySpec]: - return [ - PropertySpec("name", is_nullable=True), - PropertySpec("file_extension_types", is_nullable=True), - PropertySpec("model_types", is_nullable=True), - PropertySpec("step_fields", is_nullable=True), - PropertySpec("unit_quantities", is_nullable=True), - ] - - -class SimulatorWriteList(CogniteResourceList[SimulatorWrite]): - _RESOURCE = SimulatorWrite + return output -class SimulatorList(WriteableCogniteResourceList[SimulatorWrite, Simulator]): +class SimulatorList(CogniteResourceList[Simulator]): _RESOURCE = Simulator - - def as_write(self) -> SimulatorWriteList: - return SimulatorWriteList([item.as_write() for item in self.data]) - From 2852e9f913b7fa67b52c1351b7a0c680607974aa Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sun, 6 Oct 2024 08:05:10 +0200 Subject: [PATCH 4/5] refactor: setup shell --- cognite/client/_api/simulators/__init__.py | 3 +++ cognite/client/_cognite_client.py | 2 ++ cognite/client/testing.py | 3 +++ .../test_api/test_simulators/__init__.py | 0 .../test_api/test_simulators/test_simulators.py | 8 ++++++++ 5 files changed, 16 insertions(+) create mode 100644 cognite/client/_api/simulators/__init__.py create mode 100644 tests/tests_integration/test_api/test_simulators/__init__.py create mode 100644 tests/tests_integration/test_api/test_simulators/test_simulators.py diff --git a/cognite/client/_api/simulators/__init__.py b/cognite/client/_api/simulators/__init__.py new file mode 100644 index 0000000000..5f0738825e --- /dev/null +++ b/cognite/client/_api/simulators/__init__.py @@ -0,0 +1,3 @@ +from .simulators import SimulatorsAPI + +__all__ = ["SimulatorsAPI"] diff --git a/cognite/client/_cognite_client.py b/cognite/client/_cognite_client.py index 12d83162fd..df7d6b4118 100644 --- a/cognite/client/_cognite_client.py +++ b/cognite/client/_cognite_client.py @@ -22,6 +22,7 @@ from cognite.client._api.raw import RawAPI from cognite.client._api.relationships import RelationshipsAPI from cognite.client._api.sequences import SequencesAPI +from cognite.client._api.simulators import SimulatorsAPI from cognite.client._api.templates import TemplatesAPI from cognite.client._api.three_d import ThreeDAPI from cognite.client._api.time_series import TimeSeriesAPI @@ -81,6 +82,7 @@ def __init__(self, config: ClientConfig | None = None) -> None: self.documents = DocumentsAPI(self._config, self._API_VERSION, self) self.workflows = WorkflowAPI(self._config, self._API_VERSION, self) self.units = UnitAPI(self._config, self._API_VERSION, self) + self.simulators = SimulatorsAPI(self._config, self._API_VERSION, self) # APIs just using base_url: self._api_client = APIClient(self._config, api_version=None, cognite_client=self) diff --git a/cognite/client/testing.py b/cognite/client/testing.py index 0cb8b382ca..49147ff8bb 100644 --- a/cognite/client/testing.py +++ b/cognite/client/testing.py @@ -39,6 +39,7 @@ from cognite.client._api.raw import RawAPI, RawDatabasesAPI, RawRowsAPI, RawTablesAPI from cognite.client._api.relationships import RelationshipsAPI from cognite.client._api.sequences import SequencesAPI, SequencesDataAPI +from cognite.client._api.simulators import SimulatorsAPI from cognite.client._api.synthetic_time_series import SyntheticDatapointsAPI from cognite.client._api.templates import ( TemplateGroupsAPI, @@ -138,6 +139,8 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.relationships = MagicMock(spec_set=RelationshipsAPI) + self.simulators = MagicMock(spec=SimulatorsAPI) + self.sequences = MagicMock(spec=SequencesAPI) self.sequences.data = MagicMock(spec_set=SequencesDataAPI) diff --git a/tests/tests_integration/test_api/test_simulators/__init__.py b/tests/tests_integration/test_api/test_simulators/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/tests_integration/test_api/test_simulators/test_simulators.py b/tests/tests_integration/test_api/test_simulators/test_simulators.py new file mode 100644 index 0000000000..415239aa31 --- /dev/null +++ b/tests/tests_integration/test_api/test_simulators/test_simulators.py @@ -0,0 +1,8 @@ +from cognite.client import CogniteClient + + +class TestSimulators: + def test_list(self, cognite_client: CogniteClient) -> None: + simulators = cognite_client.simulators.list(limit=5) + + assert len(simulators) > 0 From 4fb77282eda92d61d375ec5f84b51a277bfdd440 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sun, 6 Oct 2024 08:07:28 +0200 Subject: [PATCH 5/5] fix: added forgotten --- cognite/client/_api/simulators/simulators.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cognite/client/_api/simulators/simulators.py b/cognite/client/_api/simulators/simulators.py index 5499482e05..691ebcc0e1 100644 --- a/cognite/client/_api/simulators/simulators.py +++ b/cognite/client/_api/simulators/simulators.py @@ -39,4 +39,6 @@ def list(self, limit: int = DEFAULT_LIMIT_READ) -> SimulatorList: """ self._warning.warn() - return self._list(method="POST", limit=limit, resource_cls=Simulator, list_cls=SimulatorList) + return self._list( + method="POST", limit=limit, resource_cls=Simulator, list_cls=SimulatorList, headers={"cdf-version": "beta"} + )