cognite-neat 0.123.32__py3-none-any.whl → 0.127.30__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 (320) hide show
  1. cognite/neat/__init__.py +2 -2
  2. cognite/neat/_client/__init__.py +4 -0
  3. cognite/neat/_client/api.py +8 -0
  4. cognite/neat/_client/client.py +21 -0
  5. cognite/neat/_client/config.py +40 -0
  6. cognite/neat/_client/containers_api.py +125 -0
  7. cognite/neat/_client/data_classes.py +44 -0
  8. cognite/neat/_client/data_model_api.py +115 -0
  9. cognite/neat/_client/spaces_api.py +115 -0
  10. cognite/neat/_client/statistics_api.py +24 -0
  11. cognite/neat/_client/views_api.py +129 -0
  12. cognite/neat/_config.py +185 -0
  13. cognite/neat/_data_model/_analysis.py +196 -0
  14. cognite/neat/_data_model/_constants.py +67 -0
  15. cognite/neat/_data_model/_identifiers.py +61 -0
  16. cognite/neat/_data_model/_shared.py +41 -0
  17. cognite/neat/_data_model/deployer/_differ.py +140 -0
  18. cognite/neat/_data_model/deployer/_differ_container.py +360 -0
  19. cognite/neat/_data_model/deployer/_differ_data_model.py +54 -0
  20. cognite/neat/_data_model/deployer/_differ_space.py +9 -0
  21. cognite/neat/_data_model/deployer/_differ_view.py +299 -0
  22. cognite/neat/_data_model/deployer/data_classes.py +529 -0
  23. cognite/neat/_data_model/deployer/deployer.py +401 -0
  24. cognite/neat/_data_model/exporters/__init__.py +15 -0
  25. cognite/neat/_data_model/exporters/_api_exporter.py +37 -0
  26. cognite/neat/_data_model/exporters/_base.py +24 -0
  27. cognite/neat/_data_model/exporters/_table_exporter/exporter.py +128 -0
  28. cognite/neat/_data_model/exporters/_table_exporter/workbook.py +409 -0
  29. cognite/neat/_data_model/exporters/_table_exporter/writer.py +421 -0
  30. cognite/neat/_data_model/importers/__init__.py +5 -0
  31. cognite/neat/_data_model/importers/_api_importer.py +166 -0
  32. cognite/neat/_data_model/importers/_base.py +16 -0
  33. cognite/neat/_data_model/importers/_table_importer/data_classes.py +295 -0
  34. cognite/neat/_data_model/importers/_table_importer/importer.py +192 -0
  35. cognite/neat/_data_model/importers/_table_importer/reader.py +1063 -0
  36. cognite/neat/_data_model/importers/_table_importer/source.py +94 -0
  37. cognite/neat/_data_model/models/conceptual/_base.py +18 -0
  38. cognite/neat/_data_model/models/conceptual/_concept.py +67 -0
  39. cognite/neat/_data_model/models/conceptual/_data_model.py +51 -0
  40. cognite/neat/_data_model/models/conceptual/_properties.py +104 -0
  41. cognite/neat/_data_model/models/conceptual/_property.py +105 -0
  42. cognite/neat/_data_model/models/dms/__init__.py +198 -2
  43. cognite/neat/_data_model/models/dms/_base.py +13 -9
  44. cognite/neat/_data_model/models/dms/_constants.py +47 -1
  45. cognite/neat/_data_model/models/dms/_constraints.py +42 -0
  46. cognite/neat/_data_model/models/dms/_container.py +159 -0
  47. cognite/neat/_data_model/models/dms/_data_model.py +95 -0
  48. cognite/neat/_data_model/models/dms/_data_types.py +195 -0
  49. cognite/neat/_data_model/models/dms/_http.py +28 -0
  50. cognite/neat/_data_model/models/dms/_indexes.py +30 -0
  51. cognite/neat/_data_model/models/dms/_limits.py +96 -0
  52. cognite/neat/_data_model/models/dms/_references.py +135 -0
  53. cognite/neat/_data_model/models/dms/_schema.py +18 -0
  54. cognite/neat/_data_model/models/dms/_space.py +14 -10
  55. cognite/neat/_data_model/models/dms/_types.py +17 -0
  56. cognite/neat/_data_model/models/dms/_view_filter.py +282 -0
  57. cognite/neat/_data_model/models/dms/_view_property.py +235 -0
  58. cognite/neat/_data_model/models/dms/_views.py +210 -0
  59. cognite/neat/_data_model/models/entities/__init__.py +50 -0
  60. cognite/neat/_data_model/models/entities/_base.py +101 -0
  61. cognite/neat/{data_model → _data_model}/models/entities/_constants.py +5 -0
  62. cognite/neat/_data_model/models/entities/_data_types.py +144 -0
  63. cognite/neat/{data_model → _data_model}/models/entities/_identifiers.py +1 -1
  64. cognite/neat/_data_model/models/entities/_parser.py +226 -0
  65. cognite/neat/_data_model/validation/dms/__init__.py +75 -0
  66. cognite/neat/_data_model/validation/dms/_ai_readiness.py +364 -0
  67. cognite/neat/_data_model/validation/dms/_base.py +307 -0
  68. cognite/neat/_data_model/validation/dms/_connections.py +638 -0
  69. cognite/neat/_data_model/validation/dms/_consistency.py +57 -0
  70. cognite/neat/_data_model/validation/dms/_containers.py +174 -0
  71. cognite/neat/_data_model/validation/dms/_limits.py +420 -0
  72. cognite/neat/_data_model/validation/dms/_orchestrator.py +222 -0
  73. cognite/neat/_data_model/validation/dms/_views.py +103 -0
  74. cognite/neat/_exceptions.py +56 -0
  75. cognite/neat/_issues.py +68 -0
  76. cognite/neat/_session/__init__.py +3 -0
  77. cognite/neat/_session/_html/_render.py +30 -0
  78. cognite/neat/_session/_html/static/__init__.py +8 -0
  79. cognite/neat/_session/_html/static/deployment.css +303 -0
  80. cognite/neat/_session/_html/static/deployment.js +150 -0
  81. cognite/neat/_session/_html/static/issues.css +211 -0
  82. cognite/neat/_session/_html/static/issues.js +168 -0
  83. cognite/neat/_session/_html/static/shared.css +186 -0
  84. cognite/neat/_session/_html/templates/__init__.py +4 -0
  85. cognite/neat/_session/_html/templates/deployment.html +75 -0
  86. cognite/neat/_session/_html/templates/issues.html +45 -0
  87. cognite/neat/_session/_issues.py +81 -0
  88. cognite/neat/_session/_opt.py +35 -0
  89. cognite/neat/_session/_physical.py +261 -0
  90. cognite/neat/_session/_result.py +236 -0
  91. cognite/neat/_session/_session.py +88 -0
  92. cognite/neat/_session/_usage_analytics/_collector.py +131 -0
  93. cognite/neat/_session/_usage_analytics/_constants.py +23 -0
  94. cognite/neat/_session/_usage_analytics/_storage.py +240 -0
  95. cognite/neat/_session/_wrappers.py +82 -0
  96. cognite/neat/_state_machine/__init__.py +10 -0
  97. cognite/neat/_state_machine/_base.py +37 -0
  98. cognite/neat/_state_machine/_states.py +52 -0
  99. cognite/neat/_store/__init__.py +3 -0
  100. cognite/neat/_store/_provenance.py +81 -0
  101. cognite/neat/_store/_store.py +156 -0
  102. cognite/neat/_utils/_reader.py +194 -0
  103. cognite/neat/_utils/auxiliary.py +7 -0
  104. cognite/neat/_utils/collection.py +11 -0
  105. cognite/neat/_utils/http_client/__init__.py +39 -0
  106. cognite/neat/_utils/http_client/_client.py +245 -0
  107. cognite/neat/_utils/http_client/_config.py +19 -0
  108. cognite/neat/_utils/http_client/_data_classes.py +294 -0
  109. cognite/neat/_utils/http_client/_tracker.py +31 -0
  110. cognite/neat/_utils/text.py +71 -0
  111. cognite/neat/_utils/useful_types.py +37 -0
  112. cognite/neat/_utils/validation.py +154 -0
  113. cognite/neat/_version.py +1 -1
  114. cognite/neat/v0/core/_client/_api/__init__.py +0 -0
  115. cognite/neat/{core → v0/core}/_client/_api/data_modeling_loaders.py +6 -6
  116. cognite/neat/{core → v0/core}/_client/_api/neat_instances.py +5 -5
  117. cognite/neat/{core → v0/core}/_client/_api/schema.py +5 -5
  118. cognite/neat/{core → v0/core}/_client/_api/statistics.py +3 -3
  119. cognite/neat/{core → v0/core}/_client/_api_client.py +1 -1
  120. cognite/neat/v0/core/_client/data_classes/__init__.py +0 -0
  121. cognite/neat/{core → v0/core}/_client/data_classes/schema.py +4 -4
  122. cognite/neat/{core → v0/core}/_client/testing.py +1 -1
  123. cognite/neat/{core → v0/core}/_constants.py +5 -3
  124. cognite/neat/v0/core/_data_model/__init__.py +0 -0
  125. cognite/neat/{core → v0/core}/_data_model/_constants.py +3 -0
  126. cognite/neat/{core → v0/core}/_data_model/_shared.py +4 -4
  127. cognite/neat/{core → v0/core}/_data_model/analysis/_base.py +8 -8
  128. cognite/neat/{core → v0/core}/_data_model/exporters/__init__.py +1 -2
  129. cognite/neat/{core → v0/core}/_data_model/exporters/_base.py +7 -7
  130. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2dms.py +9 -9
  131. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2excel.py +12 -12
  132. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2instance_template.py +4 -4
  133. cognite/neat/{core/_data_model/exporters/_data_model2ontology.py → v0/core/_data_model/exporters/_data_model2semantic_model.py} +126 -116
  134. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2yaml.py +1 -1
  135. cognite/neat/{core → v0/core}/_data_model/importers/_base.py +5 -5
  136. cognite/neat/{core → v0/core}/_data_model/importers/_base_file_reader.py +2 -2
  137. cognite/neat/{core → v0/core}/_data_model/importers/_dict2data_model.py +5 -5
  138. cognite/neat/{core → v0/core}/_data_model/importers/_dms2data_model.py +16 -15
  139. cognite/neat/{core → v0/core}/_data_model/importers/_graph2data_model.py +12 -12
  140. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_base.py +12 -12
  141. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_inference2rdata_model.py +14 -14
  142. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_owl2data_model.py +41 -21
  143. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_shared.py +9 -9
  144. cognite/neat/{core → v0/core}/_data_model/importers/_spreadsheet2data_model.py +92 -12
  145. cognite/neat/{core → v0/core}/_data_model/models/__init__.py +3 -3
  146. cognite/neat/{core → v0/core}/_data_model/models/_base_verified.py +5 -5
  147. cognite/neat/{core → v0/core}/_data_model/models/_import_contexts.py +1 -1
  148. cognite/neat/{core → v0/core}/_data_model/models/_types.py +5 -5
  149. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_unverified.py +5 -5
  150. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_validation.py +12 -12
  151. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_verified.py +9 -9
  152. cognite/neat/{core → v0/core}/_data_model/models/data_types.py +4 -4
  153. cognite/neat/{core → v0/core}/_data_model/models/entities/__init__.py +2 -0
  154. cognite/neat/{core → v0/core}/_data_model/models/entities/_loaders.py +2 -2
  155. cognite/neat/{core → v0/core}/_data_model/models/entities/_multi_value.py +2 -2
  156. cognite/neat/{core → v0/core}/_data_model/models/entities/_restrictions.py +6 -6
  157. cognite/neat/{core → v0/core}/_data_model/models/entities/_single_value.py +17 -3
  158. cognite/neat/{core → v0/core}/_data_model/models/entities/_types.py +10 -0
  159. cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.py +5 -5
  160. cognite/neat/{core → v0/core}/_data_model/models/physical/__init__.py +1 -1
  161. cognite/neat/{core → v0/core}/_data_model/models/physical/_exporter.py +24 -19
  162. cognite/neat/{core → v0/core}/_data_model/models/physical/_unverified.py +69 -20
  163. cognite/neat/{core → v0/core}/_data_model/models/physical/_validation.py +24 -20
  164. cognite/neat/{core → v0/core}/_data_model/models/physical/_verified.py +95 -24
  165. cognite/neat/{core → v0/core}/_data_model/transformers/_base.py +4 -4
  166. cognite/neat/{core → v0/core}/_data_model/transformers/_converters.py +35 -28
  167. cognite/neat/{core → v0/core}/_data_model/transformers/_mapping.py +7 -7
  168. cognite/neat/{core → v0/core}/_data_model/transformers/_union_conceptual.py +5 -5
  169. cognite/neat/{core → v0/core}/_data_model/transformers/_verification.py +7 -7
  170. cognite/neat/v0/core/_instances/__init__.py +0 -0
  171. cognite/neat/{core → v0/core}/_instances/_tracking/base.py +1 -1
  172. cognite/neat/{core → v0/core}/_instances/_tracking/log.py +1 -1
  173. cognite/neat/{core → v0/core}/_instances/extractors/__init__.py +1 -1
  174. cognite/neat/{core → v0/core}/_instances/extractors/_base.py +6 -6
  175. cognite/neat/v0/core/_instances/extractors/_classic_cdf/__init__.py +0 -0
  176. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_base.py +7 -7
  177. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_classic.py +12 -12
  178. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_relationships.py +3 -3
  179. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_sequences.py +2 -2
  180. cognite/neat/{core → v0/core}/_instances/extractors/_dict.py +6 -3
  181. cognite/neat/{core → v0/core}/_instances/extractors/_dms.py +6 -6
  182. cognite/neat/{core → v0/core}/_instances/extractors/_dms_graph.py +11 -11
  183. cognite/neat/{core → v0/core}/_instances/extractors/_mock_graph_generator.py +10 -10
  184. cognite/neat/{core → v0/core}/_instances/extractors/_raw.py +3 -3
  185. cognite/neat/{core → v0/core}/_instances/extractors/_rdf_file.py +7 -7
  186. cognite/neat/{core → v0/core}/_instances/loaders/_base.py +5 -5
  187. cognite/neat/{core → v0/core}/_instances/loaders/_rdf2dms.py +17 -17
  188. cognite/neat/{core → v0/core}/_instances/loaders/_rdf_to_instance_space.py +11 -11
  189. cognite/neat/{core → v0/core}/_instances/queries/_select.py +29 -3
  190. cognite/neat/{core → v0/core}/_instances/queries/_update.py +1 -1
  191. cognite/neat/{core → v0/core}/_instances/transformers/_base.py +4 -4
  192. cognite/neat/{core → v0/core}/_instances/transformers/_classic_cdf.py +6 -6
  193. cognite/neat/{core → v0/core}/_instances/transformers/_prune_graph.py +4 -4
  194. cognite/neat/{core → v0/core}/_instances/transformers/_rdfpath.py +1 -1
  195. cognite/neat/{core → v0/core}/_instances/transformers/_value_type.py +4 -4
  196. cognite/neat/{core → v0/core}/_issues/_base.py +5 -5
  197. cognite/neat/{core → v0/core}/_issues/_contextmanagers.py +1 -1
  198. cognite/neat/{core → v0/core}/_issues/_factory.py +3 -3
  199. cognite/neat/{core → v0/core}/_issues/errors/__init__.py +1 -1
  200. cognite/neat/{core → v0/core}/_issues/errors/_external.py +1 -1
  201. cognite/neat/{core → v0/core}/_issues/errors/_general.py +1 -1
  202. cognite/neat/{core → v0/core}/_issues/errors/_properties.py +1 -1
  203. cognite/neat/{core → v0/core}/_issues/errors/_resources.py +2 -2
  204. cognite/neat/{core → v0/core}/_issues/errors/_wrapper.py +2 -2
  205. cognite/neat/{core → v0/core}/_issues/warnings/__init__.py +1 -1
  206. cognite/neat/{core → v0/core}/_issues/warnings/_external.py +1 -1
  207. cognite/neat/{core → v0/core}/_issues/warnings/_general.py +1 -1
  208. cognite/neat/{core → v0/core}/_issues/warnings/_models.py +2 -2
  209. cognite/neat/{core → v0/core}/_issues/warnings/_properties.py +2 -2
  210. cognite/neat/{core → v0/core}/_issues/warnings/_resources.py +1 -1
  211. cognite/neat/{core → v0/core}/_issues/warnings/user_modeling.py +1 -1
  212. cognite/neat/{core → v0/core}/_store/_data_model.py +12 -12
  213. cognite/neat/{core → v0/core}/_store/_instance.py +43 -10
  214. cognite/neat/{core → v0/core}/_store/_provenance.py +3 -3
  215. cognite/neat/{core → v0/core}/_store/exceptions.py +4 -4
  216. cognite/neat/v0/core/_utils/__init__.py +0 -0
  217. cognite/neat/{core → v0/core}/_utils/auth.py +1 -1
  218. cognite/neat/{core → v0/core}/_utils/auxiliary.py +1 -1
  219. cognite/neat/{core → v0/core}/_utils/collection_.py +2 -2
  220. cognite/neat/{core → v0/core}/_utils/graph_transformations_report.py +1 -1
  221. cognite/neat/{core → v0/core}/_utils/rdf_.py +1 -1
  222. cognite/neat/{core → v0/core}/_utils/reader/_base.py +1 -1
  223. cognite/neat/{core → v0/core}/_utils/spreadsheet.py +18 -4
  224. cognite/neat/{core → v0/core}/_utils/text.py +1 -1
  225. cognite/neat/{core → v0/core}/_utils/upload.py +3 -3
  226. cognite/neat/v0/plugins/__init__.py +4 -0
  227. cognite/neat/v0/plugins/_base.py +9 -0
  228. cognite/neat/v0/plugins/_data_model.py +48 -0
  229. cognite/neat/{plugins → v0/plugins}/_issues.py +1 -1
  230. cognite/neat/{plugins → v0/plugins}/_manager.py +7 -16
  231. cognite/neat/{session → v0/session}/_base.py +12 -10
  232. cognite/neat/{session → v0/session}/_collector.py +1 -1
  233. cognite/neat/v0/session/_diff.py +51 -0
  234. cognite/neat/{session → v0/session}/_drop.py +3 -3
  235. cognite/neat/{session → v0/session}/_explore.py +2 -2
  236. cognite/neat/{session → v0/session}/_fix.py +2 -2
  237. cognite/neat/{session → v0/session}/_inspect.py +3 -3
  238. cognite/neat/{session → v0/session}/_mapping.py +3 -3
  239. cognite/neat/{session → v0/session}/_plugin.py +4 -5
  240. cognite/neat/{session → v0/session}/_prepare.py +8 -8
  241. cognite/neat/{session → v0/session}/_read.py +33 -20
  242. cognite/neat/{session → v0/session}/_set.py +8 -8
  243. cognite/neat/{session → v0/session}/_show.py +5 -5
  244. cognite/neat/{session → v0/session}/_state.py +10 -10
  245. cognite/neat/{session → v0/session}/_subset.py +4 -4
  246. cognite/neat/{session → v0/session}/_template.py +11 -11
  247. cognite/neat/{session → v0/session}/_to.py +12 -12
  248. cognite/neat/{session → v0/session}/_wizard.py +1 -1
  249. cognite/neat/{session → v0/session}/engine/_load.py +1 -1
  250. cognite/neat/{session → v0/session}/exceptions.py +5 -5
  251. cognite/neat/v1.py +3 -0
  252. {cognite_neat-0.123.32.dist-info → cognite_neat-0.127.30.dist-info}/METADATA +7 -6
  253. cognite_neat-0.127.30.dist-info/RECORD +319 -0
  254. {cognite_neat-0.123.32.dist-info → cognite_neat-0.127.30.dist-info}/WHEEL +1 -1
  255. cognite/neat/data_model/models/entities/__init__.py +0 -9
  256. cognite/neat/plugins/__init__.py +0 -3
  257. cognite/neat/plugins/data_model/importers/__init__.py +0 -5
  258. cognite/neat/plugins/data_model/importers/_base.py +0 -28
  259. cognite_neat-0.123.32.dist-info/RECORD +0 -209
  260. /cognite/neat/{core → _data_model/deployer}/__init__.py +0 -0
  261. /cognite/neat/{core/_client/_api → _data_model/exporters/_table_exporter}/__init__.py +0 -0
  262. /cognite/neat/{core/_client/data_classes → _data_model/importers/_table_importer}/__init__.py +0 -0
  263. /cognite/neat/{core/_data_model → _data_model/models/conceptual}/__init__.py +0 -0
  264. /cognite/neat/{core/_instances → _data_model/validation}/__init__.py +0 -0
  265. /cognite/neat/{core/_instances/extractors/_classic_cdf → _session/_html}/__init__.py +0 -0
  266. /cognite/neat/{core/_utils → _session/_usage_analytics}/__init__.py +0 -0
  267. /cognite/neat/{data_model → v0}/__init__.py +0 -0
  268. /cognite/neat/{plugins/data_model → v0/core}/__init__.py +0 -0
  269. /cognite/neat/{core → v0/core}/_client/__init__.py +0 -0
  270. /cognite/neat/{core → v0/core}/_client/data_classes/data_modeling.py +0 -0
  271. /cognite/neat/{core → v0/core}/_client/data_classes/neat_sequence.py +0 -0
  272. /cognite/neat/{core → v0/core}/_client/data_classes/statistics.py +0 -0
  273. /cognite/neat/{core → v0/core}/_config.py +0 -0
  274. /cognite/neat/{core → v0/core}/_data_model/analysis/__init__.py +0 -0
  275. /cognite/neat/{core → v0/core}/_data_model/catalog/__init__.py +0 -0
  276. /cognite/neat/{core → v0/core}/_data_model/catalog/classic_model.xlsx +0 -0
  277. /cognite/neat/{core → v0/core}/_data_model/catalog/conceptual-imf-data-model.xlsx +0 -0
  278. /cognite/neat/{core → v0/core}/_data_model/catalog/hello_world_pump.xlsx +0 -0
  279. /cognite/neat/{core → v0/core}/_data_model/importers/__init__.py +0 -0
  280. /cognite/neat/{core → v0/core}/_data_model/importers/_rdf/__init__.py +0 -0
  281. /cognite/neat/{core → v0/core}/_data_model/models/_base_unverified.py +0 -0
  282. /cognite/neat/{core → v0/core}/_data_model/models/conceptual/__init__.py +0 -0
  283. /cognite/neat/{core → v0/core}/_data_model/models/entities/_constants.py +0 -0
  284. /cognite/neat/{core → v0/core}/_data_model/models/entities/_wrapped.py +0 -0
  285. /cognite/neat/{core → v0/core}/_data_model/models/mapping/__init__.py +0 -0
  286. /cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.yaml +0 -0
  287. /cognite/neat/{core → v0/core}/_data_model/transformers/__init__.py +0 -0
  288. /cognite/neat/{core → v0/core}/_instances/_shared.py +0 -0
  289. /cognite/neat/{core → v0/core}/_instances/_tracking/__init__.py +0 -0
  290. /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -0
  291. /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44.xml +0 -0
  292. /cognite/neat/{core → v0/core}/_instances/examples/__init__.py +0 -0
  293. /cognite/neat/{core → v0/core}/_instances/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  294. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_assets.py +0 -0
  295. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_data_sets.py +0 -0
  296. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_events.py +0 -0
  297. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_files.py +0 -0
  298. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_labels.py +0 -0
  299. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_timeseries.py +0 -0
  300. /cognite/neat/{core → v0/core}/_instances/loaders/__init__.py +0 -0
  301. /cognite/neat/{core → v0/core}/_instances/queries/__init__.py +0 -0
  302. /cognite/neat/{core → v0/core}/_instances/queries/_base.py +0 -0
  303. /cognite/neat/{core → v0/core}/_instances/queries/_queries.py +0 -0
  304. /cognite/neat/{core → v0/core}/_instances/transformers/__init__.py +0 -0
  305. /cognite/neat/{core → v0/core}/_issues/__init__.py +0 -0
  306. /cognite/neat/{core → v0/core}/_issues/formatters.py +0 -0
  307. /cognite/neat/{core → v0/core}/_shared.py +0 -0
  308. /cognite/neat/{core → v0/core}/_store/__init__.py +0 -0
  309. /cognite/neat/{core → v0/core}/_utils/io_.py +0 -0
  310. /cognite/neat/{core → v0/core}/_utils/reader/__init__.py +0 -0
  311. /cognite/neat/{core → v0/core}/_utils/tarjan.py +0 -0
  312. /cognite/neat/{core → v0/core}/_utils/time_.py +0 -0
  313. /cognite/neat/{core → v0/core}/_utils/xml_.py +0 -0
  314. /cognite/neat/{session → v0/session}/__init__.py +0 -0
  315. /cognite/neat/{session → v0/session}/_experimental.py +0 -0
  316. /cognite/neat/{session → v0/session}/_state/README.md +0 -0
  317. /cognite/neat/{session → v0/session}/engine/__init__.py +0 -0
  318. /cognite/neat/{session → v0/session}/engine/_import.py +0 -0
  319. /cognite/neat/{session → v0/session}/engine/_interface.py +0 -0
  320. {cognite_neat-0.123.32.dist-info → cognite_neat-0.127.30.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,421 @@
1
+ import json
2
+ from collections import defaultdict
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, Literal
5
+
6
+ from cognite.neat._data_model._constants import DEFAULT_MAX_LIST_SIZE, DEFAULT_MAX_LIST_SIZE_DIRECT_RELATIONS
7
+ from cognite.neat._data_model.importers._table_importer.data_classes import (
8
+ CREATOR_KEY,
9
+ CREATOR_MARKER,
10
+ DMSContainer,
11
+ DMSEnum,
12
+ DMSNode,
13
+ DMSProperty,
14
+ DMSView,
15
+ MetadataValue,
16
+ TableDMS,
17
+ )
18
+ from cognite.neat._data_model.models.dms import (
19
+ ContainerPropertyDefinition,
20
+ ContainerReference,
21
+ ContainerRequest,
22
+ DataModelRequest,
23
+ DataType,
24
+ DirectNodeRelation,
25
+ EnumProperty,
26
+ ListablePropertyTypeDefinition,
27
+ NodeReference,
28
+ RequestSchema,
29
+ RequiresConstraintDefinition,
30
+ UniquenessConstraintDefinition,
31
+ ViewCorePropertyRequest,
32
+ ViewReference,
33
+ ViewRequest,
34
+ ViewRequestProperty,
35
+ )
36
+ from cognite.neat._data_model.models.dms._view_property import (
37
+ EdgeProperty,
38
+ MultiEdgeProperty,
39
+ MultiReverseDirectRelationPropertyRequest,
40
+ ReverseDirectRelationProperty,
41
+ SingleEdgeProperty,
42
+ SingleReverseDirectRelationPropertyRequest,
43
+ )
44
+ from cognite.neat._data_model.models.entities import ParsedEntity
45
+
46
+
47
+ @dataclass
48
+ class ViewProperties:
49
+ properties: list[DMSProperty] = field(default_factory=list)
50
+ nodes: list[DMSNode] = field(default_factory=list)
51
+
52
+
53
+ @dataclass
54
+ class ContainerProperties:
55
+ properties_by_id: dict[tuple[ContainerReference, str], dict] = field(default_factory=dict)
56
+ enum_collections: list[DMSEnum] = field(default_factory=list)
57
+
58
+
59
+ class DMSTableWriter:
60
+ def __init__(self, default_space: str, default_version: str, skip_properties_in_other_spaces: bool) -> None:
61
+ self.default_space = default_space
62
+ self.default_version = default_version
63
+ self.skip_properties_in_other_spaces = skip_properties_in_other_spaces
64
+
65
+ ## Main Entry Point ###
66
+ def write_tables(self, schema: RequestSchema) -> TableDMS:
67
+ metadata = self.write_metadata(schema.data_model)
68
+ container_properties = self.write_container_properties(schema.containers)
69
+ view_properties = self.write_view_properties(schema.views, container_properties)
70
+ views = self.write_views(schema.views)
71
+ containers = self.write_containers(schema.containers)
72
+
73
+ return TableDMS(
74
+ metadata=metadata,
75
+ properties=view_properties.properties,
76
+ views=views,
77
+ containers=containers,
78
+ enum=container_properties.enum_collections,
79
+ nodes=view_properties.nodes,
80
+ )
81
+
82
+ ### Metadata Sheet ###
83
+ @classmethod
84
+ def write_metadata(cls, data_model: DataModelRequest) -> list[MetadataValue]:
85
+ metadata = [
86
+ MetadataValue(key=key, value=value)
87
+ for key, value in data_model.model_dump(
88
+ mode="json", by_alias=True, exclude_none=True, exclude={"views", "description"}
89
+ ).items()
90
+ ]
91
+ if data_model.description:
92
+ description, creator = cls._serialize_description(data_model.description)
93
+ if description:
94
+ metadata.append(MetadataValue(key="description", value=description))
95
+ if creator:
96
+ metadata.append(MetadataValue(key=CREATOR_KEY, value=creator))
97
+ return metadata
98
+
99
+ @staticmethod
100
+ def _serialize_description(description: str | None) -> tuple[str | None, str | None]:
101
+ """DataModelRequest does not have a 'creator' field, this is a special addition that the Neat tables
102
+ format supports (and recommends using). If the data model was created using Neat, the suffix of the
103
+ description will be Creator: <creator>. This function extracts that information."""
104
+ if description is None:
105
+ return None, None
106
+ if CREATOR_MARKER not in description:
107
+ return description, None
108
+
109
+ description, creator = description.rsplit(CREATOR_MARKER, 1)
110
+ return description.rstrip(), creator.strip()
111
+
112
+ ### Container Properties Sheet ###
113
+
114
+ def write_containers(self, containers: list[ContainerRequest]) -> list[DMSContainer]:
115
+ return [
116
+ DMSContainer(
117
+ container=self._create_container_entity(container),
118
+ name=container.name,
119
+ description=container.description,
120
+ constraint=self._create_container_constraints(container),
121
+ used_for=container.used_for,
122
+ )
123
+ for container in containers
124
+ ]
125
+
126
+ def write_container_properties(self, containers: list[ContainerRequest]) -> ContainerProperties:
127
+ indices_by_container_property = self._write_container_indices(containers)
128
+ constraints_by_container_property = self._write_container_property_constraints(containers)
129
+
130
+ output = ContainerProperties()
131
+ for container in containers:
132
+ for prop_id, prop in container.properties.items():
133
+ container_property = self._write_container_property(
134
+ container.as_reference(),
135
+ prop_id,
136
+ prop,
137
+ indices_by_container_property,
138
+ constraints_by_container_property,
139
+ )
140
+ output.properties_by_id[(container.as_reference(), prop_id)] = container_property
141
+ if isinstance(prop.type, EnumProperty):
142
+ output.enum_collections.extend(
143
+ self._write_enum_collection(container.as_reference(), prop_id, prop.type)
144
+ )
145
+ return output
146
+
147
+ def _write_container_property(
148
+ self,
149
+ container_ref: ContainerReference,
150
+ prop_id: str,
151
+ prop: ContainerPropertyDefinition,
152
+ indices_by_container_property: dict[tuple[ContainerReference, str], list[ParsedEntity]],
153
+ constraints_by_container_property: dict[tuple[ContainerReference, str], list[ParsedEntity]],
154
+ ) -> dict[str, Any]:
155
+ return dict(
156
+ connection=self._write_container_property_connection(prop.type),
157
+ value_type=self._write_container_property_value_type(prop, prop_id, container_ref),
158
+ min_count=0 if prop.nullable else 1,
159
+ max_count=self._write_container_property_max_count(prop.type),
160
+ immutable=prop.immutable,
161
+ default=json.dumps(prop.default_value) if isinstance(prop.default_value, dict) else prop.default_value,
162
+ auto_increment=prop.auto_increment,
163
+ container=self._create_container_entity(container_ref),
164
+ container_property=prop_id,
165
+ container_property_name=prop.name,
166
+ container_property_description=prop.description,
167
+ index=indices_by_container_property.get((container_ref, prop_id)),
168
+ constraint=constraints_by_container_property.get((container_ref, prop_id)),
169
+ )
170
+
171
+ def _write_container_property_connection(self, dtype: DataType) -> ParsedEntity | None:
172
+ if not isinstance(dtype, DirectNodeRelation):
173
+ return None
174
+ properties: dict[str, str] = {}
175
+ if dtype.container is not None:
176
+ properties["container"] = str(self._create_container_entity(dtype.container))
177
+ return ParsedEntity("", "direct", properties=properties)
178
+
179
+ def _write_container_property_value_type(
180
+ self, prop: ContainerPropertyDefinition, prop_id: str, container_ref: ContainerReference
181
+ ) -> ParsedEntity:
182
+ if isinstance(prop.type, DirectNodeRelation):
183
+ # Will be overwritten if the view property has source set.
184
+ return ParsedEntity("", "#N/A", properties={})
185
+ elif isinstance(prop.type, EnumProperty):
186
+ enum_properties = {"collection": self._enum_collection_name(container_ref, prop_id)}
187
+ if prop.type.unknown_value is not None:
188
+ enum_properties["unknownValue"] = prop.type.unknown_value
189
+ return ParsedEntity("", "enum", properties=enum_properties)
190
+ elif isinstance(prop.type, ListablePropertyTypeDefinition):
191
+ # List and maxListSize are included in the maxCount of the property, so we exclude them here.
192
+ entity_properties = prop.type.model_dump(
193
+ mode="json", by_alias=True, exclude={"list", "maxListSize", "type"}, exclude_none=True
194
+ )
195
+ return ParsedEntity("", prop.type.type, properties=entity_properties)
196
+ else:
197
+ # Should not happen as all types are either ListablePropertyTypeDefinition or EnumProperty.
198
+ return ParsedEntity("", prop.type.type, properties={})
199
+
200
+ @staticmethod
201
+ def _write_container_property_max_count(dtype: DataType) -> int | None:
202
+ if isinstance(dtype, ListablePropertyTypeDefinition) and dtype.list:
203
+ if dtype.max_list_size is not None:
204
+ return dtype.max_list_size
205
+ elif isinstance(dtype, DirectNodeRelation):
206
+ return DEFAULT_MAX_LIST_SIZE_DIRECT_RELATIONS
207
+ else:
208
+ return DEFAULT_MAX_LIST_SIZE
209
+ return 1
210
+
211
+ @staticmethod
212
+ def _write_container_indices(
213
+ containers: list[ContainerRequest],
214
+ ) -> dict[tuple[ContainerReference, str], list[ParsedEntity]]:
215
+ """Writes container indices and groups them by (container_reference, property_id)."""
216
+ indices_by_id: dict[tuple[ContainerReference, str], list[ParsedEntity]] = defaultdict(list)
217
+ for container in containers:
218
+ if not container.indexes:
219
+ continue
220
+ for index_id, index in container.indexes.items():
221
+ for order, prop_id in enumerate(index.properties, 1):
222
+ entity_properties = index.model_dump(
223
+ mode="json", by_alias=True, exclude={"index_type", "properties"}, exclude_none=True
224
+ )
225
+ if len(index.properties) > 1:
226
+ entity_properties["order"] = str(order)
227
+ entity = ParsedEntity(index.index_type, index_id, properties=entity_properties)
228
+ indices_by_id[(container.as_reference(), prop_id)].append(entity)
229
+ return indices_by_id
230
+
231
+ @staticmethod
232
+ def _write_container_property_constraints(
233
+ containers: list[ContainerRequest],
234
+ ) -> dict[tuple[ContainerReference, str], list[ParsedEntity]]:
235
+ """Writes container constraints and groups them by (container_reference, property_id).
236
+
237
+ Note this only includes uniqueness constraints, the require constraints is handled
238
+ in the writing of the container itself.
239
+ """
240
+ constraints_by_id: dict[tuple[ContainerReference, str], list[ParsedEntity]] = defaultdict(list)
241
+ for container in containers:
242
+ if not container.constraints:
243
+ continue
244
+ for constraint_id, constraint in container.constraints.items():
245
+ if not isinstance(constraint, UniquenessConstraintDefinition):
246
+ continue
247
+ for order, prop_id in enumerate(constraint.properties, 1):
248
+ entity_properties = constraint.model_dump(
249
+ mode="json", by_alias=True, exclude={"constraint_type", "properties"}, exclude_none=True
250
+ )
251
+ if len(constraint.properties) > 1:
252
+ entity_properties["order"] = str(order)
253
+ entity = ParsedEntity(constraint.constraint_type, constraint_id, properties=entity_properties)
254
+ constraints_by_id[(container.as_reference(), prop_id)].append(entity)
255
+ return constraints_by_id
256
+
257
+ def _create_container_constraints(self, container: ContainerRequest) -> list[ParsedEntity] | None:
258
+ if not container.constraints:
259
+ return None
260
+ output: list[ParsedEntity] = []
261
+ for constraint_id, constraint in container.constraints.items():
262
+ if not isinstance(constraint, RequiresConstraintDefinition):
263
+ continue
264
+ entity_properties = {"require": str(self._create_container_entity(constraint.require))}
265
+ output.append(
266
+ ParsedEntity(prefix=constraint.constraint_type, suffix=constraint_id, properties=entity_properties)
267
+ )
268
+ return output or None
269
+
270
+ ### Enum Sheet ###
271
+ @staticmethod
272
+ def _enum_collection_name(container_ref: ContainerReference, prop_id: str) -> str:
273
+ return f"{container_ref.external_id}.{prop_id}"
274
+
275
+ def _write_enum_collection(
276
+ self, container_ref: ContainerReference, prop_id: str, enum: EnumProperty
277
+ ) -> list[DMSEnum]:
278
+ output: list[DMSEnum] = []
279
+ name = self._enum_collection_name(container_ref, prop_id)
280
+ for value_id, value in enum.values.items():
281
+ output.append(
282
+ DMSEnum(
283
+ collection=name,
284
+ value=value_id,
285
+ name=value.name,
286
+ description=value.description,
287
+ )
288
+ )
289
+ return output
290
+
291
+ ### View Sheet ###
292
+ def write_views(self, views: list[ViewRequest]) -> list[DMSView]:
293
+ return [
294
+ DMSView(
295
+ view=self._create_view_entity(view),
296
+ name=view.name,
297
+ description=view.description,
298
+ implements=[self._create_view_entity(parent) for parent in view.implements]
299
+ if view.implements
300
+ else None,
301
+ filter=json.dumps(view.filter) if view.filter else None,
302
+ )
303
+ for view in views
304
+ ]
305
+
306
+ def write_view_properties(self, views: list[ViewRequest], container: ContainerProperties) -> ViewProperties:
307
+ output = ViewProperties()
308
+ for view in views:
309
+ if not view.properties:
310
+ continue
311
+ if self.skip_properties_in_other_spaces and view.space != self.default_space:
312
+ continue
313
+ for prop_id, prop in view.properties.items():
314
+ output.properties.append(self._write_view_property(view, prop_id, prop, container))
315
+ if isinstance(prop, EdgeProperty):
316
+ output.nodes.append(self._write_node(prop))
317
+ return output
318
+
319
+ def _write_view_property(
320
+ self, view: ViewRequest, prop_id: str, prop: ViewRequestProperty, container: ContainerProperties
321
+ ) -> DMSProperty:
322
+ container_properties: dict[str, Any] = {}
323
+ if isinstance(prop, ViewCorePropertyRequest):
324
+ identifier = (prop.container, prop.container_property_identifier)
325
+ if identifier in container.properties_by_id:
326
+ container_properties = container.properties_by_id[identifier]
327
+ view_properties: dict[str, Any] = dict(
328
+ view=self._create_view_entity(view), view_property=prop_id, name=prop.name, description=prop.description
329
+ )
330
+ if connection := self._write_view_property_connection(prop):
331
+ view_properties["connection"] = connection
332
+ if view_value_type := self._write_view_property_value_type(prop):
333
+ view_properties["value_type"] = view_value_type
334
+ view_min_count = self._write_view_property_min_count(prop)
335
+ if view_min_count is not None:
336
+ view_properties["min_count"] = view_min_count
337
+ view_max_count = self._write_view_property_max_count(prop)
338
+ if view_max_count != "container":
339
+ view_properties["max_count"] = view_max_count
340
+
341
+ # Overwrite container properties with view properties where relevant.
342
+ args = container_properties | view_properties
343
+ return DMSProperty(**args)
344
+
345
+ def _write_view_property_connection(self, prop: ViewRequestProperty) -> ParsedEntity | None:
346
+ if isinstance(prop, ViewCorePropertyRequest):
347
+ # Use the container definition for connection
348
+ return None
349
+ elif isinstance(prop, EdgeProperty):
350
+ edge_properties: dict[str, str] = {}
351
+ if prop.direction != "outwards":
352
+ edge_properties["direction"] = prop.direction
353
+ if prop.edge_source is not None:
354
+ edge_properties["edgeSource"] = str(self._create_view_entity(prop.edge_source))
355
+ edge_properties["type"] = str(self._create_node_entity(prop.type))
356
+ return ParsedEntity("", "edge", properties=edge_properties)
357
+ elif isinstance(prop, ReverseDirectRelationProperty):
358
+ return ParsedEntity("", "reverse", properties={"property": prop.through.identifier})
359
+ else:
360
+ raise ValueError(f"Unknown view property type: {type(prop)}")
361
+
362
+ def _write_view_property_value_type(self, prop: ViewRequestProperty) -> ParsedEntity | None:
363
+ if isinstance(prop, ViewCorePropertyRequest):
364
+ if prop.source:
365
+ return self._create_view_entity(prop.source)
366
+ else:
367
+ # Use the container definition for value type
368
+ return None
369
+ elif isinstance(prop, ReverseDirectRelationProperty | EdgeProperty):
370
+ return self._create_view_entity(prop.source)
371
+ else:
372
+ raise ValueError(f"Unknown view property type: {type(prop)}")
373
+
374
+ @staticmethod
375
+ def _write_view_property_min_count(prop: ViewRequestProperty) -> int | None:
376
+ if isinstance(prop, ViewCorePropertyRequest):
377
+ # Use the container definition for min count
378
+ return None
379
+ # Edges and reverse relations cannot be required.
380
+ return 0
381
+
382
+ @staticmethod
383
+ def _write_view_property_max_count(prop: ViewRequestProperty) -> int | None | Literal["container"]:
384
+ if isinstance(prop, ViewCorePropertyRequest):
385
+ # Use the container definition for max count
386
+ return "container"
387
+ elif isinstance(prop, SingleEdgeProperty | SingleReverseDirectRelationPropertyRequest):
388
+ return 1
389
+ elif isinstance(prop, MultiEdgeProperty | MultiReverseDirectRelationPropertyRequest):
390
+ return None
391
+ else:
392
+ raise ValueError(f"Unknown view property type: {type(prop)}")
393
+
394
+ ### Node Sheet ###
395
+
396
+ def _write_node(self, prop: EdgeProperty) -> DMSNode:
397
+ return DMSNode(node=self._create_node_entity(prop.type))
398
+
399
+ ## Entity Helpers ###
400
+
401
+ def _create_view_entity(self, view: ViewRequest | ViewReference) -> ParsedEntity:
402
+ prefix = view.space
403
+ properties = {"version": view.version}
404
+ if view.space == self.default_space:
405
+ prefix = ""
406
+ if view.version == self.default_version:
407
+ # Only use default version if space is also default.
408
+ properties = {}
409
+ return ParsedEntity(prefix=prefix, suffix=view.external_id, properties=properties)
410
+
411
+ def _create_container_entity(self, container: ContainerRequest | ContainerReference) -> ParsedEntity:
412
+ prefix = container.space
413
+ if container.space == self.default_space:
414
+ prefix = ""
415
+ return ParsedEntity(prefix=prefix, suffix=container.external_id, properties={})
416
+
417
+ def _create_node_entity(self, node: NodeReference) -> ParsedEntity:
418
+ prefix = node.space
419
+ if node.space == self.default_space:
420
+ prefix = ""
421
+ return ParsedEntity(prefix=prefix, suffix=node.external_id, properties={})
@@ -0,0 +1,5 @@
1
+ from ._api_importer import DMSAPIImporter
2
+ from ._base import DMSImporter
3
+ from ._table_importer.importer import DMSTableImporter
4
+
5
+ __all__ = ["DMSAPIImporter", "DMSImporter", "DMSTableImporter"]
@@ -0,0 +1,166 @@
1
+ import difflib
2
+ from pathlib import Path
3
+ from typing import Any
4
+
5
+ import yaml
6
+ from pydantic import ValidationError
7
+
8
+ from cognite.neat._client import NeatClient
9
+ from cognite.neat._data_model.importers._base import DMSImporter
10
+ from cognite.neat._data_model.models.dms import (
11
+ DataModelReference,
12
+ RequestSchema,
13
+ SpaceReference,
14
+ )
15
+ from cognite.neat._exceptions import CDFAPIException, DataModelImportException, FileReadException
16
+ from cognite.neat._issues import ModelSyntaxError
17
+ from cognite.neat._utils.http_client import FailedRequestMessage
18
+ from cognite.neat._utils.text import humanize_collection
19
+ from cognite.neat._utils.validation import ValidationContext, humanize_validation_error
20
+
21
+
22
+ class DMSAPIImporter(DMSImporter):
23
+ """Imports DMS in the API format."""
24
+
25
+ ENCODING = "utf-8"
26
+
27
+ def __init__(self, schema: RequestSchema | dict[str, Any]) -> None:
28
+ self._schema = schema
29
+
30
+ def to_data_model(self) -> RequestSchema:
31
+ if isinstance(self._schema, RequestSchema):
32
+ return self._schema
33
+ try:
34
+ return RequestSchema.model_validate(self._schema)
35
+ except ValidationError as e:
36
+ context = ValidationContext()
37
+ errors = [
38
+ ModelSyntaxError(message=humanize_validation_error(error, context))
39
+ for error in e.errors(include_input=True, include_url=False)
40
+ ]
41
+ raise DataModelImportException(errors) from None
42
+
43
+ @classmethod
44
+ def from_cdf(cls, data_model: DataModelReference, client: NeatClient) -> "DMSAPIImporter":
45
+ """Create a DMSAPIImporter from a data model in CDF."""
46
+ data_models = client.data_models.retrieve([data_model])
47
+ if not data_models:
48
+ available_data_models = [
49
+ str(model.as_reference()) for model in client.data_models.list(limit=1000, include_global=True)
50
+ ]
51
+ close_matches = difflib.get_close_matches(str(data_model), available_data_models, n=1, cutoff=0.9)
52
+ suggestion_msg = ""
53
+ if close_matches:
54
+ suggestion_msg = f" Did you mean: {close_matches[0]!r}?"
55
+ raise CDFAPIException(
56
+ messages=[
57
+ FailedRequestMessage(message=f"Data model '{data_model!s}' not found in CDF.{suggestion_msg}")
58
+ ]
59
+ )
60
+ data_model = data_models[0]
61
+ views = client.views.retrieve(data_model.views or [])
62
+ if missing_views := set(data_model.views or []) - {view.as_reference() for view in views}:
63
+ raise CDFAPIException(
64
+ messages=[
65
+ FailedRequestMessage(
66
+ message=f"Views {humanize_collection(missing_views)} not found in CDF "
67
+ f"for data model {data_model}."
68
+ )
69
+ ]
70
+ )
71
+ container_ids = list({container for view in views for container in view.mapped_containers})
72
+ containers = client.containers.retrieve(container_ids)
73
+ if missing_containers := set(container_ids) - {container.as_reference() for container in containers}:
74
+ raise CDFAPIException(
75
+ messages=[
76
+ FailedRequestMessage(
77
+ message=f"Containers {humanize_collection(missing_containers)} not found in CDF "
78
+ f"for data model {data_model}."
79
+ )
80
+ ]
81
+ )
82
+ node_types = [nt for view in views for nt in view.node_types]
83
+ space_ids = list(
84
+ {data_model.space}
85
+ | {view.space for view in views}
86
+ | {container.space for container in containers}
87
+ | {nt.space for nt in node_types}
88
+ )
89
+ spaces = client.spaces.retrieve([SpaceReference(space=space_id) for space_id in space_ids])
90
+ if missing_spaces := set(space_ids) - {space.space for space in spaces}:
91
+ raise CDFAPIException(
92
+ messages=[
93
+ FailedRequestMessage(
94
+ message=f"Spaces {humanize_collection(missing_spaces)} not found in CDF "
95
+ f"for data model {data_model}."
96
+ )
97
+ ]
98
+ )
99
+ return DMSAPIImporter(
100
+ RequestSchema(
101
+ dataModel=data_model.as_request(),
102
+ views=[view.as_request() for view in views],
103
+ containers=[container.as_request() for container in containers],
104
+ nodeTypes=node_types,
105
+ spaces=[space.as_request() for space in spaces],
106
+ )
107
+ )
108
+
109
+ @classmethod
110
+ def from_yaml(cls, yaml_file: Path) -> "DMSAPIImporter":
111
+ """Create a DMSTableImporter from a YAML file."""
112
+ source = cls._display_name(yaml_file)
113
+ if yaml_file.suffix.lower() in {".yaml", ".yml", ".json"}:
114
+ return cls(yaml.safe_load(yaml_file.read_text(encoding=cls.ENCODING)))
115
+ elif yaml_file.is_dir():
116
+ return cls(cls._read_yaml_files(yaml_file))
117
+ raise FileReadException(source.as_posix(), f"Unsupported file type: {source.suffix}")
118
+
119
+ @classmethod
120
+ def from_json(cls, json_file: Path) -> "DMSAPIImporter":
121
+ """Create a DMSTableImporter from a JSON file."""
122
+ return cls.from_yaml(json_file)
123
+
124
+ @classmethod
125
+ def _display_name(cls, filepath: Path) -> Path:
126
+ """Get a display-friendly version of the file path."""
127
+ cwd = Path.cwd()
128
+ source = filepath
129
+ if filepath.is_relative_to(cwd):
130
+ source = filepath.relative_to(cwd)
131
+ return source
132
+
133
+ @classmethod
134
+ def _read_yaml_files(cls, directory: Path) -> dict[str, Any]:
135
+ """Read all YAML files in a directory and combine them into a single dictionary."""
136
+ schema_data: dict[str, Any] = {}
137
+ data_model: dict[str, Any] | None = None
138
+ for yaml_file in directory.rglob("**/*"):
139
+ if yaml_file.suffix.lower() not in {".yaml", ".yml", ".json"}:
140
+ continue
141
+ stem = yaml_file.stem.casefold()
142
+ if stem.endswith("datamodel") and data_model is not None:
143
+ raise FileReadException(
144
+ cls._display_name(directory).as_posix(),
145
+ "Multiple data model files found in directory.",
146
+ )
147
+ data = yaml.safe_load(yaml_file.read_text(encoding=cls.ENCODING))
148
+ list_data = data if isinstance(data, list) else [data]
149
+ if stem.endswith("datamodel"):
150
+ data_model = data
151
+ elif stem.endswith("container"):
152
+ schema_data.setdefault("containers", []).extend(list_data)
153
+ elif stem.endswith("view"):
154
+ schema_data.setdefault("views", []).extend(list_data)
155
+ elif stem.endswith("space"):
156
+ schema_data.setdefault("spaces", []).extend(list_data)
157
+ elif stem.endswith("node"):
158
+ schema_data.setdefault("nodeTypes", []).extend(list_data)
159
+ # Ignore other files
160
+ if data_model is None:
161
+ raise FileReadException(
162
+ cls._display_name(directory).as_posix(),
163
+ "No data model file found in directory.",
164
+ )
165
+ schema_data["dataModel"] = data_model
166
+ return schema_data
@@ -0,0 +1,16 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from cognite.neat._data_model.models.dms import RequestSchema
4
+
5
+
6
+ class DMSImporter(ABC):
7
+ """This is the base class for all DMS importers."""
8
+
9
+ @abstractmethod
10
+ def to_data_model(self) -> RequestSchema:
11
+ """Convert the imported data to a RequestSchema.
12
+
13
+ Returns:
14
+ RequestSchema: The data model as a RequestSchema.
15
+ """
16
+ raise NotImplementedError()