cognite-neat 0.117.1__py3-none-any.whl → 0.117.2__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.

Potentially problematic release.


This version of cognite-neat might be problematic. Click here for more details.

@@ -0,0 +1,71 @@
1
+ import time
2
+ from collections.abc import Iterator
3
+ from typing import TYPE_CHECKING, Any, Literal
4
+
5
+ from cognite.client.data_classes.data_modeling import Edge, Node, ViewId
6
+ from cognite.client.data_classes.filters import Filter
7
+ from cognite.client.exceptions import CogniteAPIError
8
+ from cognite.client.utils.useful_types import SequenceNotStr
9
+
10
+ if TYPE_CHECKING:
11
+ from cognite.neat._client._api_client import NeatClient
12
+
13
+
14
+ class NeatInstancesAPI:
15
+ def __init__(self, client: "NeatClient") -> None:
16
+ self._client = client
17
+
18
+ def iterate(
19
+ self,
20
+ instance_type: Literal["node", "edge"] = "node",
21
+ space: str | SequenceNotStr[str] | None = None,
22
+ filter_: Filter | None = None,
23
+ source: ViewId | None = None,
24
+ ) -> Iterator[Node] | Iterator[Edge]:
25
+ """Neat specific implementation of the client.data_modeling.instances(...) method to account for 408.
26
+
27
+ In addition, we enforce sort based on the argument below (provided by Alex B.).
28
+ """
29
+ body: dict[str, Any] = {"limit": 1_000, "cursor": None, "instanceType": instance_type}
30
+ # Without a sort, the sort is implicitly by the internal id, as cursoring needs a stable sort.
31
+ # By making the sort be on external_id, Postgres should pick the index that's on
32
+ # (project_id, space, external_id) WHERE deleted_at IS NULL. In other words,
33
+ # avoiding soft deleted instances.
34
+ body["sort"] = [
35
+ {
36
+ "property": [instance_type, "externalId"],
37
+ "direction": "ascending",
38
+ }
39
+ ]
40
+ url = f"/api/{self._client._API_VERSION}/projects/{self._client.config.project}/models/instances/list"
41
+ filter_ = self._client.data_modeling.instances._merge_space_into_filter(instance_type, space, filter_)
42
+ if filter_:
43
+ body["filter"] = filter_.dump() if isinstance(filter_, Filter) else filter_
44
+ if source:
45
+ body["sources"] = [{"source": source.dump(include_type=True, camel_case=True)}]
46
+ last_limit_change: float = 0.0
47
+ while True:
48
+ try:
49
+ response = self._client.post(url=url, json=body)
50
+ except CogniteAPIError as e:
51
+ if e.code == 408 and body["limit"] > 1:
52
+ body["limit"] = body["limit"] // 2
53
+ last_limit_change = time.perf_counter()
54
+ continue
55
+ raise e
56
+ response_body = response.json()
57
+ yield from (
58
+ Node.load(item) if item.get("instanceType") == "node" else Edge.load(item)
59
+ for item in response_body["items"]
60
+ )
61
+ next_cursor = response_body.get("nextCursor")
62
+ if next_cursor is None:
63
+ break
64
+ body["cursor"] = next_cursor
65
+ # Increase the limit every 30 seconds to avoid fetching reduced
66
+ # instances for a long time after a 408. This limit is somewhat arbitrary,
67
+ # but it should be large enough to avoid many requests, but small enough
68
+ # to avoid fetching very slowly for a long time after a 408.
69
+ if (time.perf_counter() - last_limit_change) > 30.0 and body["limit"] < 1_000:
70
+ body["limit"] = min(int(body["limit"] * 1.5), 1_000)
71
+ last_limit_change = time.perf_counter()
@@ -3,6 +3,7 @@ from cognite.client import ClientConfig, CogniteClient
3
3
  from cognite.neat._utils.auth import _CLIENT_NAME
4
4
 
5
5
  from ._api.data_modeling_loaders import DataModelLoaderAPI
6
+ from ._api.neat_instances import NeatInstancesAPI
6
7
  from ._api.schema import SchemaAPI
7
8
 
8
9
 
@@ -15,3 +16,4 @@ class NeatClient(CogniteClient):
15
16
  self._config.client_name = _CLIENT_NAME
16
17
  self.loaders = DataModelLoaderAPI(self)
17
18
  self.schema = SchemaAPI(self)
19
+ self.instances = NeatInstancesAPI(self)
@@ -7,6 +7,7 @@ from cognite.client.testing import CogniteClientMock
7
7
  from cognite.neat._client._api_client import NeatClient
8
8
 
9
9
  from ._api.data_modeling_loaders import DataModelLoaderAPI
10
+ from ._api.neat_instances import NeatInstancesAPI
10
11
  from ._api.schema import SchemaAPI
11
12
 
12
13
 
@@ -23,6 +24,7 @@ class NeatClientMock(CogniteClientMock):
23
24
  super().__init__(*args, **kwargs)
24
25
  self.schema = SchemaAPI(self)
25
26
  self.loaders = DataModelLoaderAPI(self)
27
+ self.instances = NeatInstancesAPI(self)
26
28
 
27
29
 
28
30
  @contextmanager
@@ -3,13 +3,13 @@ import urllib.parse
3
3
  from collections.abc import Callable, Iterable, Iterator, Set
4
4
  from functools import cached_property
5
5
 
6
- from cognite.client import CogniteClient
7
6
  from cognite.client import data_modeling as dm
8
7
  from cognite.client.data_classes.data_modeling import DataModelIdentifier
9
- from cognite.client.data_classes.data_modeling.instances import Edge, Instance, InstanceSort, Node
8
+ from cognite.client.data_classes.data_modeling.instances import Edge, Instance, Node
10
9
  from cognite.client.utils.useful_types import SequenceNotStr
11
10
  from rdflib import RDF, Literal, Namespace, URIRef
12
11
 
12
+ from cognite.neat._client import NeatClient
13
13
  from cognite.neat._config import GLOBAL_CONFIG
14
14
  from cognite.neat._constants import DEFAULT_SPACE_URI, is_readonly_property
15
15
  from cognite.neat._issues.errors import ResourceRetrievalError
@@ -62,7 +62,7 @@ class DMSExtractor(BaseExtractor):
62
62
  @classmethod
63
63
  def from_data_model(
64
64
  cls,
65
- client: CogniteClient,
65
+ client: NeatClient,
66
66
  data_model: DataModelIdentifier,
67
67
  limit: int | None = None,
68
68
  overwrite_namespace: Namespace | None = None,
@@ -96,7 +96,7 @@ class DMSExtractor(BaseExtractor):
96
96
  @classmethod
97
97
  def from_views(
98
98
  cls,
99
- client: CogniteClient,
99
+ client: NeatClient,
100
100
  views: Iterable[dm.View],
101
101
  limit: int | None = None,
102
102
  overwrite_namespace: Namespace | None = None,
@@ -237,7 +237,7 @@ class DMSExtractor(BaseExtractor):
237
237
 
238
238
 
239
239
  class _ViewInstanceIterator(Iterable[Instance]):
240
- def __init__(self, client: CogniteClient, view: dm.View, instance_space: str | SequenceNotStr[str] | None = None):
240
+ def __init__(self, client: NeatClient, view: dm.View, instance_space: str | SequenceNotStr[str] | None = None):
241
241
  self.client = client
242
242
  self.view = view
243
243
  self.instance_space = instance_space
@@ -275,28 +275,20 @@ class _ViewInstanceIterator(Iterable[Instance]):
275
275
  }
276
276
  # All nodes and edges with properties
277
277
  if self.view.used_for in ("node", "all"):
278
- # Without a sort, the sort is implicitly by the internal id, as cursoring needs a stable sort.
279
- # By making the sort be on external_id, Postgres should pick the index
280
- # that's on (project_id, space, external_id)
281
- # WHERE deleted_at IS NULL. In other words, avoiding soft deleted instances.
282
- node_iterable: Iterable[Instance] = self.client.data_modeling.instances(
283
- chunk_size=None,
278
+ node_iterable: Iterable[Instance] = self.client.instances.iterate(
284
279
  instance_type="node",
285
- sources=[view_id],
280
+ source=view_id,
286
281
  space=self.instance_space,
287
- sort=InstanceSort(["node", "externalId"]),
288
282
  )
289
283
  if read_only_properties:
290
284
  node_iterable = self._remove_read_only_properties(node_iterable, read_only_properties, view_id)
291
285
  yield from node_iterable
292
286
 
293
287
  if self.view.used_for in ("edge", "all"):
294
- yield from self.client.data_modeling.instances(
295
- chunk_size=None,
288
+ yield from self.client.instances.iterate(
296
289
  instance_type="edge",
297
- sources=[view_id],
290
+ source=view_id,
298
291
  space=self.instance_space,
299
- sort=InstanceSort(["edge", "externalId"]),
300
292
  )
301
293
 
302
294
  for prop in self.view.properties.values():
@@ -304,14 +296,12 @@ class _ViewInstanceIterator(Iterable[Instance]):
304
296
  if prop.edge_source:
305
297
  # All edges with properties are extracted from the edge source
306
298
  continue
307
- yield from self.client.data_modeling.instances(
308
- chunk_size=None,
299
+ yield from self.client.instances.iterate(
309
300
  instance_type="edge",
310
- filter=dm.filters.Equals(
301
+ filter_=dm.filters.Equals(
311
302
  ["edge", "type"], {"space": prop.type.space, "externalId": prop.type.external_id}
312
303
  ),
313
304
  space=self.instance_space,
314
- sort=InstanceSort(["edge", "externalId"]),
315
305
  )
316
306
 
317
307
  @staticmethod
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.117.1"
1
+ __version__ = "0.117.2"
2
2
  __engine__ = "^2.0.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: cognite-neat
3
- Version: 0.117.1
3
+ Version: 0.117.2
4
4
  Summary: Knowledge graph transformation
5
5
  License: Apache-2.0
6
6
  Author: Nikola Vasiljevic
@@ -3,13 +3,14 @@ cognite/neat/_alpha.py,sha256=AVw3YiSwpOiV3fSoTbwTxd-p7WGlS-zgf4TPZCT_9vE,1163
3
3
  cognite/neat/_client/__init__.py,sha256=RQ7MwL8mwGqGHokRzsPqO3XStDzmI4-c12_gz1UPJ74,177
4
4
  cognite/neat/_client/_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  cognite/neat/_client/_api/data_modeling_loaders.py,sha256=LsB8k2erMZ3BJ_wLMIBhav7ykimLkV2QJjnbeC2xikE,39790
6
+ cognite/neat/_client/_api/neat_instances.py,sha256=BxFmErL5FX1FVupHWsZRBsMMMT0BtExpnioiM5XOSHo,3349
6
7
  cognite/neat/_client/_api/schema.py,sha256=K8iNuTKHayHGVldMWfY8N6KWG71hOpNIklWGsAkCPMY,6925
7
- cognite/neat/_client/_api_client.py,sha256=6cNMizDuqMJZiOqiNRLX46BEtlCB-BpgGLyypksRVYU,616
8
+ cognite/neat/_client/_api_client.py,sha256=wsNK3abwoIppleWzVZmoXe9Ia_wrU4QqOxnxxls3ipY,714
8
9
  cognite/neat/_client/data_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
10
  cognite/neat/_client/data_classes/data_modeling.py,sha256=RvpUp9ygd-yffQFJ7O2mQqMLDPIa-dmip5zPb8QVIiw,6672
10
11
  cognite/neat/_client/data_classes/neat_sequence.py,sha256=QZWSfWnwk6KlYJvsInco4Wdwc1U8DnOQKWmHebArbQY,10830
11
12
  cognite/neat/_client/data_classes/schema.py,sha256=jPFTIKrZI0qZtwu1Bc1m3aLu_VbxIEkhZCneHpIbNkc,23205
12
- cognite/neat/_client/testing.py,sha256=M5WUzi3YbtZAN22TXas0SjvMSxmjPFT5m3lNwR0MVkI,1077
13
+ cognite/neat/_client/testing.py,sha256=JnzLQegw2f6SATWRNDQ8Fui6qBYyz7vFgA5myjioohY,1175
13
14
  cognite/neat/_config.py,sha256=WT1BS8uADcFvGoUYOOfwFOVq_VBl472TisdoA3wLick,280
14
15
  cognite/neat/_constants.py,sha256=WcrInu37p56BP7gPRIvTVScu6D9Di4RQG-OiYg5NAek,8250
15
16
  cognite/neat/_graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -36,7 +37,7 @@ cognite/neat/_graph/extractors/_classic_cdf/_sequences.py,sha256=HxN0mnm5GrPAfcN
36
37
  cognite/neat/_graph/extractors/_classic_cdf/_timeseries.py,sha256=6CmmxWWG2IErfNKOPhsjQ5wSOTUZZMjulpaRbHj0Q-g,1560
37
38
  cognite/neat/_graph/extractors/_dexpi.py,sha256=SFWnKXYpQToWag9aoX8fxISNa9b8KlqjZnkwI18BzNY,9431
38
39
  cognite/neat/_graph/extractors/_dict.py,sha256=CmXvYkzhRjWDPEaXZAb_YyWCwJDeNzdWBkmFyc2K90s,4321
39
- cognite/neat/_graph/extractors/_dms.py,sha256=rXcwJnkzAP2NcxghC7cWEi-ljpq0c5-8hgeMmaGOWMc,14473
40
+ cognite/neat/_graph/extractors/_dms.py,sha256=fpr9jmJlnB9IS9sdDA7RV50e_RedF7AEVE25qLlgtp4,13810
40
41
  cognite/neat/_graph/extractors/_dms_graph.py,sha256=b_OpXsLZ1xCGEWAqsF5Qk6EknZzxDbcfaZ5NOZGaYrE,9441
41
42
  cognite/neat/_graph/extractors/_iodd.py,sha256=sV5xKZi2ZT7MQsUQTVji9vxH34pD5yAvUjtT-gb8mts,18473
42
43
  cognite/neat/_graph/extractors/_mock_graph_generator.py,sha256=k6qVslbxwE2WpU1L5NLgHJExk8Sho96Ag6-_bcCiLwA,15436
@@ -79,7 +80,7 @@ cognite/neat/_rules/analysis/__init__.py,sha256=0Y7KiXpzrwOIU7GVlC3zlizj1TXe6sod
79
80
  cognite/neat/_rules/analysis/_base.py,sha256=t9NBxZoM95_7UqOa9coWzsH0Kv6neKcb0dtebTV2KnI,23434
80
81
  cognite/neat/_rules/catalog/__init__.py,sha256=dwDB8b-5GKZuwVyPuiwsH0EaK2FY9-wJrkTjKoL8KE4,250
81
82
  cognite/neat/_rules/catalog/classic_model.xlsx,sha256=YkocpkKypizjsWYwOdn5yzIz_BSl8T8SQLxgm4GIjLQ,15014
82
- cognite/neat/_rules/catalog/hello_world_pump.xlsx,sha256=4Fv9qyv7ARHBXSIh-PiOUHcYrtgznKyR2PZCdEBlA0o,17071
83
+ cognite/neat/_rules/catalog/hello_world_pump.xlsx,sha256=E63t5U1PQLIoUfXp1mEuhuq8I2TGKovZlEfIhO5bevw,23322
83
84
  cognite/neat/_rules/catalog/info-rules-imf.xlsx,sha256=vrE5g8vBtsGpwJqygxG3t9I3x4SUAyQsi1vtWfZ8QW4,53682
84
85
  cognite/neat/_rules/exporters/__init__.py,sha256=IYBa0DIYlx8cFItgYRw9W4FY_LmVEjuaqMz3JORZZX0,1204
85
86
  cognite/neat/_rules/exporters/_base.py,sha256=VkNMy8wsH-x4tAjS44cXgzzNH0CM2k_4RhkMwK50J7g,2284
@@ -176,10 +177,10 @@ cognite/neat/_utils/text.py,sha256=BFJoEOQBFgpelysL92FdF0OVRVFl0q9tRNoz-oRanNc,7
176
177
  cognite/neat/_utils/time_.py,sha256=O30LUiDH9TdOYz8_a9pFqTtJdg8vEjC3qHCk8xZblG8,345
177
178
  cognite/neat/_utils/upload.py,sha256=xWtM6mFuD2QYQHaZ7zCAuGptbEpPIxcH-raWQu93-Ug,5845
178
179
  cognite/neat/_utils/xml_.py,sha256=FQkq84u35MUsnKcL6nTMJ9ajtG9D5i1u4VBnhGqP2DQ,1710
179
- cognite/neat/_version.py,sha256=162Al0wYAoMRqw3d_VE0sPIzASFvLI9jYjqPsyL1Ht0,46
180
+ cognite/neat/_version.py,sha256=QPLtZ3sS71bmoKNu3TyTYKy7lRyMCDh2l6Ur8ITOlz8,46
180
181
  cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
181
- cognite_neat-0.117.1.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
182
- cognite_neat-0.117.1.dist-info/METADATA,sha256=DrUQPta5Ya3Dhco5Ent40MgVts-aNe4dpB8xk90YHIk,5361
183
- cognite_neat-0.117.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
184
- cognite_neat-0.117.1.dist-info/entry_points.txt,sha256=SsQlnl8SNMSSjE3acBI835JYFtsIinLSbVmHmMEXv6E,51
185
- cognite_neat-0.117.1.dist-info/RECORD,,
182
+ cognite_neat-0.117.2.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
183
+ cognite_neat-0.117.2.dist-info/METADATA,sha256=ekCAFZpHqHGP0JjfiP9NOa7ETMffALadml3HTGnfWvQ,5361
184
+ cognite_neat-0.117.2.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
185
+ cognite_neat-0.117.2.dist-info/entry_points.txt,sha256=SsQlnl8SNMSSjE3acBI835JYFtsIinLSbVmHmMEXv6E,51
186
+ cognite_neat-0.117.2.dist-info/RECORD,,