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

Files changed (207) hide show
  1. cognite/neat/__init__.py +2 -2
  2. cognite/neat/_data_model/_constants.py +3 -0
  3. cognite/neat/_data_model/_identifiers.py +61 -0
  4. cognite/neat/_data_model/models/dms/_space.py +1 -1
  5. cognite/neat/_data_model/models/entities/__init__.py +46 -0
  6. cognite/neat/_data_model/models/entities/_base.py +100 -0
  7. cognite/neat/_data_model/models/entities/_data_types.py +144 -0
  8. cognite/neat/{data_model → _data_model}/models/entities/_identifiers.py +1 -1
  9. cognite/neat/_data_model/models/entities/_parser.py +194 -0
  10. cognite/neat/_version.py +1 -1
  11. cognite/neat/{core → v0/core}/_client/_api/data_modeling_loaders.py +6 -6
  12. cognite/neat/{core → v0/core}/_client/_api/neat_instances.py +5 -5
  13. cognite/neat/{core → v0/core}/_client/_api/schema.py +5 -5
  14. cognite/neat/{core → v0/core}/_client/_api/statistics.py +3 -3
  15. cognite/neat/{core → v0/core}/_client/_api_client.py +1 -1
  16. cognite/neat/{core → v0/core}/_client/data_classes/schema.py +4 -4
  17. cognite/neat/{core → v0/core}/_client/testing.py +1 -1
  18. cognite/neat/{core → v0/core}/_constants.py +3 -3
  19. cognite/neat/{core → v0/core}/_data_model/_shared.py +4 -4
  20. cognite/neat/{core → v0/core}/_data_model/analysis/_base.py +8 -8
  21. cognite/neat/{core → v0/core}/_data_model/exporters/_base.py +7 -7
  22. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2dms.py +9 -9
  23. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2excel.py +9 -9
  24. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2instance_template.py +4 -4
  25. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2ontology.py +9 -9
  26. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2yaml.py +1 -1
  27. cognite/neat/{core → v0/core}/_data_model/importers/_base.py +5 -5
  28. cognite/neat/{core → v0/core}/_data_model/importers/_base_file_reader.py +2 -2
  29. cognite/neat/{core → v0/core}/_data_model/importers/_dict2data_model.py +5 -5
  30. cognite/neat/{core → v0/core}/_data_model/importers/_dms2data_model.py +12 -12
  31. cognite/neat/{core → v0/core}/_data_model/importers/_graph2data_model.py +12 -12
  32. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_base.py +12 -12
  33. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_inference2rdata_model.py +14 -14
  34. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_owl2data_model.py +2 -2
  35. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_shared.py +7 -7
  36. cognite/neat/{core → v0/core}/_data_model/importers/_spreadsheet2data_model.py +8 -8
  37. cognite/neat/{core → v0/core}/_data_model/models/__init__.py +3 -3
  38. cognite/neat/{core → v0/core}/_data_model/models/_base_verified.py +5 -5
  39. cognite/neat/{core → v0/core}/_data_model/models/_import_contexts.py +1 -1
  40. cognite/neat/{core → v0/core}/_data_model/models/_types.py +5 -5
  41. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_unverified.py +5 -5
  42. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_validation.py +12 -12
  43. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_verified.py +9 -9
  44. cognite/neat/{core → v0/core}/_data_model/models/data_types.py +3 -3
  45. cognite/neat/{core → v0/core}/_data_model/models/entities/_loaders.py +2 -2
  46. cognite/neat/{core → v0/core}/_data_model/models/entities/_multi_value.py +2 -2
  47. cognite/neat/{core → v0/core}/_data_model/models/entities/_restrictions.py +6 -6
  48. cognite/neat/{core → v0/core}/_data_model/models/entities/_single_value.py +3 -3
  49. cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.py +5 -5
  50. cognite/neat/{core → v0/core}/_data_model/models/physical/__init__.py +1 -1
  51. cognite/neat/{core → v0/core}/_data_model/models/physical/_exporter.py +8 -8
  52. cognite/neat/{core → v0/core}/_data_model/models/physical/_unverified.py +8 -8
  53. cognite/neat/{core → v0/core}/_data_model/models/physical/_validation.py +16 -16
  54. cognite/neat/{core → v0/core}/_data_model/models/physical/_verified.py +10 -10
  55. cognite/neat/{core → v0/core}/_data_model/transformers/_base.py +4 -4
  56. cognite/neat/{core → v0/core}/_data_model/transformers/_converters.py +25 -25
  57. cognite/neat/{core → v0/core}/_data_model/transformers/_mapping.py +7 -7
  58. cognite/neat/{core → v0/core}/_data_model/transformers/_union_conceptual.py +5 -5
  59. cognite/neat/{core → v0/core}/_data_model/transformers/_verification.py +7 -7
  60. cognite/neat/{core → v0/core}/_instances/_tracking/base.py +1 -1
  61. cognite/neat/{core → v0/core}/_instances/_tracking/log.py +1 -1
  62. cognite/neat/{core → v0/core}/_instances/extractors/__init__.py +1 -1
  63. cognite/neat/{core → v0/core}/_instances/extractors/_base.py +6 -6
  64. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_base.py +7 -7
  65. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_classic.py +12 -12
  66. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_relationships.py +3 -3
  67. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_sequences.py +2 -2
  68. cognite/neat/{core → v0/core}/_instances/extractors/_dict.py +2 -2
  69. cognite/neat/{core → v0/core}/_instances/extractors/_dms.py +6 -6
  70. cognite/neat/{core → v0/core}/_instances/extractors/_dms_graph.py +11 -11
  71. cognite/neat/{core → v0/core}/_instances/extractors/_mock_graph_generator.py +10 -10
  72. cognite/neat/{core → v0/core}/_instances/extractors/_raw.py +3 -3
  73. cognite/neat/{core → v0/core}/_instances/extractors/_rdf_file.py +7 -7
  74. cognite/neat/{core → v0/core}/_instances/loaders/_base.py +5 -5
  75. cognite/neat/{core → v0/core}/_instances/loaders/_rdf2dms.py +17 -17
  76. cognite/neat/{core → v0/core}/_instances/loaders/_rdf_to_instance_space.py +11 -11
  77. cognite/neat/{core → v0/core}/_instances/queries/_select.py +3 -3
  78. cognite/neat/{core → v0/core}/_instances/queries/_update.py +1 -1
  79. cognite/neat/{core → v0/core}/_instances/transformers/_base.py +4 -4
  80. cognite/neat/{core → v0/core}/_instances/transformers/_classic_cdf.py +6 -6
  81. cognite/neat/{core → v0/core}/_instances/transformers/_prune_graph.py +4 -4
  82. cognite/neat/{core → v0/core}/_instances/transformers/_rdfpath.py +1 -1
  83. cognite/neat/{core → v0/core}/_instances/transformers/_value_type.py +4 -4
  84. cognite/neat/{core → v0/core}/_issues/_base.py +5 -5
  85. cognite/neat/{core → v0/core}/_issues/_contextmanagers.py +1 -1
  86. cognite/neat/{core → v0/core}/_issues/_factory.py +3 -3
  87. cognite/neat/{core → v0/core}/_issues/errors/__init__.py +1 -1
  88. cognite/neat/{core → v0/core}/_issues/errors/_external.py +1 -1
  89. cognite/neat/{core → v0/core}/_issues/errors/_general.py +1 -1
  90. cognite/neat/{core → v0/core}/_issues/errors/_properties.py +1 -1
  91. cognite/neat/{core → v0/core}/_issues/errors/_resources.py +2 -2
  92. cognite/neat/{core → v0/core}/_issues/errors/_wrapper.py +2 -2
  93. cognite/neat/{core → v0/core}/_issues/warnings/__init__.py +1 -1
  94. cognite/neat/{core → v0/core}/_issues/warnings/_external.py +1 -1
  95. cognite/neat/{core → v0/core}/_issues/warnings/_general.py +1 -1
  96. cognite/neat/{core → v0/core}/_issues/warnings/_models.py +2 -2
  97. cognite/neat/{core → v0/core}/_issues/warnings/_properties.py +2 -2
  98. cognite/neat/{core → v0/core}/_issues/warnings/_resources.py +1 -1
  99. cognite/neat/{core → v0/core}/_issues/warnings/user_modeling.py +1 -1
  100. cognite/neat/{core → v0/core}/_store/_data_model.py +12 -12
  101. cognite/neat/{core → v0/core}/_store/_instance.py +10 -10
  102. cognite/neat/{core → v0/core}/_store/_provenance.py +3 -3
  103. cognite/neat/{core → v0/core}/_store/exceptions.py +4 -4
  104. cognite/neat/{core → v0/core}/_utils/auth.py +1 -1
  105. cognite/neat/{core → v0/core}/_utils/auxiliary.py +1 -1
  106. cognite/neat/{core → v0/core}/_utils/collection_.py +2 -2
  107. cognite/neat/{core → v0/core}/_utils/graph_transformations_report.py +1 -1
  108. cognite/neat/{core → v0/core}/_utils/rdf_.py +1 -1
  109. cognite/neat/{core → v0/core}/_utils/reader/_base.py +1 -1
  110. cognite/neat/{core → v0/core}/_utils/spreadsheet.py +1 -1
  111. cognite/neat/{core → v0/core}/_utils/text.py +1 -1
  112. cognite/neat/{core → v0/core}/_utils/upload.py +3 -3
  113. cognite/neat/{plugins → v0/plugins}/_issues.py +1 -1
  114. cognite/neat/{plugins → v0/plugins}/_manager.py +2 -2
  115. cognite/neat/{plugins → v0/plugins}/data_model/importers/_base.py +1 -1
  116. cognite/neat/{session → v0/session}/_base.py +10 -10
  117. cognite/neat/{session → v0/session}/_collector.py +1 -1
  118. cognite/neat/{session → v0/session}/_drop.py +3 -3
  119. cognite/neat/{session → v0/session}/_explore.py +2 -2
  120. cognite/neat/{session → v0/session}/_fix.py +2 -2
  121. cognite/neat/{session → v0/session}/_inspect.py +3 -3
  122. cognite/neat/{session → v0/session}/_mapping.py +3 -3
  123. cognite/neat/{session → v0/session}/_plugin.py +5 -5
  124. cognite/neat/{session → v0/session}/_prepare.py +8 -8
  125. cognite/neat/{session → v0/session}/_read.py +17 -17
  126. cognite/neat/{session → v0/session}/_set.py +8 -8
  127. cognite/neat/{session → v0/session}/_show.py +5 -5
  128. cognite/neat/{session → v0/session}/_state.py +10 -10
  129. cognite/neat/{session → v0/session}/_subset.py +4 -4
  130. cognite/neat/{session → v0/session}/_template.py +11 -11
  131. cognite/neat/{session → v0/session}/_to.py +12 -12
  132. cognite/neat/{session → v0/session}/_wizard.py +1 -1
  133. cognite/neat/{session → v0/session}/engine/_load.py +1 -1
  134. cognite/neat/{session → v0/session}/exceptions.py +5 -5
  135. {cognite_neat-0.123.33.dist-info → cognite_neat-0.123.34.dist-info}/METADATA +1 -1
  136. cognite_neat-0.123.34.dist-info/RECORD +219 -0
  137. cognite/neat/data_model/models/entities/__init__.py +0 -9
  138. cognite_neat-0.123.33.dist-info/RECORD +0 -215
  139. /cognite/neat/{data_model → _data_model}/models/entities/_constants.py +0 -0
  140. /cognite/neat/{core → v0}/__init__.py +0 -0
  141. /cognite/neat/{core/_client/_api → v0/core}/__init__.py +0 -0
  142. /cognite/neat/{core → v0/core}/_client/__init__.py +0 -0
  143. /cognite/neat/{core/_client/data_classes → v0/core/_client/_api}/__init__.py +0 -0
  144. /cognite/neat/{core/_data_model → v0/core/_client/data_classes}/__init__.py +0 -0
  145. /cognite/neat/{core → v0/core}/_client/data_classes/data_modeling.py +0 -0
  146. /cognite/neat/{core → v0/core}/_client/data_classes/neat_sequence.py +0 -0
  147. /cognite/neat/{core → v0/core}/_client/data_classes/statistics.py +0 -0
  148. /cognite/neat/{core → v0/core}/_config.py +0 -0
  149. /cognite/neat/{core/_instances → v0/core/_data_model}/__init__.py +0 -0
  150. /cognite/neat/{core → v0/core}/_data_model/_constants.py +0 -0
  151. /cognite/neat/{core → v0/core}/_data_model/analysis/__init__.py +0 -0
  152. /cognite/neat/{core → v0/core}/_data_model/catalog/__init__.py +0 -0
  153. /cognite/neat/{core → v0/core}/_data_model/catalog/classic_model.xlsx +0 -0
  154. /cognite/neat/{core → v0/core}/_data_model/catalog/conceptual-imf-data-model.xlsx +0 -0
  155. /cognite/neat/{core → v0/core}/_data_model/catalog/hello_world_pump.xlsx +0 -0
  156. /cognite/neat/{core → v0/core}/_data_model/exporters/__init__.py +0 -0
  157. /cognite/neat/{core → v0/core}/_data_model/importers/__init__.py +0 -0
  158. /cognite/neat/{core → v0/core}/_data_model/importers/_rdf/__init__.py +0 -0
  159. /cognite/neat/{core → v0/core}/_data_model/models/_base_unverified.py +0 -0
  160. /cognite/neat/{core → v0/core}/_data_model/models/conceptual/__init__.py +0 -0
  161. /cognite/neat/{core → v0/core}/_data_model/models/entities/__init__.py +0 -0
  162. /cognite/neat/{core → v0/core}/_data_model/models/entities/_constants.py +0 -0
  163. /cognite/neat/{core → v0/core}/_data_model/models/entities/_types.py +0 -0
  164. /cognite/neat/{core → v0/core}/_data_model/models/entities/_wrapped.py +0 -0
  165. /cognite/neat/{core → v0/core}/_data_model/models/mapping/__init__.py +0 -0
  166. /cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.yaml +0 -0
  167. /cognite/neat/{core → v0/core}/_data_model/transformers/__init__.py +0 -0
  168. /cognite/neat/{core/_instances/extractors/_classic_cdf → v0/core/_instances}/__init__.py +0 -0
  169. /cognite/neat/{core → v0/core}/_instances/_shared.py +0 -0
  170. /cognite/neat/{core → v0/core}/_instances/_tracking/__init__.py +0 -0
  171. /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -0
  172. /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44.xml +0 -0
  173. /cognite/neat/{core → v0/core}/_instances/examples/__init__.py +0 -0
  174. /cognite/neat/{core → v0/core}/_instances/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  175. /cognite/neat/{core/_utils → v0/core/_instances/extractors/_classic_cdf}/__init__.py +0 -0
  176. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_assets.py +0 -0
  177. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_data_sets.py +0 -0
  178. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_events.py +0 -0
  179. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_files.py +0 -0
  180. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_labels.py +0 -0
  181. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_timeseries.py +0 -0
  182. /cognite/neat/{core → v0/core}/_instances/loaders/__init__.py +0 -0
  183. /cognite/neat/{core → v0/core}/_instances/queries/__init__.py +0 -0
  184. /cognite/neat/{core → v0/core}/_instances/queries/_base.py +0 -0
  185. /cognite/neat/{core → v0/core}/_instances/queries/_queries.py +0 -0
  186. /cognite/neat/{core → v0/core}/_instances/transformers/__init__.py +0 -0
  187. /cognite/neat/{core → v0/core}/_issues/__init__.py +0 -0
  188. /cognite/neat/{core → v0/core}/_issues/formatters.py +0 -0
  189. /cognite/neat/{core → v0/core}/_shared.py +0 -0
  190. /cognite/neat/{core → v0/core}/_store/__init__.py +0 -0
  191. /cognite/neat/{data_model → v0/core/_utils}/__init__.py +0 -0
  192. /cognite/neat/{core → v0/core}/_utils/io_.py +0 -0
  193. /cognite/neat/{core → v0/core}/_utils/reader/__init__.py +0 -0
  194. /cognite/neat/{core → v0/core}/_utils/tarjan.py +0 -0
  195. /cognite/neat/{core → v0/core}/_utils/time_.py +0 -0
  196. /cognite/neat/{core → v0/core}/_utils/xml_.py +0 -0
  197. /cognite/neat/{plugins → v0/plugins}/__init__.py +0 -0
  198. /cognite/neat/{plugins → v0/plugins}/data_model/__init__.py +0 -0
  199. /cognite/neat/{plugins → v0/plugins}/data_model/importers/__init__.py +0 -0
  200. /cognite/neat/{session → v0/session}/__init__.py +0 -0
  201. /cognite/neat/{session → v0/session}/_experimental.py +0 -0
  202. /cognite/neat/{session → v0/session}/_state/README.md +0 -0
  203. /cognite/neat/{session → v0/session}/engine/__init__.py +0 -0
  204. /cognite/neat/{session → v0/session}/engine/_import.py +0 -0
  205. /cognite/neat/{session → v0/session}/engine/_interface.py +0 -0
  206. {cognite_neat-0.123.33.dist-info → cognite_neat-0.123.34.dist-info}/WHEEL +0 -0
  207. {cognite_neat-0.123.33.dist-info → cognite_neat-0.123.34.dist-info}/licenses/LICENSE +0 -0
cognite/neat/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
- from cognite.neat.core._utils.auth import get_cognite_client
1
+ from cognite.neat.v0.core._utils.auth import get_cognite_client
2
+ from cognite.neat.v0.session import NeatSession
2
3
 
3
4
  from ._version import __version__
4
- from .session import NeatSession
5
5
 
6
6
  __all__ = ["NeatSession", "__version__", "get_cognite_client"]
@@ -0,0 +1,3 @@
1
+ from ._identifiers import NameSpace
2
+
3
+ XML_SCHEMA_NAMESPACE = NameSpace("http://www.w3.org/2001/XMLSchema#")
@@ -0,0 +1,61 @@
1
+ from pydantic import HttpUrl, RootModel, ValidationError
2
+
3
+ from cognite.neat.v0.core._utils.auxiliary import local_import
4
+
5
+
6
+ class URI(RootModel[str]):
7
+ def __init__(self, value: str):
8
+ try:
9
+ # Use Pydantic's AnyUrl to validate the URI
10
+ _ = HttpUrl(value)
11
+ except ValidationError as e:
12
+ raise ValueError(f"Invalid URI: {value}") from e
13
+ super().__init__(value)
14
+
15
+ def __str__(self) -> str:
16
+ return self.root
17
+
18
+ def __repr__(self) -> str:
19
+ return f"URI({self.root!r})"
20
+
21
+ def as_rdflib_uriref(self): # type: ignore[no-untyped-def]
22
+ # rdflib is an optional dependency, so import here
23
+ local_import("rdflib", "rdflib")
24
+ from rdflib import URIRef
25
+
26
+ return URIRef(self.root)
27
+
28
+
29
+ class NameSpace(RootModel[str]):
30
+ def __init__(self, value: str):
31
+ try:
32
+ # Use Pydantic's AnyUrl to validate the URI
33
+ _ = HttpUrl(value)
34
+ except ValidationError as e:
35
+ raise ValueError(f"Invalid Namespace: {value}") from e
36
+ super().__init__(value)
37
+
38
+ def __str__(self) -> str:
39
+ return self.root
40
+
41
+ def __repr__(self) -> str:
42
+ return f"NameSpace({self.root!r})"
43
+
44
+ def term(self, name: str) -> URI:
45
+ # need to handle slices explicitly because of __getitem__ override
46
+ return URI(self.root + (name if isinstance(name, str) else ""))
47
+
48
+ def __getitem__(self, key: str) -> URI: # type: ignore[override]
49
+ return self.term(key)
50
+
51
+ def __getattr__(self, name: str) -> URI:
52
+ if name.startswith("__"): # ignore any special Python names!
53
+ raise AttributeError
54
+ return self.term(name)
55
+
56
+ def as_rdflib_namespace(self): # type: ignore[no-untyped-def]
57
+ # rdflib is an optional dependency, so import here
58
+ local_import("rdflib", "rdflib")
59
+ from rdflib import Namespace
60
+
61
+ return Namespace(self.root)
@@ -2,7 +2,7 @@ from abc import ABC
2
2
 
3
3
  from pydantic import Field, field_validator
4
4
 
5
- from cognite.neat.core._utils.text import humanize_collection
5
+ from cognite.neat.v0.core._utils.text import humanize_collection
6
6
 
7
7
  from ._base import WriteableResource
8
8
  from ._constants import FORBIDDEN_SPACES, SPACE_FORMAT_PATTERN
@@ -0,0 +1,46 @@
1
+ from ._constants import Undefined, Unknown
2
+ from ._data_types import (
3
+ AnyURI,
4
+ Boolean,
5
+ DataType,
6
+ Date,
7
+ DateTime,
8
+ DateTimeStamp,
9
+ Double,
10
+ Enum,
11
+ File,
12
+ Float,
13
+ Integer,
14
+ Json,
15
+ Long,
16
+ Sequence,
17
+ String,
18
+ Timeseries,
19
+ )
20
+ from ._identifiers import URI, NameSpace
21
+ from ._parser import ParsedEntity, parse_entity
22
+
23
+ __all__ = [
24
+ "URI",
25
+ "AnyURI",
26
+ "Boolean",
27
+ "DataType",
28
+ "Date",
29
+ "DateTime",
30
+ "DateTimeStamp",
31
+ "Double",
32
+ "Enum",
33
+ "File",
34
+ "Float",
35
+ "Integer",
36
+ "Json",
37
+ "Long",
38
+ "NameSpace",
39
+ "ParsedEntity",
40
+ "Sequence",
41
+ "String",
42
+ "Timeseries",
43
+ "Undefined",
44
+ "Unknown",
45
+ "parse_entity",
46
+ ]
@@ -0,0 +1,100 @@
1
+ from functools import total_ordering
2
+ from typing import Any
3
+
4
+ from pydantic import BaseModel, Field, field_validator, model_serializer
5
+
6
+ from ._constants import (
7
+ Undefined,
8
+ Unknown,
9
+ _UndefinedType,
10
+ _UnknownType,
11
+ )
12
+
13
+
14
+ @total_ordering
15
+ class Entity(BaseModel, extra="ignore", populate_by_name=True):
16
+ """Entity is a concept, class, property, datatype in semantics sense."""
17
+
18
+ prefix: str | _UndefinedType = Field(
19
+ default=Undefined, pattern=r"^[a-zA-Z][a-zA-Z0-9_-]{0,41}[a-zA-Z0-9]?$", min_length=1, max_length=43
20
+ )
21
+ suffix: str = Field(min_length=1, max_length=255, pattern=r"^[a-zA-Z0-9._~?@!$&'*+,;=%-]+$")
22
+
23
+ @model_serializer(when_used="unless-none", return_type=str)
24
+ def as_str(self) -> str:
25
+ return str(self)
26
+
27
+ @field_validator("*", mode="before")
28
+ def strip_string(cls, value: Any) -> Any:
29
+ if isinstance(value, str):
30
+ return value.strip()
31
+ elif isinstance(value, list):
32
+ return [entry.strip() if isinstance(entry, str) else entry for entry in value]
33
+ return value
34
+
35
+ def as_tuple(self) -> tuple[str, ...]:
36
+ # We haver overwritten the serialization to str, so we need to do it manually
37
+ extra: tuple[str, ...] = tuple(
38
+ [
39
+ str(v or "")
40
+ for field_name in self.model_fields.keys()
41
+ if (v := getattr(self, field_name)) and field_name not in {"prefix", "suffix"}
42
+ ]
43
+ )
44
+ if isinstance(self.prefix, _UndefinedType):
45
+ return str(self.suffix), *extra
46
+ else:
47
+ return self.prefix, str(self.suffix), *extra
48
+
49
+ def __lt__(self, other: object) -> bool:
50
+ if type(other) is not type(self):
51
+ return NotImplemented
52
+ return self.as_tuple() < other.as_tuple() # type: ignore[attr-defined]
53
+
54
+ def __eq__(self, other: object) -> bool:
55
+ # We need to be explicit that we are not allowing comparison between different types
56
+ if type(other) is not type(self):
57
+ # requires explicit raising as NotImplemented would lead to running comparison
58
+ raise TypeError(f"'==' not supported between instances of {type(self).__name__} and {type(other).__name__}")
59
+ return self.as_tuple() == other.as_tuple() # type: ignore[attr-defined]
60
+
61
+ def __hash__(self) -> int:
62
+ return hash(f"{type(self).__name__}({self})")
63
+
64
+ def __str__(self) -> str:
65
+ # there are three cases for string representation:
66
+ # 1. only suffix is present -> return str(suffix)
67
+ # 2. prefix and suffix are present -> return "prefix:suffix"
68
+ # 3. prefix, suffix and other fields are present -> return "prefix:suffix(field1=value1,field2=value2)"
69
+
70
+ model_dump = {k: v for k in self.model_fields if (v := getattr(self, k)) is not None}
71
+
72
+ base_str = f"{self.prefix}:{self.suffix}" if not isinstance(self.prefix, _UndefinedType) else str(self.suffix)
73
+
74
+ extra_fields = {
75
+ (self.model_fields[k].alias or k): v for k, v in model_dump.items() if k not in {"prefix", "suffix"}
76
+ }
77
+ if extra_fields:
78
+ extra_str = ",".join([f"{k}={v}" for k, v in extra_fields.items()])
79
+ return f"{base_str}({extra_str})"
80
+ else:
81
+ return base_str
82
+
83
+ def __repr__(self) -> str:
84
+ # We have overwritten the serialization to str, so we need to do it manually
85
+ model_dump = {k: v for k in self.model_fields if (v := getattr(self, k)) is not None}
86
+ args = ",".join([f"{k}={v!r}" for k, v in model_dump.items()])
87
+ return f"{type(self).__name__}({args})"
88
+
89
+
90
+ class ConceptEntity(Entity):
91
+ version: str | None = None
92
+
93
+
94
+ class UnknownEntity(ConceptEntity):
95
+ prefix: _UndefinedType = Undefined
96
+ suffix: _UnknownType = Unknown # type: ignore[assignment]
97
+
98
+ @property
99
+ def id(self) -> str:
100
+ return str(Unknown)
@@ -0,0 +1,144 @@
1
+ from datetime import date, datetime
2
+
3
+ from pydantic import Field
4
+
5
+ from cognite.neat._data_model._constants import XML_SCHEMA_NAMESPACE
6
+ from cognite.neat._data_model._identifiers import URI
7
+
8
+ from ._base import Entity
9
+
10
+
11
+ class UnitEntity(Entity): ...
12
+
13
+
14
+ class EnumCollectionEntity(Entity): ...
15
+
16
+
17
+ class DataType(Entity):
18
+ prefix: str = Field("xsd", frozen=True)
19
+
20
+ @property
21
+ def python(self) -> type:
22
+ raise NotImplementedError()
23
+
24
+ @property
25
+ def xsd(self) -> URI:
26
+ return XML_SCHEMA_NAMESPACE[self.suffix]
27
+
28
+
29
+ class Boolean(DataType):
30
+ suffix: str = Field("boolean", frozen=True)
31
+
32
+ @property
33
+ def python(self) -> type:
34
+ return bool
35
+
36
+
37
+ class Float(DataType):
38
+ suffix: str = Field("float", frozen=True)
39
+ unit: UnitEntity | None = None
40
+
41
+ @property
42
+ def python(self) -> type:
43
+ return float
44
+
45
+
46
+ class Double(DataType):
47
+ suffix: str = Field("double", frozen=True)
48
+ unit: UnitEntity | None = None
49
+
50
+ @property
51
+ def python(self) -> type:
52
+ return float
53
+
54
+
55
+ class Integer(DataType):
56
+ suffix: str = Field("integer", frozen=True)
57
+ unit: UnitEntity | None = None
58
+
59
+ @property
60
+ def python(self) -> type:
61
+ return int
62
+
63
+
64
+ class Long(DataType):
65
+ suffix: str = Field("long", frozen=True)
66
+ unit: UnitEntity | None = None
67
+
68
+ @property
69
+ def python(self) -> type:
70
+ return int
71
+
72
+
73
+ class String(DataType):
74
+ suffix: str = Field("string", frozen=True)
75
+ max_text_size: int | None = Field(
76
+ None,
77
+ alias="maxTextSize",
78
+ description="Specifies the maximum size in bytes of the text property, when encoded with utf-8.",
79
+ )
80
+
81
+ @property
82
+ def python(self) -> type:
83
+ return str
84
+
85
+
86
+ class AnyURI(DataType):
87
+ suffix: str = Field("anyURI", frozen=True)
88
+
89
+ @property
90
+ def python(self) -> type:
91
+ return str
92
+
93
+
94
+ class Date(DataType):
95
+ suffix: str = Field("date", frozen=True)
96
+
97
+ @property
98
+ def python(self) -> type:
99
+ return date
100
+
101
+
102
+ class DateTime(DataType):
103
+ suffix: str = Field("dateTime", frozen=True)
104
+
105
+ @property
106
+ def python(self) -> type:
107
+ return datetime
108
+
109
+
110
+ class DateTimeStamp(DataType):
111
+ suffix: str = Field("dateTimeStamp", frozen=True)
112
+
113
+ @property
114
+ def python(self) -> type:
115
+ return datetime
116
+
117
+
118
+ # CDF Specific extensions of XSD types
119
+
120
+
121
+ class Timeseries(DataType):
122
+ suffix: str = Field("timeseries", frozen=True)
123
+
124
+
125
+ class File(DataType):
126
+ suffix: str = Field("string", frozen=True)
127
+
128
+
129
+ class Sequence(DataType):
130
+ suffix: str = Field("sequence", frozen=True)
131
+
132
+
133
+ class Json(DataType):
134
+ suffix: str = Field("json", frozen=True)
135
+
136
+ @property
137
+ def python(self) -> type:
138
+ return dict
139
+
140
+
141
+ class Enum(DataType):
142
+ suffix: str = Field("enum", frozen=True)
143
+ collection: EnumCollectionEntity
144
+ unknown_value: str | None = Field(None, alias="unknownValue")
@@ -1,6 +1,6 @@
1
1
  from pydantic import HttpUrl, RootModel, ValidationError
2
2
 
3
- from cognite.neat.core._utils.auxiliary import local_import
3
+ from cognite.neat.v0.core._utils.auxiliary import local_import
4
4
 
5
5
 
6
6
  class URI(RootModel[str]):
@@ -0,0 +1,194 @@
1
+ from dataclasses import dataclass
2
+
3
+ SPECIAL_CHARACTERS = ":()=,"
4
+
5
+
6
+ @dataclass
7
+ class ParsedEntity:
8
+ """Represents a parsed entity string."""
9
+
10
+ prefix: str
11
+ suffix: str
12
+ properties: dict[str, str]
13
+
14
+
15
+ class _EntityParser:
16
+ """A parser for entity strings in the format 'prefix:suffix(prop1=val1,prop2=val2)'."""
17
+
18
+ def __init__(self, entity_string: str):
19
+ """Initialize the parser with the entity string to parse.
20
+
21
+ Args:
22
+ entity_string: The entity string to parse.
23
+ """
24
+ self.entity_string = entity_string.strip() if entity_string else ""
25
+ self.pos = 0
26
+ self.length = len(self.entity_string)
27
+
28
+ def peek(self) -> str:
29
+ """Peek at current character without advancing position."""
30
+ if self.pos >= self.length:
31
+ return ""
32
+ return self.entity_string[self.pos]
33
+
34
+ def advance(self) -> str:
35
+ """Get current character and advance position."""
36
+ if self.pos >= self.length:
37
+ return ""
38
+ char = self.entity_string[self.pos]
39
+ self.pos += 1
40
+ return char
41
+
42
+ def skip_whitespace(self) -> None:
43
+ """Skip whitespace characters."""
44
+ while self.pos < self.length and self.entity_string[self.pos].isspace():
45
+ self.pos += 1
46
+
47
+ def parse_identifier(self) -> str:
48
+ """Parse an identifier (letters, numbers, underscores, etc.)."""
49
+ start = self.pos
50
+ while self.pos < self.length and self.entity_string[self.pos] not in SPECIAL_CHARACTERS:
51
+ self.pos += 1
52
+ return self.entity_string[start : self.pos].strip()
53
+
54
+ def parse_property_value(self) -> str:
55
+ """Parse a property value, handling nested parentheses."""
56
+ start = self.pos
57
+ paren_depth = 0
58
+
59
+ while self.pos < self.length:
60
+ char = self.entity_string[self.pos]
61
+ if char == "(":
62
+ paren_depth += 1
63
+ elif char == ")":
64
+ if paren_depth == 0:
65
+ # This is the closing paren of the properties section
66
+ break
67
+ paren_depth -= 1
68
+ elif char == "," and paren_depth == 0:
69
+ # This is a property separator, not part of the value
70
+ break
71
+ self.pos += 1
72
+
73
+ return self.entity_string[start : self.pos].strip()
74
+
75
+ def parse_properties(self) -> dict[str, str]:
76
+ """Parse properties within parentheses."""
77
+ properties = {}
78
+
79
+ # Skip opening parenthesis
80
+ if self.peek() == "(":
81
+ self.advance()
82
+ else:
83
+ raise ValueError("expected `(`")
84
+
85
+ self.skip_whitespace()
86
+
87
+ while self.pos < self.length and self.peek() != ")":
88
+ # Parse property name
89
+ self.skip_whitespace()
90
+ if self.peek() == ")":
91
+ break
92
+
93
+ prop_name = self.parse_identifier()
94
+ if not prop_name:
95
+ raise ValueError(f"Expected property name at position {self.pos}. Got {self.peek()!r}")
96
+ self.skip_whitespace()
97
+
98
+ # Expect '='
99
+ if self.peek() != "=":
100
+ raise ValueError(
101
+ f"Expected '=' after property name '{prop_name}' at position {self.pos}. Got {self.peek()!r}"
102
+ )
103
+ self.advance() # consume '='
104
+
105
+ self.skip_whitespace()
106
+
107
+ # Parse property value (handles complex values)
108
+ prop_value = self.parse_property_value()
109
+
110
+ properties[prop_name] = prop_value
111
+
112
+ self.skip_whitespace()
113
+
114
+ # Check for comma or end
115
+ if self.peek() == ",":
116
+ self.advance() # consume ','
117
+
118
+ # Check if we reached the end without finding a closing parenthesis
119
+ if self.pos >= self.length:
120
+ raise ValueError(f"Expected ')' to close properties at position {self.length}")
121
+
122
+ # Skip closing parenthesis
123
+ if self.peek() == ")":
124
+ self.advance()
125
+
126
+ return properties
127
+
128
+ def parse(self) -> ParsedEntity:
129
+ """Parse the entity string and return prefix, suffix, and properties.
130
+
131
+ Returns:
132
+ A `ParsedEntity` object containing the parsed components of the entity string.
133
+ """
134
+ if not self.entity_string:
135
+ return ParsedEntity(prefix="", suffix="", properties={})
136
+ if self.entity_string.strip() == ":":
137
+ raise ValueError("Expected identifier at position 0")
138
+
139
+ # Parse the main identifier (could be prefix:suffix or just suffix)
140
+ main_id = self.parse_identifier()
141
+
142
+ # Check if there's a colon (indicating prefix:suffix)
143
+ prefix = ""
144
+ suffix = ""
145
+
146
+ if self.peek() == ":":
147
+ self.advance() # consume ':'
148
+ prefix = main_id
149
+ suffix = self.parse_identifier()
150
+ if not suffix:
151
+ raise ValueError(f"Expected identifier after ':' at position {self.pos}")
152
+ else:
153
+ suffix = main_id
154
+
155
+ # Check if there are properties
156
+ self.skip_whitespace()
157
+ properties = {}
158
+ if self.peek() == "(":
159
+ properties = self.parse_properties()
160
+
161
+ # Check for unexpected trailing characters
162
+ self.skip_whitespace()
163
+ if self.pos < self.length:
164
+ raise ValueError(f"Unexpected characters after properties at position {self.pos}. Got {self.peek()!r}")
165
+
166
+ return ParsedEntity(prefix, suffix, properties)
167
+
168
+
169
+ def parse_entity(entity_string: str) -> ParsedEntity:
170
+ """Parse an entity string into its prefix, suffix, and properties.
171
+
172
+ Args:
173
+ entity_string (str): The entity string to parse. It can be in the format "prefix:suffix(prop1=val1,prop2=val2)"
174
+ or "suffix(prop1=val1,prop2=val2)" or just "suffix".
175
+
176
+ Returns:
177
+ A `ParsedEntity` object containing the parsed components of the entity string.
178
+
179
+
180
+ Raises:
181
+ ValueError: If the entity string is malformed.
182
+
183
+ This parser allows arbitrary characters in property values, including nested parentheses.
184
+ Reserved characters like '=', ',', '(', and ')' are used for parsing structure and cannot appear
185
+ unescaped in property names.
186
+
187
+ For example, it can parse:
188
+ - "asset:vehicle(type=car,details=(color=red,size=large))"
189
+ - "device(sensor(model=X100,features=(wifi,bluetooth)))"
190
+ - "location(city=New York,state=NY)"
191
+
192
+ """
193
+ parser = _EntityParser(entity_string)
194
+ return parser.parse()
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.123.33"
1
+ __version__ = "0.123.34"
2
2
  __engine__ = "^2.0.4"
@@ -55,14 +55,14 @@ from cognite.client.data_classes.data_modeling.views import (
55
55
  from cognite.client.exceptions import CogniteAPIError
56
56
  from cognite.client.utils.useful_types import SequenceNotStr
57
57
 
58
- from cognite.neat.core._client.data_classes.data_modeling import Component
59
- from cognite.neat.core._client.data_classes.schema import DMSSchema
60
- from cognite.neat.core._issues.warnings import CDFMaxIterationsWarning
61
- from cognite.neat.core._shared import T_ID
62
- from cognite.neat.core._utils.tarjan import tarjan
58
+ from cognite.neat.v0.core._client.data_classes.data_modeling import Component
59
+ from cognite.neat.v0.core._client.data_classes.schema import DMSSchema
60
+ from cognite.neat.v0.core._issues.warnings import CDFMaxIterationsWarning
61
+ from cognite.neat.v0.core._shared import T_ID
62
+ from cognite.neat.v0.core._utils.tarjan import tarjan
63
63
 
64
64
  if TYPE_CHECKING:
65
- from cognite.neat.core._client._api_client import NeatClient
65
+ from cognite.neat.v0.core._client._api_client import NeatClient
66
66
 
67
67
  T_WritableCogniteResourceList = TypeVar("T_WritableCogniteResourceList", bound=WriteableCogniteResourceList)
68
68
 
@@ -7,13 +7,13 @@ from cognite.client.data_classes.filters import Filter
7
7
  from cognite.client.exceptions import CogniteAPIError
8
8
  from cognite.client.utils.useful_types import SequenceNotStr
9
9
 
10
- from cognite.neat.core._constants import DMS_INSTANCE_LIMIT_MARGIN
11
- from cognite.neat.core._issues import NeatIssue
12
- from cognite.neat.core._issues.errors import WillExceedLimitError
13
- from cognite.neat.core._issues.warnings import NeatValueWarning
10
+ from cognite.neat.v0.core._constants import DMS_INSTANCE_LIMIT_MARGIN
11
+ from cognite.neat.v0.core._issues import NeatIssue
12
+ from cognite.neat.v0.core._issues.errors import WillExceedLimitError
13
+ from cognite.neat.v0.core._issues.warnings import NeatValueWarning
14
14
 
15
15
  if TYPE_CHECKING:
16
- from cognite.neat.core._client._api_client import NeatClient
16
+ from cognite.neat.v0.core._client._api_client import NeatClient
17
17
 
18
18
 
19
19
  class NeatInstancesAPI:
@@ -5,17 +5,17 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from cognite.client import data_modeling as dm
7
7
 
8
- from cognite.neat.core._client.data_classes.data_modeling import (
8
+ from cognite.neat.v0.core._client.data_classes.data_modeling import (
9
9
  ContainerApplyDict,
10
10
  SpaceApplyDict,
11
11
  ViewApplyDict,
12
12
  )
13
- from cognite.neat.core._client.data_classes.schema import DMSSchema
14
- from cognite.neat.core._constants import is_hierarchy_property
15
- from cognite.neat.core._issues.errors import NeatValueError
13
+ from cognite.neat.v0.core._client.data_classes.schema import DMSSchema
14
+ from cognite.neat.v0.core._constants import is_hierarchy_property
15
+ from cognite.neat.v0.core._issues.errors import NeatValueError
16
16
 
17
17
  if TYPE_CHECKING:
18
- from cognite.neat.core._client._api_client import NeatClient
18
+ from cognite.neat.v0.core._client._api_client import NeatClient
19
19
 
20
20
 
21
21
  class SchemaAPI:
@@ -7,7 +7,7 @@ from cognite.client.config import ClientConfig
7
7
  from cognite.client.data_classes.data_modeling.ids import _load_space_identifier
8
8
  from cognite.client.utils.useful_types import SequenceNotStr
9
9
 
10
- from cognite.neat.core._client.data_classes.statistics import (
10
+ from cognite.neat.v0.core._client.data_classes.statistics import (
11
11
  ProjectStatsAndLimits,
12
12
  SpaceInstanceCounts,
13
13
  SpaceInstanceCountsList,
@@ -34,7 +34,7 @@ class StatisticsAPI(APIClient):
34
34
  Examples:
35
35
  Fetch project statistics (and limits) and check the current number of data models vs.
36
36
  and how many more can be created:
37
- >>> from cognite.neat.core._client import NeatClient
37
+ >>> from cognite.neat.v0.core._client import NeatClient
38
38
  >>> client = NeatClient()
39
39
  >>> stats = client.instance_statistics.project()
40
40
  >>> num_dm = stats.data_models.current
@@ -64,7 +64,7 @@ class StatisticsAPI(APIClient):
64
64
 
65
65
  Examples:
66
66
  Fetch statistics for a single space:
67
- >>> from cognite.neat.core._client import NeatClient
67
+ >>> from cognite.neat.v0.core._client import NeatClient
68
68
  >>> client = NeatClient()
69
69
  >>> res = client.instance_statistics.list("my-space")
70
70
  Fetch statistics for multiple spaces:
@@ -1,6 +1,6 @@
1
1
  from cognite.client import ClientConfig, CogniteClient
2
2
 
3
- from cognite.neat.core._utils.auth import _CLIENT_NAME
3
+ from cognite.neat.v0.core._utils.auth import _CLIENT_NAME
4
4
 
5
5
  from ._api.data_modeling_loaders import DataModelLoaderAPI
6
6
  from ._api.neat_instances import NeatInstancesAPI