cognite-neat 0.77.7__py3-none-any.whl → 0.77.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.

Potentially problematic release.


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

cognite/neat/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.77.7"
1
+ __version__ = "0.77.9"
@@ -1,6 +1,7 @@
1
1
  from ._base import BaseImporter
2
2
  from ._dms2rules import DMSImporter
3
3
  from ._dtdl2rules import DTDLImporter
4
+ from ._inference2rules import InferenceImporter
4
5
  from ._owl2rules import OWLImporter
5
6
  from ._spreadsheet2rules import ExcelImporter, GoogleSheetImporter
6
7
  from ._yaml2rules import YAMLImporter
@@ -13,4 +14,5 @@ __all__ = [
13
14
  "GoogleSheetImporter",
14
15
  "DTDLImporter",
15
16
  "YAMLImporter",
17
+ "InferenceImporter",
16
18
  ]
@@ -0,0 +1,221 @@
1
+ from datetime import datetime
2
+ from pathlib import Path
3
+ from typing import Literal, cast, overload
4
+
5
+ from rdflib import Graph, Namespace, URIRef
6
+ from rdflib import Literal as RdfLiteral
7
+
8
+ import cognite.neat.rules.issues as issues
9
+ from cognite.neat.constants import PREFIXES
10
+ from cognite.neat.rules.importers._base import BaseImporter, Rules, _handle_issues
11
+ from cognite.neat.rules.issues import IssueList
12
+ from cognite.neat.rules.models import InformationRules, RoleTypes
13
+ from cognite.neat.rules.models._base import MatchType
14
+ from cognite.neat.rules.models.information import (
15
+ InformationMetadata,
16
+ InformationRulesInput,
17
+ )
18
+ from cognite.neat.utils.utils import get_namespace, remove_namespace
19
+
20
+ ORDERED_CLASSES_QUERY = """SELECT ?class (count(?s) as ?instances )
21
+ WHERE { ?s a ?class . }
22
+ group by ?class order by DESC(?instances)"""
23
+
24
+ INSTANCES_OF_CLASS_QUERY = """SELECT ?s WHERE { ?s a <class> . }"""
25
+
26
+ INSTANCE_PROPERTIES_DEFINITION = """SELECT ?property (count(?property) as ?occurrence) ?dataType ?objectType
27
+ WHERE {<instance_id> ?property ?value .
28
+ BIND(datatype(?value) AS ?dataType)
29
+ OPTIONAL {?value rdf:type ?objectType .}}
30
+ GROUP BY ?property ?dataType ?objectType"""
31
+
32
+
33
+ class InferenceImporter(BaseImporter):
34
+ """Rules inference through analysis of knowledge graph provided in various formats.
35
+
36
+ Args:
37
+ issue_list: Issue list to store issues
38
+ graph: Knowledge graph
39
+ max_number_of_instance: Maximum number of instances to be used in inference
40
+ make_compliant: If True, NEAT will attempt to make the imported rules compliant with CDF
41
+ """
42
+
43
+ def __init__(
44
+ self, issue_list: IssueList, graph: Graph, max_number_of_instance: int = -1, make_compliant: bool = False
45
+ ):
46
+ self.issue_list = issue_list
47
+ self.graph = graph
48
+ self.max_number_of_instance = max_number_of_instance
49
+ self.make_compliant = make_compliant
50
+
51
+ @classmethod
52
+ def from_rdf_file(cls, filepath: Path, make_compliant: bool = False, max_number_of_instance: int = -1):
53
+ issue_list = IssueList(title=f"'{filepath.name}'")
54
+
55
+ graph = Graph()
56
+ try:
57
+ graph.parse(filepath)
58
+ except Exception:
59
+ issue_list.append(issues.fileread.FileReadError(filepath))
60
+
61
+ return cls(issue_list, graph, make_compliant=make_compliant, max_number_of_instance=max_number_of_instance)
62
+
63
+ @classmethod
64
+ def from_json_file(cls, filepath: Path, make_compliant: bool = False, max_number_of_instance: int = -1):
65
+ raise NotImplementedError("JSON file format is not supported yet.")
66
+
67
+ @classmethod
68
+ def from_yaml_file(cls, filepath: Path, make_compliant: bool = False, max_number_of_instance: int = -1):
69
+ raise NotImplementedError("YAML file format is not supported yet.")
70
+
71
+ @classmethod
72
+ def from_xml_file(cls, filepath: Path, make_compliant: bool = False, max_number_of_instance: int = -1):
73
+ raise NotImplementedError("JSON file format is not supported yet.")
74
+
75
+ @overload
76
+ def to_rules(self, errors: Literal["raise"], role: RoleTypes | None = None) -> Rules: ...
77
+
78
+ @overload
79
+ def to_rules(
80
+ self,
81
+ errors: Literal["continue"] = "continue",
82
+ role: RoleTypes | None = None,
83
+ ) -> tuple[Rules | None, IssueList]: ...
84
+
85
+ def to_rules(
86
+ self, errors: Literal["raise", "continue"] = "continue", role: RoleTypes | None = None
87
+ ) -> tuple[Rules | None, IssueList] | Rules:
88
+ """
89
+ Creates `Rules` object from the data for target role.
90
+ """
91
+
92
+ if self.issue_list.has_errors:
93
+ # In case there were errors during the import, the to_rules method will return None
94
+ return self._return_or_raise(self.issue_list, errors)
95
+
96
+ rules_dict = self._to_rules_components()
97
+
98
+ # adding additional prefix
99
+ rules_dict["prefixes"][rules_dict["metadata"]["prefix"]] = rules_dict["metadata"]["namespace"]
100
+
101
+ with _handle_issues(self.issue_list) as future:
102
+ rules: InformationRules
103
+ rules = InformationRulesInput.load(rules_dict).as_rules()
104
+
105
+ if future.result == "failure" or self.issue_list.has_errors:
106
+ return self._return_or_raise(self.issue_list, errors)
107
+
108
+ if self.make_compliant and rules:
109
+ rules = self._make_dms_compliant_rules(rules)
110
+
111
+ return self._to_output(
112
+ rules,
113
+ self.issue_list,
114
+ errors=errors,
115
+ role=role,
116
+ )
117
+
118
+ def _to_rules_components(
119
+ self,
120
+ ) -> dict:
121
+ """Convert RDF graph to dictionary defining data model and prefixes of the graph
122
+
123
+ Args:
124
+ graph: RDF graph to be converted to TransformationRules object
125
+ max_number_of_instance: Max number of instances to be considered for each class
126
+
127
+ Returns:
128
+ Tuple of data model and prefixes of the graph
129
+ """
130
+ classes: dict[str, dict] = {}
131
+ properties: dict[str, dict] = {}
132
+ prefixes: dict[str, Namespace] = PREFIXES
133
+
134
+ # Infers all the classes in the graph
135
+ for class_uri, no_instances in self.graph.query(ORDERED_CLASSES_QUERY): # type: ignore[misc]
136
+ self._add_uri_namespace_to_prefixes(cast(URIRef, class_uri), prefixes)
137
+
138
+ if (class_id := remove_namespace(class_uri)) in classes:
139
+ # handles cases when class id is already present in classes
140
+ class_id = f"{class_id}_{len(classes)+1}"
141
+
142
+ classes[class_id] = {
143
+ "class_": class_id,
144
+ "reference": class_uri,
145
+ "match_type": MatchType.exact,
146
+ "comment": f"Inferred from knowledge graph, where this class has {no_instances} instances",
147
+ }
148
+
149
+ # Infers all the properties of the class
150
+ for class_id, class_definition in classes.items():
151
+ for (instance,) in self.graph.query( # type: ignore[misc]
152
+ INSTANCES_OF_CLASS_QUERY.replace("class", class_definition["reference"])
153
+ if self.max_number_of_instance < 0
154
+ else INSTANCES_OF_CLASS_QUERY.replace("class", class_definition["reference"])
155
+ + f" LIMIT {self.max_number_of_instance}"
156
+ ):
157
+ for property_uri, occurrence, data_type_uri, object_type_uri in self.graph.query( # type: ignore[misc]
158
+ INSTANCE_PROPERTIES_DEFINITION.replace("instance_id", instance)
159
+ ): # type: ignore[misc]
160
+ property_id = remove_namespace(property_uri)
161
+ self._add_uri_namespace_to_prefixes(cast(URIRef, property_uri), prefixes)
162
+ value_type_uri = data_type_uri if data_type_uri else object_type_uri
163
+
164
+ # this is to skip rdf:type property
165
+ if not value_type_uri:
166
+ continue
167
+
168
+ self._add_uri_namespace_to_prefixes(cast(URIRef, value_type_uri), prefixes)
169
+ value_type_id = remove_namespace(value_type_uri)
170
+ id_ = f"{class_id}:{property_id}:{value_type_id}"
171
+
172
+ definition = {
173
+ "class_": class_id,
174
+ "property_": property_id,
175
+ "max_occurrence": cast(RdfLiteral, occurrence).value,
176
+ "value_type": value_type_id,
177
+ "reference": property_uri,
178
+ }
179
+
180
+ # USE CASE 1: If property is not present in properties
181
+ if id_ not in properties:
182
+ properties[id_] = definition
183
+
184
+ # USE CASE 2: If property is present in properties but with different max count
185
+ elif id_ in properties and not (properties[id_]["max_count"] == definition["max_count"]):
186
+ properties[id_]["max_count"] = max(properties[id_]["max_count"], definition["max_count"])
187
+
188
+ return {
189
+ "metadata": self._default_metadata().model_dump(),
190
+ "classes": list(classes.values()),
191
+ "properties": list(properties.values()),
192
+ "prefixes": prefixes,
193
+ }
194
+
195
+ @classmethod
196
+ def _add_uri_namespace_to_prefixes(cls, URI: URIRef, prefixes: dict[str, Namespace]):
197
+ """Add URI to prefixes dict if not already present
198
+
199
+ Args:
200
+ URI: URI from which namespace is being extracted
201
+ prefixes: Dict of prefixes and namespaces
202
+ """
203
+ if Namespace(get_namespace(URI)) not in prefixes.values():
204
+ prefixes[f"prefix-{len(prefixes)+1}"] = Namespace(get_namespace(URI))
205
+
206
+ @classmethod
207
+ def _default_metadata(cls):
208
+ return InformationMetadata(
209
+ name="Inferred Model",
210
+ creator="NEAT",
211
+ version="inferred",
212
+ created=datetime.now(),
213
+ updated=datetime.now(),
214
+ description="Inferred model from knowledge graph",
215
+ prefix="inferred",
216
+ namespace="http://purl.org/cognite/neat/inferred/",
217
+ )
218
+
219
+ @classmethod
220
+ def _make_dms_compliant_rules(cls, rules: InformationRules) -> InformationRules:
221
+ raise NotImplementedError("Compliance with DMS is not supported yet.")
@@ -1,8 +1,6 @@
1
1
  """This module performs importing of various formats to one of serializations for which
2
2
  there are loaders to TransformationRules pydantic class."""
3
3
 
4
- # TODO: if this module grows too big, split it into several files and place under ./converter directory
5
-
6
4
  from pathlib import Path
7
5
  from typing import Literal, overload
8
6
 
@@ -22,7 +20,8 @@ class OWLImporter(BaseImporter):
22
20
  """Convert OWL ontology to tables/ transformation rules / Excel file.
23
21
 
24
22
  Args:
25
- owl_filepath: Path to OWL ontology
23
+ filepath: Path to OWL ontology
24
+ make_compliant: If True, NEAT will attempt to make the imported rules compliant with CDF
26
25
 
27
26
  !!! Note
28
27
  OWL Ontologies typically lacks some information that is required for making a complete
@@ -78,13 +78,24 @@ class _InformationRulesConverter:
78
78
  for cls_ in self.rules.classes
79
79
  ]
80
80
 
81
+ last_dms_rules = self.rules.last.as_dms_architect_rules() if self.rules.last else None
82
+ ref_dms_rules = self.rules.reference.as_dms_architect_rules() if self.rules.reference else None
83
+
81
84
  containers: list[DMSContainer] = []
82
85
  class_by_entity = {cls_.class_: cls_ for cls_ in self.rules.classes}
83
86
  if self.rules.last:
84
87
  for cls_ in self.rules.last.classes:
85
88
  if cls_.class_ not in class_by_entity:
86
89
  class_by_entity[cls_.class_] = cls_
90
+
91
+ existing_containers: set[ContainerEntity] = set()
92
+ for rule_set in [last_dms_rules, ref_dms_rules]:
93
+ if rule_set:
94
+ existing_containers.update({c.container for c in rule_set.containers or []})
95
+
87
96
  for container_entity, class_entities in referenced_containers.items():
97
+ if container_entity in existing_containers:
98
+ continue
88
99
  constrains = self._create_container_constraint(
89
100
  class_entities, default_space, class_by_entity, referenced_containers
90
101
  )
@@ -106,8 +117,8 @@ class _InformationRulesConverter:
106
117
  ),
107
118
  views=SheetList[DMSView](data=views),
108
119
  containers=SheetList[DMSContainer](data=containers),
109
- last=self.rules.last.as_dms_architect_rules() if self.rules.last else None,
110
- reference=self.rules.reference.as_dms_architect_rules() if self.rules.reference else None,
120
+ last=last_dms_rules,
121
+ reference=ref_dms_rules,
111
122
  )
112
123
 
113
124
  @staticmethod
@@ -220,17 +231,29 @@ class _InformationRulesConverter:
220
231
  else:
221
232
  return prop.class_.as_container_entity(default_space), prop.property_
222
233
 
223
- @classmethod
224
- def _get_view_implements(cls, cls_: InformationClass, metadata: InformationMetadata) -> list[ViewEntity]:
234
+ def _get_view_implements(self, cls_: InformationClass, metadata: InformationMetadata) -> list[ViewEntity]:
225
235
  if isinstance(cls_.reference, ReferenceEntity) and cls_.reference.prefix != metadata.prefix:
226
236
  # We use the reference for implements if it is in a different namespace
227
- implements = [
228
- cls_.reference.as_view_entity(metadata.prefix, metadata.version),
229
- ]
237
+ if self.rules.reference and cls_.reference.prefix == self.rules.reference.metadata.prefix:
238
+ implements = [
239
+ cls_.reference.as_view_entity(
240
+ self.rules.reference.metadata.prefix, self.rules.reference.metadata.version
241
+ )
242
+ ]
243
+ else:
244
+ implements = [
245
+ cls_.reference.as_view_entity(metadata.prefix, metadata.version),
246
+ ]
230
247
  else:
231
248
  implements = []
232
-
233
- implements.extend([parent.as_view_entity(metadata.prefix, metadata.version) for parent in cls_.parent or []])
249
+ for parent in cls_.parent or []:
250
+ if self.rules.reference and parent.prefix == self.rules.reference.metadata.prefix:
251
+ view_entity = parent.as_view_entity(
252
+ self.rules.reference.metadata.prefix, self.rules.reference.metadata.version
253
+ )
254
+ else:
255
+ view_entity = parent.as_view_entity(metadata.prefix, metadata.version)
256
+ implements.append(view_entity)
234
257
  return implements
235
258
 
236
259
  @staticmethod
@@ -281,7 +281,6 @@ class RulesToExcel(Step):
281
281
  value="",
282
282
  label="If you chose Dump Format 'reference', the provided ID will be use in the new medata sheet. "
283
283
  "Expected format 'sp_space:my_external_id'.",
284
- options=list(exporters.ExcelExporter.dump_options),
285
284
  ),
286
285
  Configurable(
287
286
  name="File path",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cognite-neat
3
- Version: 0.77.7
3
+ Version: 0.77.9
4
4
  Summary: Knowledge graph transformation
5
5
  Home-page: https://cognite-neat.readthedocs-hosted.com/
6
6
  License: Apache-2.0
@@ -1,5 +1,5 @@
1
1
  cognite/neat/__init__.py,sha256=v-rRiDOgZ3sQSMQKq0vgUQZvpeOkoHFXissAx6Ktg84,61
2
- cognite/neat/_version.py,sha256=hFsfqx1W0uQf6EjOq0viOjyWKF79pF13oi9ziY65GuY,23
2
+ cognite/neat/_version.py,sha256=7VDP9r1I_BSyywO4zzqjsH4vyV6SUFzaVXKYLN3DGd0,23
3
3
  cognite/neat/app/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  cognite/neat/app/api/asgi/metrics.py,sha256=nxFy7L5cChTI0a-zkCiJ59Aq8yLuIJp5c9Dg0wRXtV0,152
5
5
  cognite/neat/app/api/configuration.py,sha256=2U5M6M252swvQPQyooA1EBzFUZNtcTmuSaywfJDgckM,4232
@@ -170,7 +170,7 @@ cognite/neat/rules/exporters/_rules2excel.py,sha256=HvUdXYHxfLMijYWdTnfqCsw3Izf8
170
170
  cognite/neat/rules/exporters/_rules2ontology.py,sha256=NWS3cn2927LQqW_PdQ-92OLIlmIKGNk7xh5yOMAyj94,20120
171
171
  cognite/neat/rules/exporters/_rules2yaml.py,sha256=GA8eUYRxUfIU6IMvlyGO5JidkOD5eUKSbH3qAiFiaCg,3026
172
172
  cognite/neat/rules/exporters/_validation.py,sha256=OlKIyf4nhSDehJwFHDQ8Zdf6HpNfW7dSe2s67eywHu4,4078
173
- cognite/neat/rules/importers/__init__.py,sha256=zqNbGpvdVhYkLjWx1i9dJ3FXzYGtuQyTydUYsj-BndQ,408
173
+ cognite/neat/rules/importers/__init__.py,sha256=gR6_TAEa3iO5NCLKRztHg-FMiLdBnx47Z3iSzbwLfcE,481
174
174
  cognite/neat/rules/importers/_base.py,sha256=GUiJrYwJ25thI71iS9hCeP_iSZ0Vv8ou3z6MfD07FAk,4274
175
175
  cognite/neat/rules/importers/_dms2rules.py,sha256=5yJGYkM7lAMu-QfO0_r59WE4RGtMu2smMqLm16ohgLQ,18994
176
176
  cognite/neat/rules/importers/_dtdl2rules/__init__.py,sha256=CNR-sUihs2mnR1bPMKs3j3L4ds3vFTsrl6YycExZTfU,68
@@ -178,11 +178,12 @@ cognite/neat/rules/importers/_dtdl2rules/_unit_lookup.py,sha256=wW4saKva61Q_i17g
178
178
  cognite/neat/rules/importers/_dtdl2rules/dtdl_converter.py,sha256=ysmWUxZ0npwrTB0uiH5jA0v37sfCwowGaYk17IyxPUU,12663
179
179
  cognite/neat/rules/importers/_dtdl2rules/dtdl_importer.py,sha256=QDyGt5YBaxzF4v_oCFSgKRSpwVdVruDU3-VW0DEiHbY,6718
180
180
  cognite/neat/rules/importers/_dtdl2rules/spec.py,sha256=tim_MfN1J0F3Oeqk3BMgIA82d_MZvhRuRMsLK3B4PYc,11897
181
+ cognite/neat/rules/importers/_inference2rules.py,sha256=VYs4SCYQk3OMJnCkpJ-fTsK73OfK8cOyYXBAdYI3_WU,9389
181
182
  cognite/neat/rules/importers/_owl2rules/__init__.py,sha256=tdGcrgtozdQyST-pTlxIa4cLBNTLvtk1nNYR4vOdFSw,63
182
183
  cognite/neat/rules/importers/_owl2rules/_owl2classes.py,sha256=LInFeBq-NbBIuMEAwgWch2a4DbBUt4_OMqPkwehW-sw,7591
183
184
  cognite/neat/rules/importers/_owl2rules/_owl2metadata.py,sha256=NdPN0dBB0NYkAcfC0yrYdIrGfdPbl5gfeGnSV3EtUPM,7786
184
185
  cognite/neat/rules/importers/_owl2rules/_owl2properties.py,sha256=BLptGmH-Aa5gZu0hDIxSZTrn9GmB2FicWgRYoETLSnQ,7437
185
- cognite/neat/rules/importers/_owl2rules/_owl2rules.py,sha256=H2Vv56hXGFnq_b0obWGWr5ErDFcoWpT8G2uy89100cU,6925
186
+ cognite/neat/rules/importers/_owl2rules/_owl2rules.py,sha256=vyXtAhHCg-zCv_sfq28bx5BK96GXoCB4KA5LeO_ZuvU,6917
186
187
  cognite/neat/rules/importers/_spreadsheet2rules.py,sha256=nKSJyZGoTho0bqQ_5_1XB9Z1C-MwovRgkVrC-AhOuzs,12438
187
188
  cognite/neat/rules/importers/_yaml2rules.py,sha256=F0uksSz1A3po5OlRM2152_w5j8D9oYTLB9NFTkSMlWI,4275
188
189
  cognite/neat/rules/issues/__init__.py,sha256=Ms6jgCxCezc5IgTOwCFtXQPtoVFfOvdcXj84_rs917I,563
@@ -211,7 +212,7 @@ cognite/neat/rules/models/dms/_validation.py,sha256=nPSyfM1vGZ7d9Uv_2vF2HvMetygt
211
212
  cognite/neat/rules/models/domain.py,sha256=tkKcHvDXnZ5IkOr1wHiuNBtE1h8OCFmf6GZSqzHzxjI,2814
212
213
  cognite/neat/rules/models/entities.py,sha256=iBG84Jr1qQ7PvkMJUJzJ1oWApeONb1IACixdJSztUhk,16395
213
214
  cognite/neat/rules/models/information/__init__.py,sha256=HR6g8xgyU53U7Ck8pPdbT70817Q4NC1r1pCRq5SA8iw,291
214
- cognite/neat/rules/models/information/_converter.py,sha256=sH1wJ8TmEfytFPFDfHgDl6QWnSD-1Pqeb74kIgmR8wQ,9963
215
+ cognite/neat/rules/models/information/_converter.py,sha256=JN63_G5bygdL5WCz-q0_ygiU0NHkzUxm5mZ3WD8yUes,11029
215
216
  cognite/neat/rules/models/information/_rules.py,sha256=tdCjvAtqnFzEo2zcx-BZHmvjSs28gVun2wz8UaT-AOA,13268
216
217
  cognite/neat/rules/models/information/_rules_input.py,sha256=IZp_Wnrac0nVaHKth1YttWQOs-kULGKLMtngNQFY40A,10147
217
218
  cognite/neat/rules/models/information/_serializer.py,sha256=yti9I_xJruxrib66YIBInhze___Io-oPTQH6uWDumPE,3503
@@ -257,7 +258,7 @@ cognite/neat/workflows/steps/lib/current/__init__.py,sha256=c22IznGdCSNCpXCi_yon
257
258
  cognite/neat/workflows/steps/lib/current/graph_extractor.py,sha256=vW9UpJScx5dFVCSairpOdWRdBdLpkCt2kNh6litbF0o,5161
258
259
  cognite/neat/workflows/steps/lib/current/graph_loader.py,sha256=HfGg1HRZhbV58TFu89FTjKeUxGsbCYLeFJIQFDN_pQM,2341
259
260
  cognite/neat/workflows/steps/lib/current/graph_store.py,sha256=r7VTxdaz8jJQU7FJbnRDMxvEYbSAZFNMABhPyfNwiFk,6295
260
- cognite/neat/workflows/steps/lib/current/rules_exporter.py,sha256=BWscuNvTu_u6QQSxkVz4X4A1wAHW2Kfku8lhgrIK51M,23886
261
+ cognite/neat/workflows/steps/lib/current/rules_exporter.py,sha256=iFwzDWgUDBSPajaNAcXvu9pVw-jX66upvwyMXyTq7SE,23822
261
262
  cognite/neat/workflows/steps/lib/current/rules_importer.py,sha256=oGIBh9iFYP3w_K0kLpM-OKTw70R1Mw_opD62MGkCJlk,11451
262
263
  cognite/neat/workflows/steps/lib/current/rules_validator.py,sha256=LwF9lXlnuPOxDSsOMMTHBi2BHc5rk08IF5zahS9yQuw,4844
263
264
  cognite/neat/workflows/steps/lib/io/__init__.py,sha256=k7IPbIq3ey19oRc5sA_15F99-O6dxzqbm1LihGRRo5A,32
@@ -275,8 +276,8 @@ cognite/neat/workflows/steps_registry.py,sha256=fkTX14ZA7_gkUYfWIlx7A1XbCidvqR23
275
276
  cognite/neat/workflows/tasks.py,sha256=dqlJwKAb0jlkl7abbY8RRz3m7MT4SK8-7cntMWkOYjw,788
276
277
  cognite/neat/workflows/triggers.py,sha256=_BLNplzoz0iic367u1mhHMHiUrCwP-SLK6_CZzfODX0,7071
277
278
  cognite/neat/workflows/utils.py,sha256=gKdy3RLG7ctRhbCRwaDIWpL9Mi98zm56-d4jfHDqP1E,453
278
- cognite_neat-0.77.7.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
279
- cognite_neat-0.77.7.dist-info/METADATA,sha256=3FhpHUDfplCEVHoqUUxkNwF3DoNwC9Ad90mKiQXDLaw,9316
280
- cognite_neat-0.77.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
281
- cognite_neat-0.77.7.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
282
- cognite_neat-0.77.7.dist-info/RECORD,,
279
+ cognite_neat-0.77.9.dist-info/LICENSE,sha256=W8VmvFia4WHa3Gqxq1Ygrq85McUNqIGDVgtdvzT-XqA,11351
280
+ cognite_neat-0.77.9.dist-info/METADATA,sha256=jh0m1wUZZS-M6ugn8Ju41qFQwRVziN8Nw7nSV845-Mw,9316
281
+ cognite_neat-0.77.9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
282
+ cognite_neat-0.77.9.dist-info/entry_points.txt,sha256=61FPqiWb25vbqB0KI7znG8nsg_ibLHBvTjYnkPvNFso,50
283
+ cognite_neat-0.77.9.dist-info/RECORD,,