From 7845d14650385cb33027a1820215ec75f60cd226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20V=2E=20Treider?= Date: Thu, 10 Oct 2024 11:38:10 +0200 Subject: [PATCH 1/6] [DM-2204] dump instance type even when specified as null --- .../data_classes/data_modeling/instances.py | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cognite/client/data_classes/data_modeling/instances.py b/cognite/client/data_classes/data_modeling/instances.py index 1edffcaee8..affa101248 100644 --- a/cognite/client/data_classes/data_modeling/instances.py +++ b/cognite/client/data_classes/data_modeling/instances.py @@ -108,6 +108,7 @@ Space: TypeAlias = str PropertyIdentifier: TypeAlias = str +NOT_SET = object() @dataclass @@ -578,10 +579,23 @@ def __init__( external_id: str, existing_version: int | None = None, sources: list[NodeOrEdgeData] | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: super().__init__(space, external_id, "node", existing_version, sources) - self.type = DirectRelationReference.load(type) if type else None + self.type = type # type: ignore [assignment] + + @property + def type(self) -> DirectRelationReference | None: + return self.__type + + @type.setter + def type(self, value: DirectRelationReference | None) -> None: + if value is NOT_SET: + self.__type = None + self.__type_was_set = False + else: + self.__type = DirectRelationReference.load(value) if value else None + self.__type_was_set = True @classmethod def _load(cls, resource: dict, cognite_client: CogniteClient | None = None) -> NodeApply: @@ -597,6 +611,8 @@ def dump(self, camel_case: bool = True) -> dict[str, Any]: output = super().dump(camel_case) if self.type: output["type"] = self.type.dump(camel_case) + elif self.__type_was_set: + output["type"] = self.type.dump(camel_case) if self.type else self.type return output def as_id(self) -> NodeId: From 2e03e051f1ed38eea1d8eddb895e903eae4f252a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20V=2E=20Treider?= Date: Thu, 10 Oct 2024 11:38:58 +0200 Subject: [PATCH 2/6] changelog, version --- CHANGELOG.md | 4 ++++ cognite/client/_version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2600689b55..0db64f1d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,10 @@ Changes are grouped as follows - `Fixed` for any bug fixes. - `Security` in case of vulnerabilities. +## [7.62.9] - 2024-10-10 +### Fixed +- Resetting an instance type to null now works as expected. + ## [7.62.8] - 2024-10-07 ### Added - [Feature Preview - alpha] Support for `PostgresGateway` `Users` `client.postegres_gateway.users`. diff --git a/cognite/client/_version.py b/cognite/client/_version.py index 98a258d162..1b215aa544 100644 --- a/cognite/client/_version.py +++ b/cognite/client/_version.py @@ -1,4 +1,4 @@ from __future__ import annotations -__version__ = "7.62.8" +__version__ = "7.62.9" __api_subversion__ = "20230101" diff --git a/pyproject.toml b/pyproject.toml index a6a11b2cb8..0153a647fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "cognite-sdk" -version = "7.62.8" +version = "7.62.9" description = "Cognite Python SDK" readme = "README.md" documentation = "https://cognite-sdk-python.readthedocs-hosted.com" From a8b6737e8beea59cfc6047619cd0ec436ffb2809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20V=2E=20Treider?= Date: Thu, 10 Oct 2024 12:07:06 +0200 Subject: [PATCH 3/6] fix typed instance apply classes --- .../data_classes/data_modeling/cdm/v1.py | 65 ++++++++++--------- .../data_classes/data_modeling/instances.py | 21 +++--- 2 files changed, 45 insertions(+), 41 deletions(-) diff --git a/cognite/client/data_classes/data_modeling/cdm/v1.py b/cognite/client/data_classes/data_modeling/cdm/v1.py index e652bab6de..967e5bfa4d 100644 --- a/cognite/client/data_classes/data_modeling/cdm/v1.py +++ b/cognite/client/data_classes/data_modeling/cdm/v1.py @@ -6,6 +6,7 @@ from cognite.client.data_classes.data_modeling import DirectRelationReference from cognite.client.data_classes.data_modeling.ids import ViewId from cognite.client.data_classes.data_modeling.instances import ( + NOT_SET, PropertyOptions, TypedEdge, TypedEdgeApply, @@ -87,7 +88,7 @@ def __init__( station_360: DirectRelationReference | tuple[str, str] | None = None, taken_at: datetime | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.translation_x = translation_x @@ -263,7 +264,7 @@ def __init__( revision_type: Literal["CAD", "Image360", "PointCloud"] | None = None, model_3d: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -385,7 +386,7 @@ def __init__( model_type: Literal["CAD", "Image360", "PointCloud"] | None = None, thumbnail: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -495,7 +496,7 @@ def __init__( aliases: list[str] | None = None, group_type: Literal["Station360"] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -602,7 +603,7 @@ def __init__( model_type: Literal["CAD", "Image360", "PointCloud"] | None = None, thumbnail: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -727,7 +728,7 @@ def __init__( z_min: float | None = None, z_max: float | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -857,7 +858,7 @@ def __init__( revision_type: Literal["CAD", "Image360", "PointCloud"] | None = None, model_3d: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.status = status @@ -975,7 +976,7 @@ def __init__( scale_y: float | None = None, scale_z: float | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.translation_x = translation_x @@ -1137,7 +1138,7 @@ def __init__( equipment: list[DirectRelationReference | tuple[str, str]] | None = None, time_series: list[DirectRelationReference | tuple[str, str]] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -1338,9 +1339,9 @@ def __init__( source_updated_user: str | None = None, parent: DirectRelationReference | tuple[str, str] | None = None, asset_class: DirectRelationReference | tuple[str, str] | None = None, - asset_type: DirectRelationReference | tuple[str, str] | None = None, + asset_type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.object_3d = DirectRelationReference.load(object_3d) if object_3d else None @@ -1504,7 +1505,7 @@ def __init__( code: str | None = None, standard: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -1618,7 +1619,7 @@ def __init__( standard: str | None = None, asset_class: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -1735,7 +1736,7 @@ def __init__( model_type: Literal["CAD", "Image360", "PointCloud"] | None = None, thumbnail: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -1859,7 +1860,7 @@ def __init__( tree_indexes: list[int] | None = None, sub_tree_sizes: list[int] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -1990,7 +1991,7 @@ def __init__( model_3d: DirectRelationReference | tuple[str, str] | None = None, revision_id: int | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.status = status @@ -2095,7 +2096,7 @@ def __init__( top: DirectRelationReference | tuple[str, str] | None = None, bottom: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.front = DirectRelationReference.load(front) if front else None @@ -2203,7 +2204,7 @@ def __init__( tags: list[str] | None = None, aliases: list[str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -2330,10 +2331,10 @@ def __init__( asset: DirectRelationReference | tuple[str, str] | None = None, serial_number: str | None = None, manufacturer: str | None = None, - equipment_type: DirectRelationReference | tuple[str, str] | None = None, + equipment_type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] files: list[DirectRelationReference | tuple[str, str]] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -2500,7 +2501,7 @@ def __init__( standard: str | None = None, standard_reference: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -2648,7 +2649,7 @@ def __init__( directory: str | None = None, category: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -2813,7 +2814,7 @@ def __init__( standard: str | None = None, standard_reference: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.code = code @@ -2930,7 +2931,7 @@ def __init__( model_type: Literal["CAD", "Image360", "PointCloud"] | None = None, thumbnail: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -3042,7 +3043,7 @@ def __init__( model_3d: DirectRelationReference | tuple[str, str] | None = None, revision_id: int | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.status = status @@ -3163,7 +3164,7 @@ def __init__( volume: list[float] | None = None, format_version: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -3299,7 +3300,7 @@ def __init__( scheduled_start_time: datetime | None = None, scheduled_end_time: datetime | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.start_time = start_time @@ -3401,7 +3402,7 @@ def __init__( source_system_version: str | None = None, manufacturer: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -3519,7 +3520,7 @@ def __init__( source_created_user: str | None = None, source_updated_user: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.source_id = source_id @@ -3665,7 +3666,7 @@ def __init__( assets: list[DirectRelationReference | tuple[str, str]] | None = None, equipment: list[DirectRelationReference | tuple[str, str]] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.is_step = is_step @@ -3836,7 +3837,7 @@ def __init__( source: str | None = None, source_reference: str | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.name = name @@ -3948,7 +3949,7 @@ def __init__( *, object_3d: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: TypedNodeApply.__init__(self, space, external_id, existing_version, type) self.object_3d = DirectRelationReference.load(object_3d) if object_3d else None diff --git a/cognite/client/data_classes/data_modeling/instances.py b/cognite/client/data_classes/data_modeling/instances.py index affa101248..2ebcf1b959 100644 --- a/cognite/client/data_classes/data_modeling/instances.py +++ b/cognite/client/data_classes/data_modeling/instances.py @@ -655,21 +655,16 @@ def as_apply(self) -> NodeApply: """ This is a convenience function for converting the read to a write node. - It makes the simplifying assumption that all properties are from the same view. Note that this - is not true in general. - Returns: NodeApply: A write node, NodeApply """ + sources = [NodeOrEdgeData(source=view_id, properties=props) for view_id, props in self.properties.items()] return NodeApply( space=self.space, external_id=self.external_id, existing_version=self.version, - sources=[ - NodeOrEdgeData(source=view_id, properties=properties) for view_id, properties in self.properties.items() - ] - or None, + sources=sources or None, type=self.type, ) @@ -1620,7 +1615,7 @@ def __init__( space: str, external_id: str, existing_version: int | None = None, - type: DirectRelationReference | tuple[str, str] | None = None, + type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: super().__init__(space, external_id, existing_version, type=type) @@ -1749,7 +1744,15 @@ def properties(self) -> Properties: | TypedEdgeApply._base_properties() | TypedNode._base_properties() | TypedEdge._base_properties() -) | {"instance_type", "existing_version", "_InstanceApply__sources", "_Instance__properties", "_Instance__prop_lookup"} +) | { + "instance_type", + "existing_version", + "_InstanceApply__sources", + "_Instance__properties", + "_Instance__prop_lookup", + "_NodeApply__type", + "_NodeApply__type_was_set", +} class _PropertyValueSerializer: From 1100f11896090858f342f77d1f534b014e5113f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20V=2E=20Treider?= Date: Thu, 10 Oct 2024 12:14:00 +0200 Subject: [PATCH 4/6] revert asset_type and equipment_type from NOT_SET to None --- CHANGELOG.md | 2 +- cognite/client/data_classes/data_modeling/cdm/v1.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0db64f1d0c..4f1639b997 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ Changes are grouped as follows ## [7.62.9] - 2024-10-10 ### Fixed -- Resetting an instance type to null now works as expected. +- Resetting the type of a node to null, now works as expected when `type=None` is passed. ## [7.62.8] - 2024-10-07 ### Added diff --git a/cognite/client/data_classes/data_modeling/cdm/v1.py b/cognite/client/data_classes/data_modeling/cdm/v1.py index 967e5bfa4d..f2b9033482 100644 --- a/cognite/client/data_classes/data_modeling/cdm/v1.py +++ b/cognite/client/data_classes/data_modeling/cdm/v1.py @@ -1339,7 +1339,7 @@ def __init__( source_updated_user: str | None = None, parent: DirectRelationReference | tuple[str, str] | None = None, asset_class: DirectRelationReference | tuple[str, str] | None = None, - asset_type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] + asset_type: DirectRelationReference | tuple[str, str] | None = None, existing_version: int | None = None, type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] ) -> None: @@ -2331,7 +2331,7 @@ def __init__( asset: DirectRelationReference | tuple[str, str] | None = None, serial_number: str | None = None, manufacturer: str | None = None, - equipment_type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] + equipment_type: DirectRelationReference | tuple[str, str] | None = None, files: list[DirectRelationReference | tuple[str, str]] | None = None, existing_version: int | None = None, type: DirectRelationReference | tuple[str, str] | None = NOT_SET, # type: ignore [assignment] From c63aa88d0a40080d1006ebb55ea1d934461ac839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20V=2E=20Treider?= Date: Thu, 10 Oct 2024 12:22:19 +0200 Subject: [PATCH 5/6] update tests --- .../test_api/test_data_modeling/test_core_model.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/tests_integration/test_api/test_data_modeling/test_core_model.py b/tests/tests_integration/test_api/test_data_modeling/test_core_model.py index a1ee2d92e9..2e97b85e8b 100644 --- a/tests/tests_integration/test_api/test_data_modeling/test_core_model.py +++ b/tests/tests_integration/test_api/test_data_modeling/test_core_model.py @@ -111,7 +111,7 @@ def core_model_v1_node_test_cases() -> Iterable[ParameterSet]: model_type="PointCloud", # TODO: Should be nullable, returns as 400 if not set ), cdm.Cognite3DModel, - id="CogniteModel3D", + id="Cognite3DModel", ) yield pytest.param( cdm.Cognite3DObjectApply( @@ -122,7 +122,7 @@ def core_model_v1_node_test_cases() -> Iterable[ParameterSet]: aliases=["test_object_3d_alias"], ), cdm.Cognite3DObject, - id="CogniteObject3D", + id="Cognite3DObject", ) yield pytest.param( @@ -231,6 +231,9 @@ def test_write_read_node( # so we need to remove it from the comparison read_dumped.pop("existingVersion", None) write_instance_dumped.pop("existingVersion", None) + # The read version we assume is created by the SDK (from the API response), and so if that says type is None + # the '.as_write()' will interpret this as an explicitly set null value (instead of 'not given->ignore'): + read_dumped.pop("type", None) for key, value in read_dumped["sources"][0]["properties"].items(): if isinstance(value, str) and value.endswith("+00:00"): # Server sets timezone to UTC, but expects the client to send it without From e7322cc7d2085c845882ca199555bf89fbed341a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20V=2E=20Treider?= Date: Thu, 10 Oct 2024 12:44:11 +0200 Subject: [PATCH 6/6] update NodeApply.load to not pass type unless explicitly given --- cognite/client/_constants.py | 3 ++ .../data_classes/data_modeling/cdm/v1.py | 2 +- .../data_classes/data_modeling/instances.py | 11 +++++-- cognite/client/data_classes/datapoints.py | 33 +++++++++---------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/cognite/client/_constants.py b/cognite/client/_constants.py index 4eaa2e9bf2..4c52a82fb6 100644 --- a/cognite/client/_constants.py +++ b/cognite/client/_constants.py @@ -10,6 +10,9 @@ # Max JavaScript-safe integer 2^53 - 1 MAX_VALID_INTERNAL_ID = 9007199254740991 DATA_MODELING_DEFAULT_LIMIT_READ = 10 +# Some objects need to differentiate between a default value, typically None and 'parameter no given' +# for which we use this NOT_SET object: +NOT_SET = object() try: import numpy as np # noqa F401 diff --git a/cognite/client/data_classes/data_modeling/cdm/v1.py b/cognite/client/data_classes/data_modeling/cdm/v1.py index f2b9033482..b1a898bf0e 100644 --- a/cognite/client/data_classes/data_modeling/cdm/v1.py +++ b/cognite/client/data_classes/data_modeling/cdm/v1.py @@ -3,10 +3,10 @@ from datetime import datetime from typing import Literal +from cognite.client._constants import NOT_SET from cognite.client.data_classes.data_modeling import DirectRelationReference from cognite.client.data_classes.data_modeling.ids import ViewId from cognite.client.data_classes.data_modeling.instances import ( - NOT_SET, PropertyOptions, TypedEdge, TypedEdgeApply, diff --git a/cognite/client/data_classes/data_modeling/instances.py b/cognite/client/data_classes/data_modeling/instances.py index 2ebcf1b959..6fbd269f2a 100644 --- a/cognite/client/data_classes/data_modeling/instances.py +++ b/cognite/client/data_classes/data_modeling/instances.py @@ -34,6 +34,7 @@ from typing_extensions import Self, TypeAlias +from cognite.client._constants import NOT_SET from cognite.client.data_classes._base import ( CogniteObject, CogniteResourceList, @@ -108,7 +109,6 @@ Space: TypeAlias = str PropertyIdentifier: TypeAlias = str -NOT_SET = object() @dataclass @@ -599,12 +599,19 @@ def type(self, value: DirectRelationReference | None) -> None: @classmethod def _load(cls, resource: dict, cognite_client: CogniteClient | None = None) -> NodeApply: + # To distinguish between 'no given type' and 'type is None', we only pass it when + # explicitly present in the resource dictionary: + if "type" in resource: + tp = resource["type"] + type_kw = {"type": DirectRelationReference.load(tp) if tp else tp} + else: + type_kw = {} return cls( space=resource["space"], external_id=resource["externalId"], existing_version=resource.get("existingVersion"), sources=[NodeOrEdgeData.load(source) for source in resource.get("sources", [])] or None, - type=DirectRelationReference.load(resource["type"]) if "type" in resource else None, + **type_kw, ) def dump(self, camel_case: bool = True) -> dict[str, Any]: diff --git a/cognite/client/data_classes/datapoints.py b/cognite/client/data_classes/datapoints.py index 8705143987..ee0977f8fb 100644 --- a/cognite/client/data_classes/datapoints.py +++ b/cognite/client/data_classes/datapoints.py @@ -24,7 +24,7 @@ from typing_extensions import NotRequired, Self -from cognite.client._constants import NUMPY_IS_AVAILABLE +from cognite.client._constants import NOT_SET, NUMPY_IS_AVAILABLE from cognite.client.data_classes._base import CogniteResource, CogniteResourceList from cognite.client.data_classes.data_modeling import NodeId from cognite.client.utils import _json @@ -141,9 +141,6 @@ class _DatapointsPayload(_DatapointsPayloadItem): ignoreUnknownIds: NotRequired[bool] -_NOT_SET = object() - - @dataclass class DatapointsQuery: """Represent a user request for datapoints for a single time series""" @@ -168,19 +165,19 @@ class DatapointsQuery: id: InitVar[int | None] = None external_id: InitVar[str | None] = None instance_id: InitVar[NodeId | None] = None - start: int | str | datetime.datetime = _NOT_SET # type: ignore [assignment] - end: int | str | datetime.datetime = _NOT_SET # type: ignore [assignment] - aggregates: Aggregate | list[Aggregate] | None = _NOT_SET # type: ignore [assignment] - granularity: str | None = _NOT_SET # type: ignore [assignment] - timezone: str | datetime.timezone | ZoneInfo | None = _NOT_SET # type: ignore [assignment] - target_unit: str | None = _NOT_SET # type: ignore [assignment] - target_unit_system: str | None = _NOT_SET # type: ignore [assignment] - limit: int | None = _NOT_SET # type: ignore [assignment] - include_outside_points: bool = _NOT_SET # type: ignore [assignment] - ignore_unknown_ids: bool = _NOT_SET # type: ignore [assignment] - include_status: bool = _NOT_SET # type: ignore [assignment] - ignore_bad_datapoints: bool = _NOT_SET # type: ignore [assignment] - treat_uncertain_as_bad: bool = _NOT_SET # type: ignore [assignment] + start: int | str | datetime.datetime = NOT_SET # type: ignore [assignment] + end: int | str | datetime.datetime = NOT_SET # type: ignore [assignment] + aggregates: Aggregate | list[Aggregate] | None = NOT_SET # type: ignore [assignment] + granularity: str | None = NOT_SET # type: ignore [assignment] + timezone: str | datetime.timezone | ZoneInfo | None = NOT_SET # type: ignore [assignment] + target_unit: str | None = NOT_SET # type: ignore [assignment] + target_unit_system: str | None = NOT_SET # type: ignore [assignment] + limit: int | None = NOT_SET # type: ignore [assignment] + include_outside_points: bool = NOT_SET # type: ignore [assignment] + ignore_unknown_ids: bool = NOT_SET # type: ignore [assignment] + include_status: bool = NOT_SET # type: ignore [assignment] + ignore_bad_datapoints: bool = NOT_SET # type: ignore [assignment] + treat_uncertain_as_bad: bool = NOT_SET # type: ignore [assignment] def __post_init__(self, id: int | None, external_id: str | None, instance_id: NodeId | None) -> None: # Ensure user have just specified one of id/xid: @@ -297,7 +294,7 @@ def dump(self) -> dict[str, Any]: # We need to dump only those fields specifically passed by the user: return { **self.identifier.as_dict(camel_case=False), - **dict((fld.name, val) for fld in fields(self) if (val := getattr(self, fld.name)) is not _NOT_SET), + **dict((fld.name, val) for fld in fields(self) if (val := getattr(self, fld.name)) is not NOT_SET), } @property