cognite-neat 1.0.7__py3-none-any.whl → 1.0.9__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.
@@ -12,6 +12,7 @@ from .data_classes import PagedResponse
12
12
 
13
13
  class ContainersAPI(NeatAPI):
14
14
  ENDPOINT = "/models/containers"
15
+ LIST_REQUEST_LIMIT = 1000
15
16
 
16
17
  def apply(self, items: Sequence[ContainerRequest]) -> list[ContainerResponse]:
17
18
  """Apply (create or update) containers in CDF.
@@ -93,33 +94,45 @@ class ContainersAPI(NeatAPI):
93
94
  self,
94
95
  space: str | None = None,
95
96
  include_global: bool = False,
96
- limit: int = 10,
97
+ limit: int | None = 10,
97
98
  ) -> list[ContainerResponse]:
98
99
  """List containers in CDF Project.
99
100
 
100
101
  Args:
101
102
  space: If specified, only containers in this space are returned.
102
103
  include_global: If True, include global containers.
103
- limit: Maximum number of containers to return. Max is 1000.
104
+ limit: Maximum number of containers to return. If None, return all containers.
104
105
 
105
106
  Returns:
106
107
  List of ContainerResponse objects.
107
108
  """
108
- if limit > 1000:
109
- raise ValueError("Pagination is not (yet) supported for listing containers. The maximum limit is 1000.")
110
- parameters: dict[str, PrimitiveType] = {
111
- "includeGlobal": include_global,
112
- "limit": limit,
113
- }
109
+ if limit is not None and limit < 0:
110
+ raise ValueError("Limit must be non-negative.")
111
+ elif limit is not None and limit == 0:
112
+ return []
113
+ parameters: dict[str, PrimitiveType] = {"includeGlobal": include_global}
114
114
  if space is not None:
115
115
  parameters["space"] = space
116
- result = self._http_client.request_with_retries(
117
- ParametersRequest(
118
- endpoint_url=self._config.create_api_url(self.ENDPOINT),
119
- method="GET",
120
- parameters=parameters,
116
+ cursor: str | None = None
117
+ container_responses: list[ContainerResponse] = []
118
+ while True:
119
+ if cursor is not None:
120
+ parameters["cursor"] = cursor
121
+ if limit is None:
122
+ parameters["limit"] = self.LIST_REQUEST_LIMIT
123
+ else:
124
+ parameters["limit"] = min(self.LIST_REQUEST_LIMIT, limit - len(container_responses))
125
+ result = self._http_client.request_with_retries(
126
+ ParametersRequest(
127
+ endpoint_url=self._config.create_api_url(self.ENDPOINT),
128
+ method="GET",
129
+ parameters=parameters,
130
+ )
121
131
  )
122
- )
123
- result.raise_for_status()
124
- result = PagedResponse[ContainerResponse].model_validate_json(result.success_response.body)
125
- return result.items
132
+ result.raise_for_status()
133
+ result = PagedResponse[ContainerResponse].model_validate_json(result.success_response.body)
134
+ container_responses.extend(result.items)
135
+ cursor = result.next_cursor
136
+ if cursor is None or (limit is not None and len(container_responses) >= limit):
137
+ break
138
+ return container_responses
@@ -13,6 +13,7 @@ from .data_classes import PagedResponse
13
13
 
14
14
  class ViewsAPI(NeatAPI):
15
15
  ENDPOINT = "/models/views"
16
+ LIST_REQUEST_LIMIT = 1000
16
17
 
17
18
  def apply(self, items: Sequence[ViewRequest]) -> list[ViewResponse]:
18
19
  """Create or update views in CDF Project.
@@ -93,7 +94,7 @@ class ViewsAPI(NeatAPI):
93
94
  all_versions: bool = False,
94
95
  include_inherited_properties: bool = True,
95
96
  include_global: bool = False,
96
- limit: int = 10,
97
+ limit: int | None = 10,
97
98
  ) -> list[ViewResponse]:
98
99
  """List views in CDF Project.
99
100
 
@@ -102,28 +103,42 @@ class ViewsAPI(NeatAPI):
102
103
  all_versions: If True, return all versions. If False, only return the latest version.
103
104
  include_inherited_properties: If True, include properties inherited from parent views.
104
105
  include_global: If True, include global views.
105
- limit: Maximum number of views to return. Max is 1000.
106
+ limit: Maximum number of views to return. If None, return all views.
106
107
 
107
108
  Returns:
108
109
  List of ViewResponse objects.
109
110
  """
110
- if limit > 1000:
111
- raise ValueError("Pagination is not (yet) supported for listing views. The maximum limit is 1000.")
111
+ if limit is not None and limit < 0:
112
+ raise ValueError("Limit must be non-negative.")
113
+ elif limit is not None and limit == 0:
114
+ return []
112
115
  parameters: dict[str, PrimitiveType] = {
113
116
  "allVersions": all_versions,
114
117
  "includeInheritedProperties": include_inherited_properties,
115
118
  "includeGlobal": include_global,
116
- "limit": limit,
117
119
  }
118
120
  if space is not None:
119
121
  parameters["space"] = space
120
- result = self._http_client.request_with_retries(
121
- ParametersRequest(
122
- endpoint_url=self._config.create_api_url(self.ENDPOINT),
123
- method="GET",
124
- parameters=parameters,
122
+ cursor: str | None = None
123
+ view_responses: list[ViewResponse] = []
124
+ while True:
125
+ if cursor is not None:
126
+ parameters["cursor"] = cursor
127
+ if limit is None:
128
+ parameters["limit"] = self.LIST_REQUEST_LIMIT
129
+ else:
130
+ parameters["limit"] = min(self.LIST_REQUEST_LIMIT, limit - len(view_responses))
131
+ result = self._http_client.request_with_retries(
132
+ ParametersRequest(
133
+ endpoint_url=self._config.create_api_url(self.ENDPOINT),
134
+ method="GET",
135
+ parameters=parameters,
136
+ )
125
137
  )
126
- )
127
- result.raise_for_status()
128
- result = PagedResponse[ViewResponse].model_validate_json(result.success_response.body)
129
- return result.items
138
+ result.raise_for_status()
139
+ result = PagedResponse[ViewResponse].model_validate_json(result.success_response.body)
140
+ view_responses.extend(result.items)
141
+ cursor = result.next_cursor
142
+ if cursor is None or (limit is not None and len(view_responses) >= limit):
143
+ break
144
+ return view_responses
@@ -86,6 +86,12 @@ class PrimitiveField(FieldChange, ABC):
86
86
  def severity(self) -> SeverityType:
87
87
  return self.item_severity
88
88
 
89
+ @property
90
+ @abstractmethod
91
+ def description(self) -> str:
92
+ """Human-readable description of the change."""
93
+ ...
94
+
89
95
 
90
96
  class AddedField(PrimitiveField):
91
97
  new_value: BaseModelObject | str | int | float | bool | None
@@ -254,6 +254,9 @@ def _move_filter_key(value: Any) -> Any:
254
254
  # Already in the correct format
255
255
  return value
256
256
  key, data = next(iter(value.items()))
257
+ # Check if inner data already has filterType (already processed by a previous recursive call)
258
+ if isinstance(data, dict) and "filterType" in data:
259
+ return value
257
260
  if key not in AVAILABLE_FILTERS:
258
261
  raise ValueError(
259
262
  f"Unknown filter type: {key!r}. Available filter types: {humanize_collection(AVAILABLE_FILTERS)}."
@@ -267,12 +267,22 @@ def _from_dotenv(evn_file: Path) -> EnvironmentVariables:
267
267
  raise FileNotFoundError(f"{evn_file} does not exist.")
268
268
  content = evn_file.read_text()
269
269
  valid_variables = {f.name for f in fields(EnvironmentVariables)}
270
- variables: dict[str, str] = {}
270
+ int_variables = {"CDF_MAX_WORKERS", "CDF_CLIENT_TIMEOUT", "CDF_REDIRECT_PORT"}
271
+ variables: dict[str, str | int] = {}
272
+ value: str | int
271
273
  for line in content.splitlines():
272
274
  if line.startswith("#") or "=" not in line:
273
275
  continue
274
276
  key, value = line.split("=", 1)
275
277
  if key in valid_variables:
278
+ if key in int_variables:
279
+ try:
280
+ value = int(value)
281
+ except ValueError as e:
282
+ raise ValueError(
283
+ f"Failed to parse {evn_file.as_posix()!r} file. "
284
+ f"Variable '{key}' must be an integer, but got '{value}'."
285
+ ) from e
276
286
  variables[key] = value
277
287
  return EnvironmentVariables(**variables) # type: ignore[arg-type]
278
288
 
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "1.0.7"
1
+ __version__ = "1.0.9"
2
2
  __engine__ = "^2.0.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cognite-neat
3
- Version: 1.0.7
3
+ Version: 1.0.9
4
4
  Summary: Knowledge graph transformation
5
5
  Author: Nikola Vasiljevic, Anders Albert
6
6
  Author-email: Nikola Vasiljevic <nikola.vasiljevic@cognite.com>, Anders Albert <anders.albert@cognite.com>
@@ -3,12 +3,12 @@ cognite/neat/_client/__init__.py,sha256=75Bh7eGhaN4sOt3ZcRzHl7pXaheu1z27kmTHeaI0
3
3
  cognite/neat/_client/api.py,sha256=nbxCdWBXcTVM6MrQeT_VpB6ehfoI544JHPFq-ejQKCY,292
4
4
  cognite/neat/_client/client.py,sha256=h0HELAHiBFxMNInkDu4AzbgfEIXqeM0BqqnMBmXjgi0,903
5
5
  cognite/neat/_client/config.py,sha256=eIIdWaA13yncRP6X7vTYsTpmXmVcmkhZPv5oPnLUEVc,1484
6
- cognite/neat/_client/containers_api.py,sha256=JPXbCm68d5GsnIdMWgQKP48ax9lY8L2w2tC-7iKCpUA,4486
6
+ cognite/neat/_client/containers_api.py,sha256=7bVIlL5PwoAG5Bks1ortW_bCG8iTkFqFVyL05pdJ3Pw,5176
7
7
  cognite/neat/_client/data_classes.py,sha256=HYPsrAJGVCUmlWTSIxJgAnIHAOzcyDveMM6Z-cuA92M,1404
8
8
  cognite/neat/_client/data_model_api.py,sha256=ogVHOabQ3HTqWaaoiGClmbtYdP-pl6DPN2zmPdH5LWY,4253
9
9
  cognite/neat/_client/spaces_api.py,sha256=xHtSMt_2k2YwZ5_8kH2dfa7fWxQQrky7wra4Ar2jwqs,4111
10
10
  cognite/neat/_client/statistics_api.py,sha256=HcYb2nNC9M_iaI1xyjjLn2Cz1tcyu7BJeaqVps79tg4,773
11
- cognite/neat/_client/views_api.py,sha256=vZh851Yw8X-Y90sahOiGnq-pwDOBBXegcxTtypkcMvA,4956
11
+ cognite/neat/_client/views_api.py,sha256=Qzk_wiLtaWszxCQFDBoWCH1yDc4GOEJsVOcL061rcK0,5639
12
12
  cognite/neat/_config.py,sha256=MzQiZer0Wyk6VEtfDtl_tTF9KYAjYu2Q8jE7RugMJuM,9201
13
13
  cognite/neat/_data_model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  cognite/neat/_data_model/_analysis.py,sha256=d_gP0M_8-HjSAhWT28cfdOsydNAKmOOT4pTh5W_CQcU,8827
@@ -21,7 +21,7 @@ cognite/neat/_data_model/deployer/_differ_container.py,sha256=mcy7PhUOfnvAxnZWNo
21
21
  cognite/neat/_data_model/deployer/_differ_data_model.py,sha256=iA7Xp-7NRvzZJXLLpJaLebkKKpv_VCBKPX6f-RU9wBk,1864
22
22
  cognite/neat/_data_model/deployer/_differ_space.py,sha256=J_AaqiseLpwQsOkKc7gmho4U2oSWAGVeEdQNepZiWw0,343
23
23
  cognite/neat/_data_model/deployer/_differ_view.py,sha256=g1xHwsoxFUaTOTtQa19nntKF3rxFzc2FxpKKFAUN_NE,11412
24
- cognite/neat/_data_model/deployer/data_classes.py,sha256=e0whwQkvaVAAL26McEnbLFREeWXMOevNKONJHQmfM8w,26779
24
+ cognite/neat/_data_model/deployer/data_classes.py,sha256=1T4Kk9DjYo_wgmFMC--DWq82Ws7F3FqCiNtcRA5C5_4,26916
25
25
  cognite/neat/_data_model/deployer/deployer.py,sha256=8W6Zy8MVLaUWRqNlNrP-A1HUJlOMdzpDsyPqClxfyrU,20288
26
26
  cognite/neat/_data_model/exporters/__init__.py,sha256=AskjmB_0Vqib4kN84bWt8-M8nO42QypFf-l-E8oA5W8,482
27
27
  cognite/neat/_data_model/exporters/_api_exporter.py,sha256=G9cqezy_SH8VdhW4o862qBHh_QcbzfP6O1Yyjvdpeog,1579
@@ -59,7 +59,7 @@ cognite/neat/_data_model/models/dms/_references.py,sha256=x2sK_YnEpWtLED4j8dqrqV
59
59
  cognite/neat/_data_model/models/dms/_schema.py,sha256=2JFLcm52smzPdtZ69Lf02UbYAD8I_hpRbI7ZAzdxJJs,641
60
60
  cognite/neat/_data_model/models/dms/_space.py,sha256=3KvWg0bVuLpgQwhkDbsJ53ZMMmK0cKUgfyDRrSrERko,1904
61
61
  cognite/neat/_data_model/models/dms/_types.py,sha256=5-cgC53AG186OZUqkltv7pMjcGNLuH7Etbn8IUcgk1c,447
62
- cognite/neat/_data_model/models/dms/_view_filter.py,sha256=cfeEOtRz5SGFI0rmPD3jNl-V6_zJxyxgxYjG3Oz8OEU,10301
62
+ cognite/neat/_data_model/models/dms/_view_filter.py,sha256=SXZw2soq9KKNFQQKHPrI9YxptxYdffUhbo-rNI_icmw,10476
63
63
  cognite/neat/_data_model/models/dms/_view_property.py,sha256=nJBPmw4KzJOdaQmvRfCE3A4FL-E13OsNUEufI64vLKo,9271
64
64
  cognite/neat/_data_model/models/dms/_views.py,sha256=1yxuwnsUM4WKItEY1hmJbMQKW0q3Dn321NmLmKLJeCM,8657
65
65
  cognite/neat/_data_model/models/entities/__init__.py,sha256=7dDyES7fYl9LEREal59F038RdEvfGRpUOc6n_MtSgjU,836
@@ -270,7 +270,7 @@ cognite/neat/_v0/core/_store/_instance.py,sha256=helzPszrD6ti4Efo0IE4fpcUxnQN7AC
270
270
  cognite/neat/_v0/core/_store/_provenance.py,sha256=3U63x-qvNUv89c_dcKD8Lrbo4BPw-hcdHy8wfBMWn4w,7338
271
271
  cognite/neat/_v0/core/_store/exceptions.py,sha256=ypiAiUNGVULAKE6GVcVVjpMscRyY4qjnYDV_k8jnnOk,1672
272
272
  cognite/neat/_v0/core/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
273
- cognite/neat/_v0/core/_utils/auth.py,sha256=RrwfhuX5ldsU9YQ767eLvWQC1xtT81OHo6yw-iDafu8,14841
273
+ cognite/neat/_v0/core/_utils/auth.py,sha256=uaPymyoiaOQ9to-m9e6ALlpI_weEmCNmfshKh3_Y6YI,15312
274
274
  cognite/neat/_v0/core/_utils/auxiliary.py,sha256=cUAW3_OT8hYNNoFhcdqEPyaM7TNqTkA0eUzCbCvtaNc,7116
275
275
  cognite/neat/_v0/core/_utils/collection_.py,sha256=06avD7NaXOSlM500zmJgwWVM-suDBg-rt5sd6nHKrhA,2384
276
276
  cognite/neat/_v0/core/_utils/graph_transformations_report.py,sha256=WRA0JrQmRYwT-2-GwbOR1ZncnNrufXt7j__CP_QRI34,1239
@@ -315,9 +315,9 @@ cognite/neat/_v0/session/_template.py,sha256=BNcvrW5y7LWzRM1XFxZkfR1Nc7e8UgjBClH
315
315
  cognite/neat/_v0/session/_to.py,sha256=AnsRSDDdfFyYwSgi0Z-904X7WdLtPfLlR0x1xsu_jAo,19447
316
316
  cognite/neat/_v0/session/_wizard.py,sha256=baPJgXAAF3d1bn4nbIzon1gWfJOeS5T43UXRDJEnD3c,1490
317
317
  cognite/neat/_v0/session/exceptions.py,sha256=jv52D-SjxGfgqaHR8vnpzo0SOJETIuwbyffSWAxSDJw,3495
318
- cognite/neat/_version.py,sha256=2sCnCVH3MOOkLqwv-pjtB202dwYfG-1e2vtDDOCqmIQ,44
318
+ cognite/neat/_version.py,sha256=xkV7Ynbzd3nMdRtl2ZfVZQqTsYCuXajW-2kq0kFsnHI,44
319
319
  cognite/neat/legacy.py,sha256=eI2ecxOV8ilGHyLZlN54ve_abtoK34oXognkFv3yvF0,219
320
320
  cognite/neat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
321
- cognite_neat-1.0.7.dist-info/WHEEL,sha256=93kfTGt3a0Dykt_T-gsjtyS5_p8F_d6CE1NwmBOirzo,79
322
- cognite_neat-1.0.7.dist-info/METADATA,sha256=aXEyOVPO3fvZT-NcPv1Zc3N9hZEVOuFQhRW_zHtnLSg,6090
323
- cognite_neat-1.0.7.dist-info/RECORD,,
321
+ cognite_neat-1.0.9.dist-info/WHEEL,sha256=93kfTGt3a0Dykt_T-gsjtyS5_p8F_d6CE1NwmBOirzo,79
322
+ cognite_neat-1.0.9.dist-info/METADATA,sha256=A0qrxdua5CQ2020BXufsTZgZmveQULmVtfqqBCrMV64,6090
323
+ cognite_neat-1.0.9.dist-info/RECORD,,