cognite-toolkit 0.7.38__py3-none-any.whl → 0.7.40__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. cognite_toolkit/_cdf_tk/client/_toolkit_client.py +3 -1
  2. cognite_toolkit/_cdf_tk/client/api/assets.py +118 -0
  3. cognite_toolkit/_cdf_tk/client/api/events.py +79 -0
  4. cognite_toolkit/_cdf_tk/client/api/infield.py +3 -3
  5. cognite_toolkit/_cdf_tk/client/api/legacy/extended_functions.py +1 -1
  6. cognite_toolkit/_cdf_tk/client/api/project.py +1 -1
  7. cognite_toolkit/_cdf_tk/client/api/streams.py +2 -2
  8. cognite_toolkit/_cdf_tk/client/api/three_d.py +5 -4
  9. cognite_toolkit/_cdf_tk/client/api/timeseries.py +85 -0
  10. cognite_toolkit/_cdf_tk/client/cdf_client/__init__.py +9 -0
  11. cognite_toolkit/_cdf_tk/client/cdf_client/api.py +220 -0
  12. cognite_toolkit/_cdf_tk/client/{data_classes/api_classes.py → cdf_client/responses.py} +10 -13
  13. cognite_toolkit/_cdf_tk/client/data_classes/asset.py +54 -0
  14. cognite_toolkit/_cdf_tk/client/data_classes/base.py +117 -22
  15. cognite_toolkit/_cdf_tk/client/data_classes/event.py +40 -0
  16. cognite_toolkit/_cdf_tk/client/data_classes/identifiers.py +44 -0
  17. cognite_toolkit/_cdf_tk/client/data_classes/instance_api.py +34 -0
  18. cognite_toolkit/_cdf_tk/client/data_classes/streams.py +3 -2
  19. cognite_toolkit/_cdf_tk/client/data_classes/three_d.py +29 -34
  20. cognite_toolkit/_cdf_tk/client/data_classes/timeseries.py +45 -0
  21. cognite_toolkit/_cdf_tk/{utils → client}/http_client/__init__.py +4 -4
  22. cognite_toolkit/_cdf_tk/{utils → client}/http_client/_client.py +10 -10
  23. cognite_toolkit/_cdf_tk/{utils → client}/http_client/_data_classes.py +2 -2
  24. cognite_toolkit/_cdf_tk/{utils → client}/http_client/_data_classes2.py +10 -33
  25. cognite_toolkit/_cdf_tk/client/testing.py +2 -0
  26. cognite_toolkit/_cdf_tk/commands/_migrate/command.py +1 -1
  27. cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +6 -7
  28. cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +6 -5
  29. cognite_toolkit/_cdf_tk/commands/_migrate/data_mapper.py +6 -4
  30. cognite_toolkit/_cdf_tk/commands/_migrate/migration_io.py +10 -10
  31. cognite_toolkit/_cdf_tk/commands/_purge.py +7 -7
  32. cognite_toolkit/_cdf_tk/commands/_upload.py +1 -1
  33. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/classic.py +43 -47
  34. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/fieldops.py +11 -4
  35. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +2 -1
  36. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/location.py +3 -2
  37. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +2 -1
  38. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/streams.py +1 -1
  39. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/timeseries.py +2 -1
  40. cognite_toolkit/_cdf_tk/data_classes/_module_toml.py +1 -0
  41. cognite_toolkit/_cdf_tk/storageio/_applications.py +1 -1
  42. cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +32 -29
  43. cognite_toolkit/_cdf_tk/storageio/_base.py +1 -1
  44. cognite_toolkit/_cdf_tk/storageio/_datapoints.py +7 -7
  45. cognite_toolkit/_cdf_tk/storageio/_file_content.py +7 -7
  46. cognite_toolkit/_cdf_tk/storageio/_raw.py +1 -1
  47. cognite_toolkit/_cdf_tk/utils/useful_types.py +4 -7
  48. cognite_toolkit/_cdf_tk/utils/useful_types2.py +12 -0
  49. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  50. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  51. cognite_toolkit/_resources/cdf.toml +1 -1
  52. cognite_toolkit/_version.py +1 -1
  53. {cognite_toolkit-0.7.38.dist-info → cognite_toolkit-0.7.40.dist-info}/METADATA +1 -1
  54. {cognite_toolkit-0.7.38.dist-info → cognite_toolkit-0.7.40.dist-info}/RECORD +58 -48
  55. {cognite_toolkit-0.7.38.dist-info → cognite_toolkit-0.7.40.dist-info}/WHEEL +1 -1
  56. /cognite_toolkit/_cdf_tk/{utils → client}/http_client/_exception.py +0 -0
  57. /cognite_toolkit/_cdf_tk/{utils → client}/http_client/_tracker.py +0 -0
  58. {cognite_toolkit-0.7.38.dist-info → cognite_toolkit-0.7.40.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,54 @@
1
+ from typing import Literal
2
+
3
+ from pydantic import JsonValue
4
+
5
+ from cognite_toolkit._cdf_tk.client.data_classes.base import BaseModelObject, RequestUpdateable, ResponseResource
6
+
7
+ from .identifiers import ExternalId
8
+
9
+
10
+ class AssetRequest(RequestUpdateable):
11
+ container_fields = frozenset({"metadata", "labels"})
12
+ non_nullable_fields = frozenset({"parent_id", "parent_external_id"})
13
+ external_id: str | None = None
14
+ name: str
15
+ parent_id: int | None = None
16
+ parent_external_id: str | None = None
17
+ description: str | None = None
18
+ metadata: dict[str, str] | None = None
19
+ data_set_id: int | None = None
20
+ source: str | None = None
21
+ labels: list[dict[Literal["externalId"], str]] | None = None
22
+ geo_location: dict[str, JsonValue] | None = None
23
+
24
+ def as_id(self) -> ExternalId:
25
+ if self.external_id is None:
26
+ raise ValueError("Cannot convert AssetRequest to ExternalId when external_id is None")
27
+ return ExternalId(external_id=self.external_id)
28
+
29
+
30
+ class AssetAggregateItem(BaseModelObject):
31
+ child_count: int
32
+ depth: int
33
+ path: list[dict[Literal["id"], int]]
34
+
35
+
36
+ class AssetResponse(ResponseResource[AssetRequest]):
37
+ created_time: int
38
+ last_updated_time: int
39
+ root_id: int
40
+ aggregates: AssetAggregateItem | None = None
41
+ id: int
42
+ external_id: str | None = None
43
+ name: str
44
+ parent_id: int | None = None
45
+ parent_external_id: str | None = None
46
+ description: str | None = None
47
+ metadata: dict[str, str] | None = None
48
+ data_set_id: int | None = None
49
+ source: str | None = None
50
+ labels: list[dict[Literal["externalId"], str]] | None = None
51
+ geo_location: dict[str, JsonValue] | None = None
52
+
53
+ def as_request_resource(self) -> AssetRequest:
54
+ return AssetRequest.model_validate(self.dump(), extra="ignore")
@@ -1,55 +1,150 @@
1
1
  import sys
2
+ import types
2
3
  from abc import ABC, abstractmethod
3
4
  from collections import UserList
4
- from typing import TYPE_CHECKING, Any, Generic, TypeVar
5
+ from typing import Any, ClassVar, Generic, Literal, TypeVar, Union, get_args, get_origin
5
6
 
6
- from pydantic import ConfigDict
7
+ from cognite.client import CogniteClient
8
+ from pydantic import BaseModel, ConfigDict
7
9
  from pydantic.alias_generators import to_camel
8
10
 
9
- from cognite_toolkit._cdf_tk.utils.http_client._data_classes2 import BaseModelObject, RequestResource
10
-
11
- if TYPE_CHECKING:
12
- from cognite.client import CogniteClient
13
-
14
11
  if sys.version_info >= (3, 11):
15
12
  from typing import Self
16
13
  else:
17
14
  from typing_extensions import Self
18
15
 
19
16
 
20
- T_RequestResource = TypeVar("T_RequestResource", bound=RequestResource)
17
+ class BaseModelObject(BaseModel):
18
+ """Base class for all object. This includes resources and nested objects."""
21
19
 
20
+ # We allow extra fields to support forward compatibility.
21
+ model_config = ConfigDict(alias_generator=to_camel, extra="allow")
22
22
 
23
- class ResponseResource(BaseModelObject, Generic[T_RequestResource], ABC):
24
- @abstractmethod
25
- def as_request_resource(self) -> T_RequestResource:
26
- """Convert the response resource to a request resource."""
27
- ...
23
+ def dump(self, camel_case: bool = True) -> dict[str, Any]:
24
+ """Dump the resource to a dictionary.
28
25
 
29
- def as_write(self) -> T_RequestResource:
30
- """Alias for as_request_resource to match protocol signature."""
31
- return self.as_request_resource()
26
+ This is the default serialization method for request resources.
27
+ """
28
+ return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=True)
29
+
30
+ @classmethod
31
+ def _load(cls, resource: dict[str, Any]) -> Self:
32
+ """Load method to match CogniteResource signature."""
33
+ return cls.model_validate(resource)
32
34
 
33
35
 
34
- class Identifier(RequestResource, ABC):
35
- """Base class for all identifier classes."""
36
+ class Identifier(BaseModelObject):
37
+ """Base class for all identifier objects typically
38
+ {"externalId": "..."}, {"id": ...}, {"space": "...", "externalId: }."""
36
39
 
37
40
  model_config = ConfigDict(alias_generator=to_camel, extra="ignore", populate_by_name=True, frozen=True)
38
41
 
39
- def dump(self, camel_case: bool = True, include_type: bool = True) -> dict[str, Any]:
42
+ def dump(self, camel_case: bool = True) -> dict[str, Any]:
40
43
  """Dump the resource to a dictionary.
41
44
 
42
45
  This is the default serialization method for request resources.
43
46
  """
44
- return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=not include_type)
47
+ return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=True)
48
+
49
+ def __str__(self) -> str:
50
+ raise NotImplementedError()
51
+
52
+
53
+ T_Identifier = TypeVar("T_Identifier", bound=Identifier)
54
+
55
+
56
+ class RequestResource(BaseModelObject, ABC):
57
+ @abstractmethod
58
+ def as_id(self) -> Identifier:
59
+ raise NotImplementedError()
60
+
61
+ def __str__(self) -> str:
62
+ return str(self.as_id())
63
+
64
+
65
+ T_RequestResource = TypeVar("T_RequestResource", bound=RequestResource)
66
+
67
+
68
+ class RequestUpdateable(RequestResource, ABC):
69
+ container_fields: ClassVar[frozenset[str]] = frozenset()
70
+ non_nullable_fields: ClassVar[frozenset[str]] = frozenset()
71
+
72
+ def as_update(self, mode: Literal["patch", "replace"]) -> dict[str, Any]:
73
+ """Convert the request resource to an update item."""
74
+ update_item = self.as_id().dump(camel_case=True)
75
+ update: dict[str, Any] = {}
76
+ field_by_name = {info.alias or field_id: (field_id, info) for field_id, info in type(self).model_fields.items()}
77
+ # When mode is "patch", we only include fields that are set
78
+ exclude_unset = mode == "patch"
79
+ for key, value in self.model_dump(mode="json", by_alias=True, exclude_unset=exclude_unset).items():
80
+ if key in update_item:
81
+ # Skip identifier fields
82
+ continue
83
+ if key not in field_by_name:
84
+ # Skip unknown fields
85
+ continue
86
+ field_id, info = field_by_name[key]
87
+ if field_id in self.container_fields:
88
+ if mode == "patch":
89
+ update[key] = {"add": value}
90
+ elif mode == "replace":
91
+ if value is None:
92
+ origin = _get_annotation_origin(info.annotation)
93
+ if origin is list:
94
+ update[key] = {"set": []}
95
+ elif origin is dict:
96
+ update[key] = {"set": {}}
97
+ else:
98
+ raise NotImplementedError(
99
+ f'Cannot replace container field "{key}" with None when its type is unknown.'
100
+ )
101
+ else:
102
+ update[key] = {"set": value}
103
+ else:
104
+ raise NotImplementedError(f'Update mode "{mode}" is not supported for container fields.')
105
+ elif value is None:
106
+ if field_id not in self.non_nullable_fields:
107
+ update[key] = {"setNull": True}
108
+ else:
109
+ update[key] = {"set": value}
110
+ update_item["update"] = update
111
+ return update_item
112
+
113
+
114
+ def _get_annotation_origin(field_type: Any) -> Any:
115
+ origin = get_origin(field_type)
116
+ args = get_args(field_type)
117
+
118
+ # Check for Union type (both typing.Union and | syntax from Python 3.10+)
119
+ is_union = origin is Union or isinstance(field_type, getattr(types, "UnionType", ()))
120
+
121
+ if is_union:
122
+ # Handle Optional[T] by filtering out NoneType
123
+ none_types = (type(None), types.NoneType)
124
+ non_none_args = [arg for arg in args if arg not in none_types]
125
+ if len(non_none_args) == 1:
126
+ field_type = non_none_args[0]
127
+ origin = get_origin(field_type) or field_type
128
+ return origin
129
+
130
+
131
+ class ResponseResource(BaseModelObject, Generic[T_RequestResource], ABC):
132
+ @abstractmethod
133
+ def as_request_resource(self) -> T_RequestResource:
134
+ """Convert the response resource to a request resource."""
135
+ raise NotImplementedError()
136
+
137
+ def as_write(self) -> T_RequestResource:
138
+ """Alias for as_request_resource to match protocol signature."""
139
+ return self.as_request_resource()
45
140
 
46
- def as_id(self) -> Self:
47
- return self
48
141
 
142
+ T_ResponseResource = TypeVar("T_ResponseResource", bound=ResponseResource)
49
143
 
50
144
  T_Resource = TypeVar("T_Resource", bound=RequestResource | ResponseResource)
51
145
 
52
146
 
147
+ # Todo: Delete this class and use list[T_Resource] directly
53
148
  class BaseResourceList(UserList[T_Resource]):
54
149
  """Base class for resource lists."""
55
150
 
@@ -0,0 +1,40 @@
1
+ from cognite_toolkit._cdf_tk.client.data_classes.base import RequestResource, ResponseResource
2
+
3
+ from .identifiers import ExternalId, InternalOrExternalId
4
+
5
+
6
+ class EventRequest(RequestResource):
7
+ external_id: str | None = None
8
+ data_set_id: int | None = None
9
+ start_time: int | None = None
10
+ end_time: int | None = None
11
+ type: str | None = None
12
+ subtype: str | None = None
13
+ description: str | None = None
14
+ metadata: dict[str, str] | None = None
15
+ asset_ids: list[int] | None = None
16
+ source: str | None = None
17
+
18
+ def as_id(self) -> InternalOrExternalId:
19
+ if self.external_id is None:
20
+ raise ValueError("Cannot convert EventRequest to ExternalId when external_id is None")
21
+ return ExternalId(external_id=self.external_id)
22
+
23
+
24
+ class EventResponse(ResponseResource[EventRequest]):
25
+ external_id: str | None = None
26
+ data_set_id: int | None = None
27
+ start_time: int | None = None
28
+ end_time: int | None = None
29
+ type: str | None = None
30
+ subtype: str | None = None
31
+ description: str | None = None
32
+ metadata: dict[str, str] | None = None
33
+ asset_ids: list[int] | None = None
34
+ source: str | None = None
35
+ id: int
36
+ created_time: int
37
+ last_updated_time: int
38
+
39
+ def as_request_resource(self) -> EventRequest:
40
+ return EventRequest.model_validate(self.dump())
@@ -0,0 +1,44 @@
1
+ from collections.abc import Sequence
2
+ from typing import Annotated, Literal
3
+
4
+ from pydantic import Field
5
+
6
+ from cognite_toolkit._cdf_tk.client.data_classes.base import Identifier
7
+
8
+
9
+ class InternalOrExternalIdDefinition(Identifier):
10
+ type: str
11
+
12
+
13
+ class InternalId(InternalOrExternalIdDefinition):
14
+ type: Literal["id"] = Field("id", exclude=True)
15
+ id: int
16
+
17
+ @classmethod
18
+ def from_ids(cls, ids: Sequence[int]) -> list["InternalId"]:
19
+ return [cls(id=id_) for id_ in ids]
20
+
21
+ def __str__(self) -> str:
22
+ return f"id={self.id}"
23
+
24
+
25
+ class ExternalId(InternalOrExternalIdDefinition):
26
+ type: Literal["externalId"] = Field("externalId", exclude=True)
27
+ external_id: str
28
+
29
+ @classmethod
30
+ def from_external_ids(cls, external_ids: list[str]) -> list["ExternalId"]:
31
+ return [cls(external_id=ext_id) for ext_id in external_ids]
32
+
33
+ def __str__(self) -> str:
34
+ return f"externalId='{self.external_id}'"
35
+
36
+
37
+ InternalOrExternalId = Annotated[InternalId | ExternalId, Field(discriminator="type")]
38
+
39
+
40
+ class NameId(Identifier):
41
+ name: str
42
+
43
+ def __str__(self) -> str:
44
+ return f"name='{self.name}'"
@@ -14,19 +14,38 @@ class TypedInstanceIdentifier(Identifier):
14
14
  space: str
15
15
  external_id: str
16
16
 
17
+ def __str__(self) -> str:
18
+ return f"Instance({self.instance_type}, {self.space}, {self.external_id})"
19
+
20
+ def dump(self, camel_case: bool = True, include_type: bool = True) -> dict[str, Any]:
21
+ """Dump the resource to a dictionary.
22
+
23
+ This is the default serialization method for request resources.
24
+ """
25
+ return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=not include_type)
26
+
17
27
 
18
28
  class TypedNodeIdentifier(TypedInstanceIdentifier):
19
29
  instance_type: Literal["node"] = "node"
20
30
 
31
+ def __str__(self) -> str:
32
+ return f"Node({self.space}, {self.external_id})"
33
+
21
34
 
22
35
  class TypedEdgeIdentifier(TypedInstanceIdentifier):
23
36
  instance_type: Literal["edge"] = "edge"
24
37
 
38
+ def __str__(self) -> str:
39
+ return f"Edge({self.space}, {self.external_id})"
40
+
25
41
 
26
42
  class InstanceIdentifier(Identifier):
27
43
  space: str
28
44
  external_id: str
29
45
 
46
+ def __str__(self) -> str:
47
+ return f"Instance({self.space}, {self.external_id})"
48
+
30
49
 
31
50
  class InstanceResult(BaseModelObject):
32
51
  instance_type: InstanceType
@@ -51,6 +70,16 @@ class ViewReference(Identifier):
51
70
  external_id: str
52
71
  version: str
53
72
 
73
+ def __str__(self) -> str:
74
+ return f"View({self.space}, {self.external_id}, v{self.version})"
75
+
76
+ def dump(self, camel_case: bool = True, include_type: bool = True) -> dict[str, Any]:
77
+ """Dump the resource to a dictionary.
78
+
79
+ This is the default serialization method for request resources.
80
+ """
81
+ return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=not include_type)
82
+
54
83
 
55
84
  ######################################################
56
85
  # The classes below are helper classes for making instances request/responses.
@@ -160,3 +189,8 @@ class InstanceResponseItem(BaseModelObject):
160
189
  space=self.space,
161
190
  external_id=self.external_id,
162
191
  )
192
+
193
+
194
+ class NodeReference(BaseModelObject):
195
+ space: str
196
+ external_id: str
@@ -7,6 +7,7 @@ from cognite_toolkit._cdf_tk.protocols import (
7
7
  )
8
8
 
9
9
  from .base import BaseModelObject, BaseResourceList, RequestResource, ResponseResource
10
+ from .identifiers import ExternalId
10
11
 
11
12
 
12
13
  class StreamRequest(RequestResource):
@@ -15,8 +16,8 @@ class StreamRequest(RequestResource):
15
16
  external_id: str
16
17
  settings: dict[Literal["template"], dict[Literal["name"], StreamTemplateName]]
17
18
 
18
- def as_id(self) -> str:
19
- return self.external_id
19
+ def as_id(self) -> ExternalId:
20
+ return ExternalId(external_id=self.external_id)
20
21
 
21
22
 
22
23
  class StreamRequestList(BaseResourceList[StreamRequest], ResourceRequestListProtocol):
@@ -1,14 +1,16 @@
1
- from collections.abc import Hashable
1
+ import sys
2
2
  from typing import Literal
3
3
 
4
4
  from pydantic import Field
5
5
 
6
- from .base import BaseModelObject, RequestResource, ResponseResource
6
+ from .base import BaseModelObject, Identifier, RequestResource, ResponseResource
7
+ from .identifiers import NameId
8
+ from .instance_api import NodeReference
7
9
 
8
-
9
- class NodeReference(BaseModelObject):
10
- space: str
11
- external_id: str
10
+ if sys.version_info >= (3, 11):
11
+ from typing import Self
12
+ else:
13
+ from typing_extensions import Self
12
14
 
13
15
 
14
16
  class RevisionStatus(BaseModelObject):
@@ -22,17 +24,14 @@ class RevisionStatus(BaseModelObject):
22
24
  class ThreeDModelRequest(RequestResource):
23
25
  name: str
24
26
 
25
- def as_id(self) -> str:
26
- return self.name
27
+ def as_id(self) -> NameId:
28
+ return NameId(name=self.name)
27
29
 
28
30
 
29
31
  class ThreeDModelClassicRequest(ThreeDModelRequest):
30
32
  data_set_id: int | None = None
31
33
  metadata: dict[str, str] | None = None
32
34
 
33
- def as_id(self) -> str:
34
- return self.name
35
-
36
35
 
37
36
  class ThreeDModelDMSRequest(ThreeDModelRequest):
38
37
  space: str
@@ -56,24 +55,21 @@ class ThreeDModelResponse(ResponseResource[ThreeDModelRequest]):
56
55
  return ThreeDModelDMSRequest._load(self.dump())
57
56
 
58
57
 
59
- class AssetMappingDMRequest(RequestResource):
58
+ class AssetMappingDMRequest(RequestResource, Identifier):
60
59
  node_id: int
61
60
  asset_instance_id: NodeReference
62
61
  # These fields are part of the path request and not the body schema.
63
62
  model_id: int = Field(exclude=True)
64
63
  revision_id: int = Field(exclude=True)
65
64
 
66
- def as_id(self) -> Hashable:
67
- return (
68
- self.model_id,
69
- self.revision_id,
70
- self.node_id,
71
- self.asset_instance_id.space,
72
- self.asset_instance_id.external_id,
73
- )
65
+ def as_id(self) -> Self:
66
+ return self
74
67
 
68
+ def __str__(self) -> str:
69
+ return f"{self.model_id}_{self.revision_id}_{self.node_id}_{self.asset_instance_id.space}_{self.asset_instance_id.external_id}"
75
70
 
76
- class AssetMappingClassicRequest(RequestResource):
71
+
72
+ class AssetMappingClassicRequest(RequestResource, Identifier):
77
73
  node_id: int
78
74
  asset_id: int | None = None
79
75
  asset_instance_id: NodeReference | None = None
@@ -81,19 +77,18 @@ class AssetMappingClassicRequest(RequestResource):
81
77
  model_id: int = Field(exclude=True)
82
78
  revision_id: int = Field(exclude=True)
83
79
 
84
- def as_id(self) -> Hashable:
85
- if self.asset_id:
86
- return self.model_id, self.revision_id, self.node_id, self.asset_id
87
- elif self.asset_instance_id:
88
- return (
89
- self.model_id,
90
- self.revision_id,
91
- self.node_id,
92
- self.asset_instance_id.space,
93
- self.asset_instance_id.external_id,
94
- )
95
- else:
96
- raise AttributeError("asset_id or asset_instance_id is required")
80
+ def as_id(self) -> Self:
81
+ return self
82
+
83
+ def __str__(self) -> str:
84
+ asset_part = (
85
+ f"assetId:{self.asset_id}"
86
+ if self.asset_id is not None
87
+ else f"assetInstance:{self.asset_instance_id.space}_{self.asset_instance_id.external_id}"
88
+ if self.asset_instance_id is not None
89
+ else "noAsset"
90
+ )
91
+ return f"{self.model_id}_{self.revision_id}_{self.node_id}_{asset_part}"
97
92
 
98
93
 
99
94
  class AssetMappingResponse(ResponseResource[AssetMappingClassicRequest]):
@@ -0,0 +1,45 @@
1
+ from cognite_toolkit._cdf_tk.client.data_classes.base import RequestResource, ResponseResource
2
+
3
+ from .identifiers import ExternalId, InternalOrExternalId
4
+ from .instance_api import NodeReference
5
+
6
+
7
+ class TimeSeriesRequest(RequestResource):
8
+ external_id: str | None = None
9
+ name: str | None = None
10
+ is_sting: bool = False
11
+ metadata: dict[str, str] | None = None
12
+ unit: str | None = None
13
+ unit_external_id: str | None = None
14
+ asset_id: int | None = None
15
+ is_step: bool = False
16
+ description: str | None = None
17
+ security_categories: list[int] | None = None
18
+ data_set_id: int | None = None
19
+
20
+ def as_id(self) -> InternalOrExternalId:
21
+ if self.external_id is None:
22
+ raise ValueError("Cannot convert TimeSeriesRequest to ExternalId when external_id is None")
23
+ return ExternalId(external_id=self.external_id)
24
+
25
+
26
+ class TimeSeriesResponse(ResponseResource[TimeSeriesRequest]):
27
+ id: int
28
+ instance_id: NodeReference | None = None
29
+ external_id: str | None = None
30
+ name: str | None = None
31
+ is_sting: bool
32
+ metadata: dict[str, str] | None = None
33
+ unit: str | None = None
34
+ type: str
35
+ unit_external_id: str | None = None
36
+ asset_id: int | None = None
37
+ is_step: bool
38
+ description: str | None = None
39
+ security_categories: list[int] | None = None
40
+ data_set_id: int | None = None
41
+ created_time: int
42
+ last_updated_time: int
43
+
44
+ def as_request_resource(self) -> TimeSeriesRequest:
45
+ return TimeSeriesRequest.model_validate(self.dump())
@@ -1,5 +1,6 @@
1
1
  from ._client import HTTPClient
2
2
  from ._data_classes import (
3
+ T_COVARIANT_ID,
3
4
  DataBodyRequest,
4
5
  ErrorDetails,
5
6
  FailedRequestItems,
@@ -10,6 +11,7 @@ from ._data_classes import (
10
11
  ItemMessage,
11
12
  ItemsRequest,
12
13
  ParamRequest,
14
+ RequestItem,
13
15
  RequestMessage,
14
16
  ResponseList,
15
17
  ResponseMessage,
@@ -18,7 +20,6 @@ from ._data_classes import (
18
20
  SuccessResponseItems,
19
21
  )
20
22
  from ._data_classes2 import (
21
- BaseModelObject,
22
23
  ErrorDetails2,
23
24
  FailedRequest2,
24
25
  FailedResponse2,
@@ -29,13 +30,12 @@ from ._data_classes2 import (
29
30
  ItemsResultMessage2,
30
31
  ItemsSuccessResponse2,
31
32
  RequestMessage2,
32
- RequestResource,
33
33
  SuccessResponse2,
34
34
  )
35
35
  from ._exception import ToolkitAPIError
36
36
 
37
37
  __all__ = [
38
- "BaseModelObject",
38
+ "T_COVARIANT_ID",
39
39
  "DataBodyRequest",
40
40
  "ErrorDetails",
41
41
  "ErrorDetails2",
@@ -56,9 +56,9 @@ __all__ = [
56
56
  "ItemsResultMessage2",
57
57
  "ItemsSuccessResponse2",
58
58
  "ParamRequest",
59
+ "RequestItem",
59
60
  "RequestMessage",
60
61
  "RequestMessage2",
61
- "RequestResource",
62
62
  "ResponseList",
63
63
  "ResponseMessage",
64
64
  "SimpleBodyRequest",
@@ -10,9 +10,7 @@ import httpx
10
10
  from cognite.client import global_config
11
11
  from rich.console import Console
12
12
 
13
- from cognite_toolkit._cdf_tk.tk_warnings import HighSeverityWarning
14
- from cognite_toolkit._cdf_tk.utils.auxiliary import get_current_toolkit_version, get_user_agent
15
- from cognite_toolkit._cdf_tk.utils.http_client._data_classes import (
13
+ from cognite_toolkit._cdf_tk.client.http_client._data_classes import (
16
14
  BodyRequest,
17
15
  DataBodyRequest,
18
16
  FailedRequestMessage,
@@ -23,7 +21,7 @@ from cognite_toolkit._cdf_tk.utils.http_client._data_classes import (
23
21
  ResponseList,
24
22
  ResponseMessage,
25
23
  )
26
- from cognite_toolkit._cdf_tk.utils.http_client._data_classes2 import (
24
+ from cognite_toolkit._cdf_tk.client.http_client._data_classes2 import (
27
25
  BaseRequestMessage,
28
26
  ErrorDetails2,
29
27
  FailedRequest2,
@@ -38,6 +36,8 @@ from cognite_toolkit._cdf_tk.utils.http_client._data_classes2 import (
38
36
  RequestMessage2,
39
37
  SuccessResponse2,
40
38
  )
39
+ from cognite_toolkit._cdf_tk.tk_warnings import HighSeverityWarning
40
+ from cognite_toolkit._cdf_tk.utils.auxiliary import get_current_toolkit_version, get_user_agent
41
41
  from cognite_toolkit._cdf_tk.utils.useful_types import PrimitiveType
42
42
 
43
43
  if sys.version_info >= (3, 11):
@@ -414,7 +414,7 @@ class HTTPClient:
414
414
  if message.tracker and message.tracker.limit_reached():
415
415
  return [
416
416
  ItemsFailedRequest2(
417
- ids=[item.as_id() for item in message.items],
417
+ ids=[str(item) for item in message.items],
418
418
  error_message=f"Aborting further splitting of requests after {message.tracker.failed_split_count} failed attempts.",
419
419
  )
420
420
  ]
@@ -464,7 +464,7 @@ class HTTPClient:
464
464
  if 200 <= response.status_code < 300:
465
465
  return [
466
466
  ItemsSuccessResponse2(
467
- ids=[item.as_id() for item in request.items],
467
+ ids=[str(item) for item in request.items],
468
468
  status_code=response.status_code,
469
469
  body=response.text,
470
470
  content=response.content,
@@ -480,7 +480,7 @@ class HTTPClient:
480
480
  if splits[0].tracker and splits[0].tracker.limit_reached():
481
481
  return [
482
482
  ItemsFailedResponse2(
483
- ids=[item.as_id() for item in request.items],
483
+ ids=[str(item) for item in request.items],
484
484
  status_code=response.status_code,
485
485
  body=response.text,
486
486
  error=ErrorDetails2.from_response(response),
@@ -494,7 +494,7 @@ class HTTPClient:
494
494
  # Permanent failure
495
495
  return [
496
496
  ItemsFailedResponse2(
497
- ids=[item.as_id() for item in request.items],
497
+ ids=[str(item) for item in request.items],
498
498
  status_code=response.status_code,
499
499
  body=response.text,
500
500
  error=ErrorDetails2.from_response(response),
@@ -516,7 +516,7 @@ class HTTPClient:
516
516
  error_msg = f"Unexpected exception: {e!s}"
517
517
  return [
518
518
  ItemsFailedRequest2(
519
- ids=[item.as_id() for item in request.items],
519
+ ids=[str(item) for item in request.items],
520
520
  error_message=error_msg,
521
521
  )
522
522
  ]
@@ -530,7 +530,7 @@ class HTTPClient:
530
530
 
531
531
  return [
532
532
  ItemsFailedRequest2(
533
- ids=[item.as_id() for item in request.items],
533
+ ids=[str(item) for item in request.items],
534
534
  error_message=error_msg,
535
535
  )
536
536
  ]