cognite-toolkit 0.7.43__py3-none-any.whl → 0.7.44__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 (50) hide show
  1. cognite_toolkit/_cdf_tk/client/_toolkit_client.py +6 -0
  2. cognite_toolkit/_cdf_tk/client/api/filemetadata.py +145 -0
  3. cognite_toolkit/_cdf_tk/client/api/raw.py +174 -0
  4. cognite_toolkit/_cdf_tk/client/api/simulator_models.py +118 -0
  5. cognite_toolkit/_cdf_tk/client/api/simulators.py +8 -0
  6. cognite_toolkit/_cdf_tk/client/cdf_client/__init__.py +2 -1
  7. cognite_toolkit/_cdf_tk/client/cdf_client/api.py +40 -6
  8. cognite_toolkit/_cdf_tk/client/data_classes/annotation.py +79 -0
  9. cognite_toolkit/_cdf_tk/client/data_classes/base.py +13 -3
  10. cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/__init__.py +16 -0
  11. cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/_instance.py +143 -0
  12. cognite_toolkit/_cdf_tk/client/data_classes/data_modeling/_references.py +8 -0
  13. cognite_toolkit/_cdf_tk/client/data_classes/dataset.py +35 -0
  14. cognite_toolkit/_cdf_tk/client/data_classes/extraction_pipeline.py +59 -0
  15. cognite_toolkit/_cdf_tk/client/data_classes/filemetadata.py +7 -1
  16. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_destination.py +34 -0
  17. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_job.py +134 -0
  18. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_mapping.py +72 -0
  19. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/__init__.py +63 -0
  20. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_auth.py +63 -0
  21. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_base.py +26 -0
  22. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_certificate.py +20 -0
  23. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_eventhub.py +31 -0
  24. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_kafka.py +53 -0
  25. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_mqtt.py +36 -0
  26. cognite_toolkit/_cdf_tk/client/data_classes/hosted_extractor_source/_rest.py +49 -0
  27. cognite_toolkit/_cdf_tk/client/data_classes/identifiers.py +8 -0
  28. cognite_toolkit/_cdf_tk/client/data_classes/label.py +27 -0
  29. cognite_toolkit/_cdf_tk/client/data_classes/raw.py +3 -2
  30. cognite_toolkit/_cdf_tk/client/data_classes/securitycategory.py +24 -0
  31. cognite_toolkit/_cdf_tk/client/data_classes/sequence.py +45 -0
  32. cognite_toolkit/_cdf_tk/client/data_classes/transformation.py +140 -0
  33. cognite_toolkit/_cdf_tk/client/data_classes/workflow.py +27 -0
  34. cognite_toolkit/_cdf_tk/client/data_classes/workflow_trigger.py +63 -0
  35. cognite_toolkit/_cdf_tk/client/data_classes/workflow_version.py +155 -0
  36. cognite_toolkit/_cdf_tk/client/testing.py +5 -0
  37. cognite_toolkit/_cdf_tk/commands/_migrate/conversion.py +4 -3
  38. cognite_toolkit/_cdf_tk/cruds/_data_cruds.py +7 -3
  39. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/file.py +56 -59
  40. cognite_toolkit/_cdf_tk/cruds/_resource_cruds/relationship.py +1 -1
  41. cognite_toolkit/_cdf_tk/storageio/_asset_centric.py +34 -29
  42. cognite_toolkit/_cdf_tk/storageio/_file_content.py +22 -19
  43. cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
  44. cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
  45. cognite_toolkit/_resources/cdf.toml +1 -1
  46. cognite_toolkit/_version.py +1 -1
  47. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/METADATA +11 -1
  48. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/RECORD +50 -24
  49. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/WHEEL +1 -1
  50. {cognite_toolkit-0.7.43.dist-info → cognite_toolkit-0.7.44.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,79 @@
1
+ from typing import Any, Literal, TypeAlias
2
+
3
+ from pydantic import Field, JsonValue
4
+
5
+ from cognite_toolkit._cdf_tk.client.data_classes.base import BaseModelObject, RequestUpdateable, ResponseResource
6
+
7
+ from .identifiers import InternalId
8
+
9
+ AnnotationStatus: TypeAlias = Literal["suggested", "rejected", "approved"]
10
+ AnnotationType: TypeAlias = Literal[
11
+ "diagrams.AssetLink",
12
+ "diagrams.FileLink",
13
+ "diagrams.InstanceLink",
14
+ "diagrams.Junction",
15
+ "diagrams.Line",
16
+ "diagrams.UnhandledSymbolObject",
17
+ "diagrams.UnhandledTextObject",
18
+ "documents.ExtractedText",
19
+ "forms.Detection",
20
+ "images.AssetLink",
21
+ "images.Classification",
22
+ "images.InstanceLink",
23
+ "images.KeypointCollection",
24
+ "images.ObjectDetection",
25
+ "images.TextRegion",
26
+ "isoplan.IsoPlanAnnotation",
27
+ "pointcloud.BoundingVolume",
28
+ ]
29
+
30
+
31
+ class Annotation(BaseModelObject):
32
+ annotated_resource_type: str
33
+ annotated_resource_id: int
34
+ annotation_type: AnnotationType
35
+ creating_app: str
36
+ creating_app_version: str
37
+ creating_user: str | None
38
+ data: dict[str, JsonValue]
39
+ status: AnnotationStatus
40
+
41
+
42
+ class AnnotationRequest(Annotation, RequestUpdateable):
43
+ """Request data class for annotations."""
44
+
45
+ # The 'id' field is not part of the request when creating a new resource,
46
+ # but is needed when updating an existing resource.
47
+ id: int | None = Field(default=None, exclude=True)
48
+
49
+ def as_id(self) -> InternalId:
50
+ if self.id is None:
51
+ raise ValueError("Cannot convert AnnotationRequest to InternalId when id is None")
52
+ return InternalId(id=self.id)
53
+
54
+ def as_update(self, mode: Literal["patch", "replace"]) -> dict[str, Any]:
55
+ """Converts the request to an update payload for the API."""
56
+ if self.id is None:
57
+ raise ValueError("id must be provided to create an update dictionary")
58
+ return {
59
+ "id": self.id,
60
+ "update": {
61
+ "annotationType": {"set": self.annotation_type},
62
+ "data": {"set": self.data},
63
+ "status": {"set": self.status},
64
+ },
65
+ }
66
+
67
+
68
+ class AnnotationResponse(Annotation, ResponseResource[AnnotationRequest]):
69
+ """Response data class for annotations."""
70
+
71
+ id: int
72
+ created_time: int
73
+ last_updated_time: int
74
+
75
+ def as_id(self) -> InternalId:
76
+ return InternalId(id=self.id)
77
+
78
+ def as_request_resource(self) -> AnnotationRequest:
79
+ return AnnotationRequest.model_validate(self.dump(), extra="ignore")
@@ -20,11 +20,21 @@ class BaseModelObject(BaseModel):
20
20
  # We allow extra fields to support forward compatibility.
21
21
  model_config = ConfigDict(alias_generator=to_camel, extra="allow", populate_by_name=True)
22
22
 
23
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
23
+ def dump(self, camel_case: bool = True, exclude_extra: bool = False) -> dict[str, Any]:
24
24
  """Dump the resource to a dictionary.
25
25
 
26
- This is the default serialization method for request resources.
26
+ Args:
27
+ camel_case (bool): Whether to use camelCase for the keys. Default is True.
28
+ exclude_extra (bool): Whether to exclude extra fields not defined in the model. Default is False.
29
+
27
30
  """
31
+ if exclude_extra:
32
+ return self.model_dump(
33
+ mode="json",
34
+ by_alias=camel_case,
35
+ exclude_unset=True,
36
+ exclude=set(self.__pydantic_extra__) if self.__pydantic_extra__ else None,
37
+ )
28
38
  return self.model_dump(mode="json", by_alias=camel_case, exclude_unset=True)
29
39
 
30
40
  @classmethod
@@ -39,7 +49,7 @@ class Identifier(BaseModelObject):
39
49
 
40
50
  model_config = ConfigDict(alias_generator=to_camel, extra="ignore", populate_by_name=True, frozen=True)
41
51
 
42
- def dump(self, camel_case: bool = True) -> dict[str, Any]:
52
+ def dump(self, camel_case: bool = True, exclude_extra: bool = False) -> dict[str, Any]:
43
53
  """Dump the resource to a dictionary.
44
54
 
45
55
  This is the default serialization method for request resources.
@@ -42,6 +42,15 @@ from ._indexes import (
42
42
  IndexDefinition,
43
43
  InvertedIndex,
44
44
  )
45
+ from ._instance import (
46
+ EdgeRequest,
47
+ EdgeResponse,
48
+ InstanceDefinition,
49
+ InstanceResponseDefinition,
50
+ InstanceSource,
51
+ NodeRequest,
52
+ NodeResponse,
53
+ )
45
54
  from ._references import (
46
55
  ContainerConstraintReference,
47
56
  ContainerDirectReference,
@@ -99,6 +108,8 @@ __all__ = [
99
108
  "DateProperty",
100
109
  "DirectNodeRelation",
101
110
  "EdgeProperty",
111
+ "EdgeRequest",
112
+ "EdgeResponse",
102
113
  "EnumProperty",
103
114
  "EnumValue",
104
115
  "FileCDFExternalIdReference",
@@ -108,6 +119,9 @@ __all__ = [
108
119
  "Index",
109
120
  "IndexAdapter",
110
121
  "IndexDefinition",
122
+ "InstanceDefinition",
123
+ "InstanceResponseDefinition",
124
+ "InstanceSource",
111
125
  "Int32Property",
112
126
  "Int64Property",
113
127
  "InvertedIndex",
@@ -117,6 +131,8 @@ __all__ = [
117
131
  "MultiReverseDirectRelationPropertyRequest",
118
132
  "MultiReverseDirectRelationPropertyResponse",
119
133
  "NodeReference",
134
+ "NodeRequest",
135
+ "NodeResponse",
120
136
  "PropertyTypeDefinition",
121
137
  "RequiresConstraintDefinition",
122
138
  "ReverseDirectRelationProperty",
@@ -0,0 +1,143 @@
1
+ from abc import ABC
2
+ from typing import Any, Generic, Literal
3
+
4
+ from pydantic import JsonValue, field_serializer, field_validator
5
+
6
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
7
+ BaseModelObject,
8
+ RequestResource,
9
+ ResponseResource,
10
+ T_RequestResource,
11
+ )
12
+
13
+ from ._references import ContainerReference, EdgeReference, NodeReference, ViewReference
14
+
15
+
16
+ class InstanceDefinition(BaseModelObject, ABC):
17
+ """Base class for node and edge instances."""
18
+
19
+ instance_type: str # "node" | "edge"
20
+ space: str
21
+ external_id: str
22
+
23
+
24
+ class InstanceSource(BaseModelObject):
25
+ source: ViewReference | ContainerReference
26
+ properties: dict[str, JsonValue] | None = None
27
+
28
+
29
+ class InstanceRequestDefinition(InstanceDefinition, RequestResource, ABC):
30
+ existing_version: int | None = None
31
+ sources: list[InstanceSource]
32
+
33
+
34
+ class InstanceResponseDefinition(InstanceDefinition, ResponseResource, Generic[T_RequestResource], ABC):
35
+ version: int
36
+ created_time: int
37
+ last_updated_time: int
38
+ deleted_time: int | None = None
39
+ properties: dict[ViewReference | ContainerReference, dict[str, JsonValue]] | None = None
40
+
41
+ @field_validator("properties", mode="before")
42
+ def parse_reference(cls, value: Any) -> Any:
43
+ if not isinstance(value, dict):
44
+ return value
45
+ parsed: dict[ViewReference | ContainerReference, dict[str, Any]] = {}
46
+ for space, inner_dict in value.items():
47
+ if not isinstance(inner_dict, dict) or not isinstance(space, str):
48
+ raise ValueError(
49
+ f"Invalid properties format expected dict[str, dict[...]], got: dict[{type(space).__name__}, {type(inner_dict).__name__}]"
50
+ )
51
+ for view_or_container_identifier, prop in inner_dict.items():
52
+ if not isinstance(view_or_container_identifier, str):
53
+ raise ValueError(
54
+ "Invalid properties format expected dict[str, dict[str, ...]]], "
55
+ f"got: dict[{type(space).__name__}, "
56
+ f"dict[{type(view_or_container_identifier).__name__}, ...]]"
57
+ )
58
+ source_ref: ViewReference | ContainerReference
59
+ if "/" in view_or_container_identifier:
60
+ external_id, version = view_or_container_identifier.split("/", 1)
61
+ source_ref = ViewReference(space=space, external_id=external_id, version=version)
62
+ else:
63
+ source_ref = ContainerReference(space=space, external_id=view_or_container_identifier)
64
+ parsed[source_ref] = prop
65
+ return parsed
66
+
67
+ @field_serializer("properties", mode="plain")
68
+ def serialize_properties(self, value: dict[ViewReference | ContainerReference, dict[str, Any]] | None) -> Any:
69
+ if value is None:
70
+ return None
71
+ serialized: dict[str, dict[str, Any]] = {}
72
+ for source_ref, props in value.items():
73
+ space = source_ref.space
74
+ if space not in serialized:
75
+ serialized[space] = {}
76
+ if isinstance(source_ref, ViewReference):
77
+ identifier = f"{source_ref.external_id}/{source_ref.version}"
78
+ else:
79
+ identifier = source_ref.external_id
80
+ serialized[space][identifier] = props
81
+ return serialized
82
+
83
+
84
+ class NodeRequest(InstanceRequestDefinition):
85
+ """A node request resource."""
86
+
87
+ instance_type: Literal["node"] = "node"
88
+ type: NodeReference | None = None
89
+
90
+ def as_id(self) -> NodeReference:
91
+ return NodeReference(space=self.space, external_id=self.external_id)
92
+
93
+
94
+ class EdgeRequest(InstanceRequestDefinition):
95
+ """An edge request resource."""
96
+
97
+ instance_type: Literal["edge"] = "edge"
98
+ type: NodeReference
99
+ start_node: NodeReference
100
+ end_node: NodeReference
101
+
102
+ def as_id(self) -> EdgeReference:
103
+ return EdgeReference(space=self.space, external_id=self.external_id)
104
+
105
+
106
+ class NodeResponse(InstanceResponseDefinition[NodeRequest]):
107
+ """A node response from the API."""
108
+
109
+ instance_type: Literal["node"] = "node"
110
+ type: NodeReference | None = None
111
+
112
+ def as_id(self) -> NodeReference:
113
+ return NodeReference(space=self.space, external_id=self.external_id)
114
+
115
+ def as_request_resource(self) -> NodeRequest:
116
+ dumped = self.dump()
117
+ if self.properties:
118
+ dumped["sources"] = [
119
+ InstanceSource(source=source_ref, properties=props) for source_ref, props in self.properties.items()
120
+ ]
121
+ dumped["existingVersion"] = dumped.pop("version", None)
122
+ return NodeRequest.model_validate(dumped, extra="ignore")
123
+
124
+
125
+ class EdgeResponse(InstanceResponseDefinition[EdgeRequest]):
126
+ """An edge response from the API."""
127
+
128
+ instance_type: Literal["edge"] = "edge"
129
+ type: NodeReference
130
+ start_node: NodeReference
131
+ end_node: NodeReference
132
+
133
+ def as_id(self) -> EdgeReference:
134
+ return EdgeReference(space=self.space, external_id=self.external_id)
135
+
136
+ def as_request_resource(self) -> EdgeRequest:
137
+ dumped = self.dump()
138
+ if self.properties:
139
+ dumped["sources"] = [
140
+ InstanceSource(source=source_ref, properties=props) for source_ref, props in self.properties.items()
141
+ ]
142
+ dumped["existingVersion"] = dumped.pop("version", None)
143
+ return EdgeRequest.model_validate(dumped, extra="ignore")
@@ -48,6 +48,14 @@ class NodeReference(Identifier):
48
48
  return f"{self.space}:{self.external_id}"
49
49
 
50
50
 
51
+ class EdgeReference(Identifier):
52
+ space: str
53
+ external_id: str
54
+
55
+ def __str__(self) -> str:
56
+ return f"{self.space}:{self.external_id}"
57
+
58
+
51
59
  class ContainerDirectReference(Identifier):
52
60
  source: ContainerReference
53
61
  identifier: str
@@ -0,0 +1,35 @@
1
+ from typing import ClassVar
2
+
3
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
4
+ BaseModelObject,
5
+ RequestUpdateable,
6
+ ResponseResource,
7
+ )
8
+
9
+ from .identifiers import ExternalId
10
+
11
+
12
+ class DataSet(BaseModelObject):
13
+ external_id: str | None = None
14
+ name: str | None = None
15
+ description: str | None = None
16
+ metadata: dict[str, str] | None = None
17
+ write_protected: bool = False
18
+
19
+ def as_id(self) -> ExternalId:
20
+ if self.external_id is None:
21
+ raise ValueError("Cannot convert DataSet to ExternalId when external_id is None")
22
+ return ExternalId(external_id=self.external_id)
23
+
24
+
25
+ class DataSetRequest(DataSet, RequestUpdateable):
26
+ container_fields: ClassVar[frozenset[str]] = frozenset({"metadata"})
27
+
28
+
29
+ class DataSetResponse(DataSet, ResponseResource[DataSetRequest]):
30
+ id: int
31
+ created_time: int
32
+ last_updated_time: int
33
+
34
+ def as_request_resource(self) -> DataSetRequest:
35
+ return DataSetRequest.model_validate(self.dump(), extra="ignore")
@@ -0,0 +1,59 @@
1
+ from typing import ClassVar
2
+
3
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
4
+ BaseModelObject,
5
+ RequestUpdateable,
6
+ ResponseResource,
7
+ )
8
+
9
+ from .identifiers import ExternalId
10
+
11
+
12
+ class RawTable(BaseModelObject):
13
+ db_name: str
14
+ table_name: str
15
+
16
+
17
+ class Contact(BaseModelObject):
18
+ name: str | None = None
19
+ email: str | None = None
20
+ role: str | None = None
21
+ send_notification: bool | None = None
22
+
23
+
24
+ class NotificationConfig(BaseModelObject):
25
+ allowed_not_seen_range_in_minutes: int | None = None
26
+
27
+
28
+ class ExtractionPipeline(BaseModelObject):
29
+ external_id: str
30
+ name: str
31
+ description: str | None = None
32
+ data_set_id: int
33
+ raw_tables: list[RawTable] | None = None
34
+ schedule: str | None = None
35
+ contacts: list[Contact] | None = None
36
+ metadata: dict[str, str] | None = None
37
+ source: str | None = None
38
+ documentation: str | None = None
39
+ notification_config: NotificationConfig | None = None
40
+ created_by: str | None = None
41
+
42
+ def as_id(self) -> ExternalId:
43
+ return ExternalId(external_id=self.external_id)
44
+
45
+
46
+ class ExtractionPipelineRequest(ExtractionPipeline, RequestUpdateable):
47
+ container_fields: ClassVar[frozenset[str]] = frozenset({"raw_tables", "contacts", "metadata"})
48
+ non_nullable_fields: ClassVar[frozenset[str]] = frozenset(
49
+ {"documentation", "source", "notification_config", "schedule", "description"}
50
+ )
51
+
52
+
53
+ class ExtractionPipelineResponse(ExtractionPipeline, ResponseResource[ExtractionPipelineRequest]):
54
+ id: int
55
+ created_time: int
56
+ last_updated_time: int
57
+
58
+ def as_request_resource(self) -> ExtractionPipelineRequest:
59
+ return ExtractionPipelineRequest.model_validate(self.dump(), extra="ignore")
@@ -1,6 +1,6 @@
1
1
  from typing import ClassVar, Literal
2
2
 
3
- from pydantic import JsonValue
3
+ from pydantic import Field, JsonValue
4
4
 
5
5
  from cognite_toolkit._cdf_tk.client.data_classes.base import BaseModelObject, RequestUpdateable, ResponseResource
6
6
 
@@ -32,6 +32,10 @@ class FileMetadata(BaseModelObject):
32
32
  class FileMetadataRequest(FileMetadata, RequestUpdateable):
33
33
  container_fields: ClassVar[frozenset[str]] = frozenset({"metadata", "labels", "asset_ids", "security_categories"})
34
34
  non_nullable_fields: ClassVar[frozenset[str]] = frozenset({"asset_ids", "security_categories"})
35
+ # This field is not part of the request when creating or updating a resource
36
+ # but we added it here for convenience so that it is available when converting
37
+ # from response to request.
38
+ instance_id: NodeReference | None = Field(default=None, exclude=True)
35
39
 
36
40
 
37
41
  class FileMetadataResponse(FileMetadata, ResponseResource[FileMetadataRequest]):
@@ -41,6 +45,8 @@ class FileMetadataResponse(FileMetadata, ResponseResource[FileMetadataRequest]):
41
45
  uploaded: bool
42
46
  id: int
43
47
  instance_id: NodeReference | None = None
48
+ # This field is required in the upload endpoint response, but not in any other file metadata response
49
+ upload_url: str | None = None
44
50
 
45
51
  def as_request_resource(self) -> FileMetadataRequest:
46
52
  return FileMetadataRequest.model_validate(self.dump(), extra="ignore")
@@ -0,0 +1,34 @@
1
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
2
+ BaseModelObject,
3
+ RequestUpdateable,
4
+ ResponseResource,
5
+ )
6
+
7
+ from .identifiers import ExternalId
8
+
9
+
10
+ class Credentials(BaseModelObject):
11
+ nonce: str
12
+
13
+
14
+ class HostedExtractorDestination(BaseModelObject):
15
+ external_id: str
16
+ target_data_set_id: int | None = None
17
+
18
+ def as_id(self) -> ExternalId:
19
+ return ExternalId(external_id=self.external_id)
20
+
21
+
22
+ class HostedExtractorDestinationRequest(HostedExtractorDestination, RequestUpdateable):
23
+ credentials: Credentials | None = None
24
+
25
+
26
+ class HostedExtractorDestinationResponse(
27
+ HostedExtractorDestination, ResponseResource[HostedExtractorDestinationRequest]
28
+ ):
29
+ session_id: int | None = None
30
+ created_time: int
31
+ last_updated_time: int
32
+
33
+ def as_request_resource(self) -> HostedExtractorDestinationRequest:
34
+ return HostedExtractorDestinationRequest.model_validate(self.dump(), extra="ignore")
@@ -0,0 +1,134 @@
1
+ from typing import Annotated, Literal
2
+
3
+ from pydantic import Field, JsonValue
4
+
5
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
6
+ BaseModelObject,
7
+ RequestUpdateable,
8
+ ResponseResource,
9
+ )
10
+
11
+ from .identifiers import ExternalId
12
+
13
+
14
+ class JobFormatDefinition(BaseModelObject):
15
+ type: str
16
+
17
+
18
+ class PrefixConfig(BaseModelObject):
19
+ from_topic: bool | None = None
20
+ prefix: str | None = None
21
+
22
+
23
+ class SpaceRef(BaseModelObject):
24
+ space: str
25
+
26
+
27
+ class CogniteFormat(JobFormatDefinition):
28
+ type: Literal["cognite"] = "cognite"
29
+ encoding: str | None = None
30
+ compression: str | None = None
31
+ prefix: PrefixConfig | None = None
32
+ data_models: list[SpaceRef] | None = None
33
+
34
+
35
+ class CustomFormat(JobFormatDefinition):
36
+ type: Literal["custom"] = "custom"
37
+ encoding: str | None = None
38
+ compression: str | None = None
39
+ mapping_id: str
40
+
41
+
42
+ class RockwellFormat(JobFormatDefinition):
43
+ type: Literal["rockwell"] = "rockwell"
44
+ encoding: str | None = None
45
+ compression: str | None = None
46
+ prefix: PrefixConfig | None = None
47
+ data_models: list[SpaceRef] | None = None
48
+
49
+
50
+ class ValueFormat(JobFormatDefinition):
51
+ type: Literal["value"] = "value"
52
+ encoding: str | None = None
53
+ compression: str | None = None
54
+ prefix: PrefixConfig | None = None
55
+ data_models: list[SpaceRef] | None = None
56
+
57
+
58
+ JobFormat = Annotated[
59
+ CogniteFormat | CustomFormat | RockwellFormat | ValueFormat,
60
+ Field(discriminator="type"),
61
+ ]
62
+
63
+
64
+ class IncrementalLoadDefinition(BaseModelObject):
65
+ type: str
66
+
67
+
68
+ class BodyIncrementalLoad(IncrementalLoadDefinition):
69
+ type: Literal["body"] = "body"
70
+ value: str
71
+
72
+
73
+ class NextUrlIncrementalLoad(IncrementalLoadDefinition):
74
+ type: Literal["nextUrl"] = "nextUrl"
75
+ value: str
76
+
77
+
78
+ class HeaderIncrementalLoad(IncrementalLoadDefinition):
79
+ type: Literal["headerValue"] = "headerValue"
80
+ key: str
81
+ value: str
82
+
83
+
84
+ class QueryParamIncrementalLoad(IncrementalLoadDefinition):
85
+ type: Literal["queryParam"] = "queryParam"
86
+ key: str
87
+ value: str
88
+
89
+
90
+ class MQTTConfig(BaseModelObject):
91
+ topic_filter: str
92
+
93
+
94
+ class KafkaConfig(BaseModelObject):
95
+ topic: str
96
+ partitions: int | None = None
97
+
98
+
99
+ class RestConfig(BaseModelObject):
100
+ interval: Literal["5m", "15m", "1h", "6h", "12h", "1d"]
101
+ path: str
102
+ method: Literal["get", "post"] | None = None
103
+ body: JsonValue | None = None
104
+ query: dict[str, str] | None = None
105
+ headers: dict[str, str] | None = None
106
+ incremental_load: BodyIncrementalLoad | HeaderIncrementalLoad | QueryParamIncrementalLoad | None = Field(
107
+ None, discriminator="type"
108
+ )
109
+ pagination: (
110
+ BodyIncrementalLoad | NextUrlIncrementalLoad | HeaderIncrementalLoad | QueryParamIncrementalLoad | None
111
+ ) = Field(None, discriminator="type")
112
+
113
+
114
+ class HostedExtractorJob(BaseModelObject):
115
+ external_id: str
116
+ destination_id: str
117
+ source_id: str
118
+ format: JobFormat
119
+ config: MQTTConfig | KafkaConfig | RestConfig
120
+
121
+ def as_id(self) -> ExternalId:
122
+ return ExternalId(external_id=self.external_id)
123
+
124
+
125
+ class HostedExtractorJobRequest(HostedExtractorJob, RequestUpdateable): ...
126
+
127
+
128
+ class HostedExtractorJobResponse(HostedExtractorJob, ResponseResource[HostedExtractorJobRequest]):
129
+ status: str | None = None
130
+ created_time: int
131
+ last_updated_time: int
132
+
133
+ def as_request_resource(self) -> HostedExtractorJobRequest:
134
+ return HostedExtractorJobRequest.model_validate(self.dump(), extra="ignore")
@@ -0,0 +1,72 @@
1
+ from typing import Annotated, Literal
2
+
3
+ from pydantic import Field
4
+
5
+ from cognite_toolkit._cdf_tk.client.data_classes.base import (
6
+ BaseModelObject,
7
+ RequestUpdateable,
8
+ ResponseResource,
9
+ )
10
+
11
+ from .identifiers import ExternalId
12
+
13
+
14
+ class Mapping(BaseModelObject):
15
+ expression: str
16
+
17
+
18
+ class MappingInputDefinition(BaseModelObject):
19
+ type: str
20
+
21
+
22
+ class ProtobufFile(BaseModelObject):
23
+ file_name: str
24
+ content: str
25
+
26
+
27
+ class ProtobufInput(BaseModelObject):
28
+ type: Literal["protobuf"] = "protobuf"
29
+ message_name: str
30
+ files: list[ProtobufFile]
31
+
32
+
33
+ class CSVInput(BaseModelObject):
34
+ type: Literal["csv"] = "csv"
35
+ delimiter: str = ","
36
+ custom_keys: list[str] | None = None
37
+
38
+
39
+ class XMLInput(BaseModelObject):
40
+ type: Literal["xml"] = "xml"
41
+
42
+
43
+ class JSONInput(BaseModelObject):
44
+ type: Literal["json"] = "json"
45
+
46
+
47
+ MappingInput = Annotated[
48
+ ProtobufInput | CSVInput | XMLInput | JSONInput,
49
+ Field(discriminator="type"),
50
+ ]
51
+
52
+
53
+ class HostedExtractorMapping(BaseModelObject):
54
+ external_id: str
55
+ mapping: Mapping
56
+ published: bool
57
+
58
+ def as_id(self) -> ExternalId:
59
+ return ExternalId(external_id=self.external_id)
60
+
61
+
62
+ class HostedExtractorMappingRequest(HostedExtractorMapping, RequestUpdateable):
63
+ input: MappingInput | None = None
64
+
65
+
66
+ class HostedExtractorMappingResponse(HostedExtractorMapping, ResponseResource[HostedExtractorMappingRequest]):
67
+ input: MappingInput
68
+ created_time: int
69
+ last_updated_time: int
70
+
71
+ def as_request_resource(self) -> HostedExtractorMappingRequest:
72
+ return HostedExtractorMappingRequest.model_validate(self.dump(), extra="ignore")