cognite-neat 0.123.2__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 (333) 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 +206 -0
  43. cognite/neat/_data_model/models/dms/_base.py +31 -0
  44. cognite/neat/_data_model/models/dms/_constants.py +48 -0
  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 +48 -0
  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/models/entities/_constants.py +22 -0
  62. cognite/neat/_data_model/models/entities/_data_types.py +144 -0
  63. cognite/neat/_data_model/models/entities/_identifiers.py +61 -0
  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/__init__.py +0 -0
  93. cognite/neat/_session/_usage_analytics/_collector.py +131 -0
  94. cognite/neat/_session/_usage_analytics/_constants.py +23 -0
  95. cognite/neat/_session/_usage_analytics/_storage.py +240 -0
  96. cognite/neat/_session/_wrappers.py +82 -0
  97. cognite/neat/_state_machine/__init__.py +10 -0
  98. cognite/neat/_state_machine/_base.py +37 -0
  99. cognite/neat/_state_machine/_states.py +52 -0
  100. cognite/neat/_store/__init__.py +3 -0
  101. cognite/neat/_store/_provenance.py +81 -0
  102. cognite/neat/_store/_store.py +156 -0
  103. cognite/neat/_utils/__init__.py +0 -0
  104. cognite/neat/_utils/_reader.py +194 -0
  105. cognite/neat/_utils/auxiliary.py +39 -0
  106. cognite/neat/_utils/collection.py +11 -0
  107. cognite/neat/_utils/http_client/__init__.py +39 -0
  108. cognite/neat/_utils/http_client/_client.py +245 -0
  109. cognite/neat/_utils/http_client/_config.py +19 -0
  110. cognite/neat/_utils/http_client/_data_classes.py +294 -0
  111. cognite/neat/_utils/http_client/_tracker.py +31 -0
  112. cognite/neat/_utils/text.py +71 -0
  113. cognite/neat/_utils/useful_types.py +37 -0
  114. cognite/neat/_utils/validation.py +154 -0
  115. cognite/neat/_version.py +1 -1
  116. cognite/neat/v0/__init__.py +0 -0
  117. cognite/neat/v0/core/__init__.py +0 -0
  118. cognite/neat/v0/core/_client/_api/__init__.py +0 -0
  119. cognite/neat/{core → v0/core}/_client/_api/data_modeling_loaders.py +86 -7
  120. cognite/neat/{core → v0/core}/_client/_api/neat_instances.py +5 -5
  121. cognite/neat/{core → v0/core}/_client/_api/schema.py +5 -5
  122. cognite/neat/{core → v0/core}/_client/_api/statistics.py +3 -3
  123. cognite/neat/{core → v0/core}/_client/_api_client.py +1 -1
  124. cognite/neat/v0/core/_client/data_classes/__init__.py +0 -0
  125. cognite/neat/{core → v0/core}/_client/data_classes/schema.py +4 -4
  126. cognite/neat/{core → v0/core}/_client/testing.py +1 -1
  127. cognite/neat/{core → v0/core}/_constants.py +10 -3
  128. cognite/neat/v0/core/_data_model/__init__.py +0 -0
  129. cognite/neat/{core → v0/core}/_data_model/_constants.py +9 -6
  130. cognite/neat/{core → v0/core}/_data_model/_shared.py +5 -5
  131. cognite/neat/{core → v0/core}/_data_model/analysis/_base.py +12 -8
  132. cognite/neat/{core → v0/core}/_data_model/exporters/__init__.py +1 -2
  133. cognite/neat/{core → v0/core}/_data_model/exporters/_base.py +7 -7
  134. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2dms.py +9 -9
  135. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2excel.py +13 -13
  136. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2instance_template.py +4 -4
  137. cognite/neat/{core/_data_model/exporters/_data_model2ontology.py → v0/core/_data_model/exporters/_data_model2semantic_model.py} +126 -133
  138. cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2yaml.py +1 -1
  139. cognite/neat/{core → v0/core}/_data_model/importers/__init__.py +4 -6
  140. cognite/neat/{core → v0/core}/_data_model/importers/_base.py +5 -5
  141. cognite/neat/{core → v0/core}/_data_model/importers/_base_file_reader.py +2 -2
  142. cognite/neat/{core → v0/core}/_data_model/importers/_dict2data_model.py +6 -6
  143. cognite/neat/{core → v0/core}/_data_model/importers/_dms2data_model.py +19 -16
  144. cognite/neat/v0/core/_data_model/importers/_graph2data_model.py +299 -0
  145. cognite/neat/v0/core/_data_model/importers/_rdf/__init__.py +4 -0
  146. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_base.py +13 -13
  147. cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_inference2rdata_model.py +14 -14
  148. cognite/neat/v0/core/_data_model/importers/_rdf/_owl2data_model.py +144 -0
  149. cognite/neat/v0/core/_data_model/importers/_rdf/_shared.py +255 -0
  150. cognite/neat/{core → v0/core}/_data_model/importers/_spreadsheet2data_model.py +94 -13
  151. cognite/neat/{core → v0/core}/_data_model/models/__init__.py +3 -3
  152. cognite/neat/{core → v0/core}/_data_model/models/_base_verified.py +5 -5
  153. cognite/neat/v0/core/_data_model/models/_import_contexts.py +82 -0
  154. cognite/neat/{core → v0/core}/_data_model/models/_types.py +5 -5
  155. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_unverified.py +18 -12
  156. cognite/neat/v0/core/_data_model/models/conceptual/_validation.py +308 -0
  157. cognite/neat/{core → v0/core}/_data_model/models/conceptual/_verified.py +13 -11
  158. cognite/neat/{core → v0/core}/_data_model/models/data_types.py +14 -4
  159. cognite/neat/{core → v0/core}/_data_model/models/entities/__init__.py +6 -0
  160. cognite/neat/v0/core/_data_model/models/entities/_loaders.py +155 -0
  161. cognite/neat/{core → v0/core}/_data_model/models/entities/_multi_value.py +2 -2
  162. cognite/neat/v0/core/_data_model/models/entities/_restrictions.py +230 -0
  163. cognite/neat/{core → v0/core}/_data_model/models/entities/_single_value.py +121 -16
  164. cognite/neat/{core → v0/core}/_data_model/models/entities/_types.py +10 -0
  165. cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.py +5 -5
  166. cognite/neat/{core → v0/core}/_data_model/models/physical/__init__.py +1 -1
  167. cognite/neat/{core → v0/core}/_data_model/models/physical/_exporter.py +28 -21
  168. cognite/neat/{core → v0/core}/_data_model/models/physical/_unverified.py +141 -38
  169. cognite/neat/{core → v0/core}/_data_model/models/physical/_validation.py +190 -24
  170. cognite/neat/{core → v0/core}/_data_model/models/physical/_verified.py +135 -15
  171. cognite/neat/{core → v0/core}/_data_model/transformers/__init__.py +2 -0
  172. cognite/neat/{core → v0/core}/_data_model/transformers/_base.py +4 -4
  173. cognite/neat/{core → v0/core}/_data_model/transformers/_converters.py +39 -32
  174. cognite/neat/{core → v0/core}/_data_model/transformers/_mapping.py +7 -7
  175. cognite/neat/v0/core/_data_model/transformers/_union_conceptual.py +208 -0
  176. cognite/neat/{core → v0/core}/_data_model/transformers/_verification.py +7 -7
  177. cognite/neat/v0/core/_instances/__init__.py +0 -0
  178. cognite/neat/{core → v0/core}/_instances/_tracking/base.py +1 -1
  179. cognite/neat/{core → v0/core}/_instances/_tracking/log.py +1 -1
  180. cognite/neat/{core → v0/core}/_instances/extractors/__init__.py +1 -1
  181. cognite/neat/{core → v0/core}/_instances/extractors/_base.py +6 -6
  182. cognite/neat/v0/core/_instances/extractors/_classic_cdf/__init__.py +0 -0
  183. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_base.py +7 -7
  184. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_classic.py +12 -12
  185. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_relationships.py +3 -3
  186. cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_sequences.py +2 -2
  187. cognite/neat/{core → v0/core}/_instances/extractors/_dict.py +6 -3
  188. cognite/neat/{core → v0/core}/_instances/extractors/_dms.py +6 -6
  189. cognite/neat/{core → v0/core}/_instances/extractors/_dms_graph.py +11 -11
  190. cognite/neat/{core → v0/core}/_instances/extractors/_mock_graph_generator.py +10 -10
  191. cognite/neat/{core → v0/core}/_instances/extractors/_raw.py +3 -3
  192. cognite/neat/{core → v0/core}/_instances/extractors/_rdf_file.py +7 -7
  193. cognite/neat/{core → v0/core}/_instances/loaders/_base.py +5 -5
  194. cognite/neat/{core → v0/core}/_instances/loaders/_rdf2dms.py +17 -17
  195. cognite/neat/{core → v0/core}/_instances/loaders/_rdf_to_instance_space.py +11 -11
  196. cognite/neat/{core → v0/core}/_instances/queries/_select.py +29 -3
  197. cognite/neat/{core → v0/core}/_instances/queries/_update.py +1 -1
  198. cognite/neat/{core → v0/core}/_instances/transformers/_base.py +4 -4
  199. cognite/neat/{core → v0/core}/_instances/transformers/_classic_cdf.py +6 -6
  200. cognite/neat/{core → v0/core}/_instances/transformers/_prune_graph.py +4 -4
  201. cognite/neat/{core → v0/core}/_instances/transformers/_rdfpath.py +1 -1
  202. cognite/neat/{core → v0/core}/_instances/transformers/_value_type.py +4 -4
  203. cognite/neat/{core → v0/core}/_issues/_base.py +11 -6
  204. cognite/neat/{core → v0/core}/_issues/_contextmanagers.py +8 -6
  205. cognite/neat/{core → v0/core}/_issues/_factory.py +11 -8
  206. cognite/neat/{core → v0/core}/_issues/errors/__init__.py +3 -1
  207. cognite/neat/{core → v0/core}/_issues/errors/_external.py +1 -1
  208. cognite/neat/{core → v0/core}/_issues/errors/_general.py +1 -1
  209. cognite/neat/{core → v0/core}/_issues/errors/_properties.py +12 -1
  210. cognite/neat/{core → v0/core}/_issues/errors/_resources.py +2 -2
  211. cognite/neat/{core → v0/core}/_issues/errors/_wrapper.py +7 -3
  212. cognite/neat/{core → v0/core}/_issues/warnings/__init__.py +5 -1
  213. cognite/neat/{core → v0/core}/_issues/warnings/_external.py +1 -1
  214. cognite/neat/{core → v0/core}/_issues/warnings/_general.py +1 -1
  215. cognite/neat/{core → v0/core}/_issues/warnings/_models.py +39 -4
  216. cognite/neat/{core → v0/core}/_issues/warnings/_properties.py +13 -2
  217. cognite/neat/{core → v0/core}/_issues/warnings/_resources.py +1 -1
  218. cognite/neat/{core → v0/core}/_issues/warnings/user_modeling.py +1 -1
  219. cognite/neat/{core → v0/core}/_store/_data_model.py +13 -12
  220. cognite/neat/{core → v0/core}/_store/_instance.py +45 -12
  221. cognite/neat/{core → v0/core}/_store/_provenance.py +3 -3
  222. cognite/neat/{core → v0/core}/_store/exceptions.py +4 -4
  223. cognite/neat/v0/core/_utils/__init__.py +0 -0
  224. cognite/neat/{core → v0/core}/_utils/auth.py +1 -1
  225. cognite/neat/{core → v0/core}/_utils/auxiliary.py +7 -1
  226. cognite/neat/{core → v0/core}/_utils/collection_.py +2 -2
  227. cognite/neat/{core → v0/core}/_utils/graph_transformations_report.py +1 -1
  228. cognite/neat/{core → v0/core}/_utils/rdf_.py +38 -14
  229. cognite/neat/{core → v0/core}/_utils/reader/_base.py +1 -1
  230. cognite/neat/{core → v0/core}/_utils/spreadsheet.py +22 -4
  231. cognite/neat/v0/core/_utils/tarjan.py +44 -0
  232. cognite/neat/{core → v0/core}/_utils/text.py +1 -1
  233. cognite/neat/{core → v0/core}/_utils/upload.py +3 -3
  234. cognite/neat/v0/plugins/__init__.py +4 -0
  235. cognite/neat/v0/plugins/_base.py +9 -0
  236. cognite/neat/v0/plugins/_data_model.py +48 -0
  237. cognite/neat/{plugins → v0/plugins}/_issues.py +1 -1
  238. cognite/neat/{plugins → v0/plugins}/_manager.py +7 -16
  239. cognite/neat/{session → v0/session}/_base.py +13 -10
  240. cognite/neat/{session → v0/session}/_collector.py +1 -1
  241. cognite/neat/v0/session/_diff.py +51 -0
  242. cognite/neat/{session → v0/session}/_drop.py +3 -3
  243. cognite/neat/{session → v0/session}/_explore.py +2 -2
  244. cognite/neat/{session → v0/session}/_fix.py +2 -2
  245. cognite/neat/{session → v0/session}/_inspect.py +3 -3
  246. cognite/neat/{session → v0/session}/_mapping.py +3 -3
  247. cognite/neat/{session → v0/session}/_plugin.py +4 -5
  248. cognite/neat/{session → v0/session}/_prepare.py +8 -8
  249. cognite/neat/{session → v0/session}/_read.py +33 -43
  250. cognite/neat/{session → v0/session}/_set.py +8 -8
  251. cognite/neat/{session → v0/session}/_show.py +5 -5
  252. cognite/neat/{session → v0/session}/_state.py +22 -8
  253. cognite/neat/{session → v0/session}/_subset.py +4 -4
  254. cognite/neat/{session → v0/session}/_template.py +11 -11
  255. cognite/neat/{session → v0/session}/_to.py +12 -12
  256. cognite/neat/{session → v0/session}/_wizard.py +1 -1
  257. cognite/neat/{session → v0/session}/engine/_load.py +1 -1
  258. cognite/neat/{session → v0/session}/exceptions.py +5 -5
  259. cognite/neat/v1.py +3 -0
  260. {cognite_neat-0.123.2.dist-info → cognite_neat-0.127.30.dist-info}/METADATA +9 -8
  261. cognite_neat-0.127.30.dist-info/RECORD +319 -0
  262. {cognite_neat-0.123.2.dist-info → cognite_neat-0.127.30.dist-info}/WHEEL +1 -1
  263. cognite/neat/core/_data_model/importers/_dtdl2data_model/__init__.py +0 -3
  264. cognite/neat/core/_data_model/importers/_dtdl2data_model/_unit_lookup.py +0 -224
  265. cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_converter.py +0 -320
  266. cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_importer.py +0 -155
  267. cognite/neat/core/_data_model/importers/_dtdl2data_model/spec.py +0 -363
  268. cognite/neat/core/_data_model/importers/_rdf/__init__.py +0 -5
  269. cognite/neat/core/_data_model/importers/_rdf/_imf2data_model.py +0 -98
  270. cognite/neat/core/_data_model/importers/_rdf/_owl2data_model.py +0 -87
  271. cognite/neat/core/_data_model/importers/_rdf/_shared.py +0 -168
  272. cognite/neat/core/_data_model/models/conceptual/_validation.py +0 -294
  273. cognite/neat/core/_data_model/models/entities/_loaders.py +0 -75
  274. cognite/neat/plugins/__init__.py +0 -3
  275. cognite/neat/plugins/data_model/importers/__init__.py +0 -5
  276. cognite/neat/plugins/data_model/importers/_base.py +0 -28
  277. cognite_neat-0.123.2.dist-info/RECORD +0 -197
  278. /cognite/neat/{core → _data_model}/__init__.py +0 -0
  279. /cognite/neat/{core/_client/_api → _data_model/deployer}/__init__.py +0 -0
  280. /cognite/neat/{core/_client/data_classes → _data_model/exporters/_table_exporter}/__init__.py +0 -0
  281. /cognite/neat/{core/_data_model → _data_model/importers/_table_importer}/__init__.py +0 -0
  282. /cognite/neat/{core/_instances → _data_model/models}/__init__.py +0 -0
  283. /cognite/neat/{core/_instances/extractors/_classic_cdf → _data_model/models/conceptual}/__init__.py +0 -0
  284. /cognite/neat/{core/_utils → _data_model/validation}/__init__.py +0 -0
  285. /cognite/neat/{plugins/data_model → _session/_html}/__init__.py +0 -0
  286. /cognite/neat/{core → v0/core}/_client/__init__.py +0 -0
  287. /cognite/neat/{core → v0/core}/_client/data_classes/data_modeling.py +0 -0
  288. /cognite/neat/{core → v0/core}/_client/data_classes/neat_sequence.py +0 -0
  289. /cognite/neat/{core → v0/core}/_client/data_classes/statistics.py +0 -0
  290. /cognite/neat/{core → v0/core}/_config.py +0 -0
  291. /cognite/neat/{core → v0/core}/_data_model/analysis/__init__.py +0 -0
  292. /cognite/neat/{core → v0/core}/_data_model/catalog/__init__.py +0 -0
  293. /cognite/neat/{core → v0/core}/_data_model/catalog/classic_model.xlsx +0 -0
  294. /cognite/neat/{core → v0/core}/_data_model/catalog/conceptual-imf-data-model.xlsx +0 -0
  295. /cognite/neat/{core → v0/core}/_data_model/catalog/hello_world_pump.xlsx +0 -0
  296. /cognite/neat/{core → v0/core}/_data_model/models/_base_unverified.py +0 -0
  297. /cognite/neat/{core → v0/core}/_data_model/models/conceptual/__init__.py +0 -0
  298. /cognite/neat/{core → v0/core}/_data_model/models/entities/_constants.py +0 -0
  299. /cognite/neat/{core → v0/core}/_data_model/models/entities/_wrapped.py +0 -0
  300. /cognite/neat/{core → v0/core}/_data_model/models/mapping/__init__.py +0 -0
  301. /cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.yaml +0 -0
  302. /cognite/neat/{core → v0/core}/_instances/_shared.py +0 -0
  303. /cognite/neat/{core → v0/core}/_instances/_tracking/__init__.py +0 -0
  304. /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -0
  305. /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44.xml +0 -0
  306. /cognite/neat/{core → v0/core}/_instances/examples/__init__.py +0 -0
  307. /cognite/neat/{core → v0/core}/_instances/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  308. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_assets.py +0 -0
  309. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_data_sets.py +0 -0
  310. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_events.py +0 -0
  311. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_files.py +0 -0
  312. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_labels.py +0 -0
  313. /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_timeseries.py +0 -0
  314. /cognite/neat/{core → v0/core}/_instances/loaders/__init__.py +0 -0
  315. /cognite/neat/{core → v0/core}/_instances/queries/__init__.py +0 -0
  316. /cognite/neat/{core → v0/core}/_instances/queries/_base.py +0 -0
  317. /cognite/neat/{core → v0/core}/_instances/queries/_queries.py +0 -0
  318. /cognite/neat/{core → v0/core}/_instances/transformers/__init__.py +0 -0
  319. /cognite/neat/{core → v0/core}/_issues/__init__.py +0 -0
  320. /cognite/neat/{core → v0/core}/_issues/formatters.py +0 -0
  321. /cognite/neat/{core → v0/core}/_shared.py +0 -0
  322. /cognite/neat/{core → v0/core}/_store/__init__.py +0 -0
  323. /cognite/neat/{core → v0/core}/_utils/io_.py +0 -0
  324. /cognite/neat/{core → v0/core}/_utils/reader/__init__.py +0 -0
  325. /cognite/neat/{core → v0/core}/_utils/time_.py +0 -0
  326. /cognite/neat/{core → v0/core}/_utils/xml_.py +0 -0
  327. /cognite/neat/{session → v0/session}/__init__.py +0 -0
  328. /cognite/neat/{session → v0/session}/_experimental.py +0 -0
  329. /cognite/neat/{session → v0/session}/_state/README.md +0 -0
  330. /cognite/neat/{session → v0/session}/engine/__init__.py +0 -0
  331. /cognite/neat/{session → v0/session}/engine/_import.py +0 -0
  332. /cognite/neat/{session → v0/session}/engine/_interface.py +0 -0
  333. {cognite_neat-0.123.2.dist-info → cognite_neat-0.127.30.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,19 @@
1
+ import functools
2
+ import platform
3
+
4
+ from cognite.neat._utils.auxiliary import get_current_neat_version
5
+
6
+
7
+ @functools.lru_cache(maxsize=1)
8
+ def get_user_agent() -> str:
9
+ neat_version = f"CogniteNeat/{get_current_neat_version()}"
10
+ python_version = (
11
+ f"{platform.python_implementation()}/{platform.python_version()} "
12
+ f"({platform.python_build()};{platform.python_compiler()})"
13
+ )
14
+ os_version_info = [platform.release(), platform.machine(), platform.architecture()[0]]
15
+ os_version_info = [s for s in os_version_info if s] # Ignore empty strings
16
+ os_version_info_str = "-".join(os_version_info)
17
+ operating_system = f"{platform.system()}/{os_version_info_str}"
18
+
19
+ return f"{neat_version} {python_version} {operating_system}"
@@ -0,0 +1,294 @@
1
+ import sys
2
+ from abc import ABC, abstractmethod
3
+ from collections import UserList
4
+ from collections.abc import MutableSequence, Sequence
5
+ from typing import Generic, Literal, TypeAlias, TypeVar
6
+
7
+ import httpx
8
+ from pydantic import BaseModel, ConfigDict, Field, JsonValue, ValidationError, model_serializer
9
+
10
+ from cognite.neat._exceptions import CDFAPIException
11
+ from cognite.neat._utils.http_client._tracker import ItemsRequestTracker
12
+ from cognite.neat._utils.useful_types import PrimaryTypes, ReferenceObject, T_Reference
13
+
14
+ if sys.version_info >= (3, 11):
15
+ from typing import Self
16
+ else:
17
+ from typing_extensions import Self
18
+
19
+ StatusCode: TypeAlias = int
20
+
21
+
22
+ class HTTPMessage(BaseModel):
23
+ """Base class for HTTP messages (requests and responses)"""
24
+
25
+
26
+ class FailedRequestMessage(HTTPMessage):
27
+ message: str
28
+
29
+ def __str__(self) -> str:
30
+ return self.message
31
+
32
+
33
+ class ResponseMessage(HTTPMessage):
34
+ code: StatusCode
35
+ body: str
36
+
37
+
38
+ class SuccessResponse(ResponseMessage): ...
39
+
40
+
41
+ class ErrorDetails(BaseModel):
42
+ """This is the structure of failure responses from CDF APIs"""
43
+
44
+ code: StatusCode
45
+ message: str
46
+ missing: list[JsonValue] | None = None
47
+ duplicated: list[JsonValue] | None = None
48
+ is_auto_retryable: bool | None = Field(None, alias="isAutoRetryable")
49
+
50
+ @classmethod
51
+ def from_response(cls, response: httpx.Response) -> "ErrorDetails":
52
+ try:
53
+ return _ErrorResponse.model_validate_json(response.text).error
54
+ except ValidationError:
55
+ return cls(code=response.status_code, message=response.text)
56
+
57
+
58
+ class _ErrorResponse(BaseModel):
59
+ error: ErrorDetails
60
+
61
+
62
+ class FailedResponse(ResponseMessage):
63
+ error: ErrorDetails
64
+
65
+ def __str__(self) -> str:
66
+ return f"HTTP {self.code} | {self.error.message}"
67
+
68
+
69
+ class RequestMessage(HTTPMessage, ABC):
70
+ """Base class for HTTP request messages"""
71
+
72
+ endpoint_url: str
73
+ method: Literal["GET", "POST", "PATCH", "DELETE"]
74
+ connect_attempt: int = 0
75
+ read_attempt: int = 0
76
+ status_attempt: int = 0
77
+ api_version: str | None = None
78
+
79
+ @property
80
+ def total_attempts(self) -> int:
81
+ return self.connect_attempt + self.read_attempt + self.status_attempt
82
+
83
+ @abstractmethod
84
+ def create_success_response(self, response: httpx.Response) -> Sequence[HTTPMessage]:
85
+ raise NotImplementedError()
86
+
87
+ @abstractmethod
88
+ def create_failure_response(self, response: httpx.Response) -> Sequence[HTTPMessage]:
89
+ raise NotImplementedError()
90
+
91
+ @abstractmethod
92
+ def create_failed_request(self, error_message: str) -> Sequence[HTTPMessage]:
93
+ raise NotImplementedError()
94
+
95
+
96
+ class SimpleRequest(RequestMessage):
97
+ """Base class for requests with a simple success/fail response structure"""
98
+
99
+ def create_success_response(self, response: httpx.Response) -> Sequence[HTTPMessage]:
100
+ return [SuccessResponse(code=response.status_code, body=response.text)]
101
+
102
+ def create_failure_response(self, response: httpx.Response) -> Sequence[HTTPMessage]:
103
+ return [
104
+ FailedResponse(code=response.status_code, body=response.text, error=ErrorDetails.from_response(response))
105
+ ]
106
+
107
+ def create_failed_request(self, error_message: str) -> Sequence[HTTPMessage]:
108
+ return [FailedRequestMessage(message=error_message)]
109
+
110
+
111
+ class ParametersRequest(SimpleRequest):
112
+ """Base class for HTTP request messages with query parameters"""
113
+
114
+ parameters: dict[str, PrimaryTypes] | None = None
115
+
116
+
117
+ class BodyRequest(ParametersRequest, ABC):
118
+ """Base class for HTTP request messages with a body"""
119
+
120
+ @abstractmethod
121
+ def data(self) -> str:
122
+ raise NotImplementedError()
123
+
124
+
125
+ class SimpleBodyRequest(BodyRequest):
126
+ body: str
127
+
128
+ def data(self) -> str:
129
+ return self.body
130
+
131
+
132
+ class ItemMessage(BaseModel, Generic[T_Reference], ABC):
133
+ """Base class for message related to a specific item"""
134
+
135
+ ids: Sequence[T_Reference]
136
+
137
+
138
+ class SuccessResponseItems(ItemMessage[T_Reference], SuccessResponse): ...
139
+
140
+
141
+ class FailedResponseItems(ItemMessage[T_Reference], FailedResponse): ...
142
+
143
+
144
+ class FailedRequestItems(ItemMessage[T_Reference], FailedRequestMessage): ...
145
+
146
+
147
+ T_BaseModel = TypeVar("T_BaseModel", bound=BaseModel)
148
+
149
+
150
+ class ItemBody(BaseModel, Generic[T_Reference, T_BaseModel], ABC):
151
+ items: Sequence[T_BaseModel]
152
+ extra_args: dict[str, JsonValue] | None = None
153
+
154
+ @model_serializer(mode="plain", return_type=dict)
155
+ def serialize(self) -> dict[str, JsonValue]:
156
+ data: dict[str, JsonValue] = {
157
+ "items": [item.model_dump(exclude_unset=False, by_alias=True, exclude_none=False) for item in self.items]
158
+ }
159
+ if isinstance(self.extra_args, dict):
160
+ data.update(self.extra_args)
161
+ return data
162
+
163
+ @abstractmethod
164
+ def as_ids(self) -> list[T_Reference]:
165
+ """Returns the list of item identifiers for the items in the body."""
166
+ raise NotImplementedError()
167
+
168
+ def split(self, mid: int) -> tuple[Self, Self]:
169
+ """Splits the body into two smaller bodies.
170
+
171
+ This is useful for retrying requests that fail due to size limits or timeouts.
172
+
173
+ Args:
174
+ mid: The index at which to split the items.
175
+ Returns:
176
+ A tuple containing two new ItemBody instances, each with half of the original items.
177
+
178
+ """
179
+
180
+ type_ = type(self)
181
+ return type_(items=self.items[:mid], extra_args=self.extra_args), type_(
182
+ items=self.items[mid:], extra_args=self.extra_args
183
+ )
184
+
185
+
186
+ class ItemIDBody(ItemBody[ReferenceObject, ReferenceObject]):
187
+ def as_ids(self) -> list[ReferenceObject]:
188
+ return list(self.items)
189
+
190
+
191
+ class ItemsRequest(BodyRequest, Generic[T_Reference, T_BaseModel]):
192
+ """Requests message for endpoints that accept multiple items in a single request.
193
+
194
+ This class provides functionality to split large requests into smaller ones, handle responses for each item,
195
+ and manage errors effectively.
196
+
197
+ Attributes:
198
+ body (ItemBody): The body of the request containing the items to be processed.
199
+ max_failures_before_abort (int): The maximum number of failed split requests before aborting further splits.
200
+
201
+ """
202
+
203
+ model_config = ConfigDict(arbitrary_types_allowed=True)
204
+ body: ItemBody[T_Reference, T_BaseModel]
205
+ max_failures_before_abort: int = 50
206
+ tracker: ItemsRequestTracker | None = None
207
+
208
+ def data(self) -> str:
209
+ return self.body.model_dump_json(exclude_unset=True, by_alias=True)
210
+
211
+ def split(self, status_attempts: int) -> "list[ItemsRequest]":
212
+ """Splits the request into two smaller requests.
213
+
214
+ This is useful for retrying requests that fail due to size limits or timeouts.
215
+
216
+ Args:
217
+ status_attempts: The number of status attempts to set for the new requests. This is used when the
218
+ request failed with a 5xx status code and we want to track the number of attempts. For 4xx errors,
219
+ there is at least one item causing the error, so we do not increment the status attempts, but
220
+ instead essentially do a binary search to find the problematic item(s).
221
+
222
+ Returns:
223
+ A list containing two new ItemsRequest instances, each with half of the original items.
224
+
225
+ """
226
+ mid = len(self.body.items) // 2
227
+ if mid == 0:
228
+ return [self]
229
+ tracker = self.tracker or ItemsRequestTracker(self.max_failures_before_abort)
230
+ tracker.register_failure()
231
+ messages: list[ItemsRequest] = []
232
+ for body in self.body.split(mid):
233
+ item_request = ItemsRequest(
234
+ endpoint_url=self.endpoint_url,
235
+ method=self.method,
236
+ body=body,
237
+ connect_attempt=self.connect_attempt,
238
+ read_attempt=self.read_attempt,
239
+ status_attempt=status_attempts,
240
+ )
241
+ item_request.tracker = tracker
242
+ messages.append(item_request)
243
+ return messages
244
+
245
+ def create_success_response(self, response: httpx.Response) -> Sequence[HTTPMessage]:
246
+ return [SuccessResponseItems(code=response.status_code, body=response.text, ids=self.body.as_ids())]
247
+
248
+ def create_failure_response(self, response: httpx.Response) -> Sequence[HTTPMessage]:
249
+ """Creates response messages based on the HTTP response and the original request.
250
+
251
+ Args:
252
+ response: The HTTP response received from the server.
253
+ Returns:
254
+ A sequence of HTTPMessage instances representing the outcome for each item in the request.
255
+ """
256
+ return [
257
+ FailedResponseItems(
258
+ code=response.status_code,
259
+ body=response.text,
260
+ error=ErrorDetails.from_response(response),
261
+ ids=self.body.as_ids(),
262
+ )
263
+ ]
264
+
265
+ def create_failed_request(self, error_message: str) -> Sequence[HTTPMessage]:
266
+ """Creates failed request messages for each item in the request.
267
+
268
+ Args:
269
+ error_message: The error message to include in the failed request messages.
270
+
271
+ Returns:
272
+ A sequence of HTTPMessage instances representing the failed request for each item.
273
+ """
274
+ return [FailedRequestItems(message=error_message, ids=self.body.as_ids())]
275
+
276
+
277
+ class APIResponse(UserList, MutableSequence[ResponseMessage | FailedRequestMessage]):
278
+ def __init__(self, collection: Sequence[ResponseMessage | FailedRequestMessage] | None = None):
279
+ super().__init__(collection or [])
280
+
281
+ def raise_for_status(self) -> None:
282
+ error_messages = [message for message in self.data if not isinstance(message, SuccessResponse)]
283
+ if error_messages:
284
+ raise CDFAPIException(error_messages)
285
+
286
+ @property
287
+ def success_response(self) -> SuccessResponse:
288
+ success = [msg for msg in self.data if isinstance(msg, SuccessResponse)]
289
+ if len(success) == 1:
290
+ return success[0]
291
+ elif success:
292
+ raise ValueError("Multiple successful HTTP responses found in the messages.")
293
+ else:
294
+ raise ValueError("No successful HTTP response found in the messages.")
@@ -0,0 +1,31 @@
1
+ import threading
2
+ from dataclasses import dataclass, field
3
+
4
+
5
+ @dataclass
6
+ class ItemsRequestTracker:
7
+ """Tracks the state of requests split from an original request.
8
+
9
+ Attributes:
10
+ max_failures_before_abort (int): Maximum number of allowed failed split requests before aborting
11
+ the entire operation. A value of -1 indicates no early abort.
12
+ lock (threading.Lock): A lock to ensure thread-safe updates to the failure count.
13
+ failed_split_count (int): The current count of failed split requests.
14
+
15
+ """
16
+
17
+ max_failures_before_abort: int = -1 # -1 means no early abort
18
+ lock: threading.Lock = field(default_factory=threading.Lock, init=False)
19
+ failed_split_count: int = field(default=0, init=False)
20
+
21
+ def register_failure(self) -> None:
22
+ """Register a failed split request and return whether to continue splitting."""
23
+ with self.lock:
24
+ self.failed_split_count += 1
25
+
26
+ def limit_reached(self) -> bool:
27
+ """Check if the failure limit has been reached."""
28
+ with self.lock:
29
+ if self.max_failures_before_abort < 0:
30
+ return False
31
+ return self.failed_split_count >= self.max_failures_before_abort
@@ -0,0 +1,71 @@
1
+ import re
2
+ from collections.abc import Collection
3
+ from typing import Any
4
+
5
+ NEWLINE = "\n"
6
+ TAB = "\t"
7
+
8
+
9
+ def humanize_collection(collection: Collection[Any], /, *, sort: bool = True, bind_word: str = "and") -> str:
10
+ """Convert a collection of items to a human-readable string.
11
+
12
+ Args:
13
+ collection: The collection of items to convert.
14
+ sort: Whether to sort the collection before converting. Default is True.
15
+ bind_word: The word to use to bind the last two items. Default is "and".
16
+
17
+ Returns:
18
+ A human-readable string of the collection.
19
+
20
+ Examples:
21
+ >>> humanize_collection(["b", "c", "a"])
22
+ 'a, b and c'
23
+ >>> humanize_collection(["b", "c", "a"], sort=False)
24
+ 'b, c and a'
25
+ >>> humanize_collection(["a", "b"])
26
+ 'a and b'
27
+ >>> humanize_collection(["a"])
28
+ 'a'
29
+ >>> humanize_collection([])
30
+ ''
31
+
32
+ """
33
+ if not collection:
34
+ return ""
35
+ elif len(collection) == 1:
36
+ return str(next(iter(collection)))
37
+
38
+ strings = (str(item) for item in collection)
39
+ if sort:
40
+ sequence = sorted(strings)
41
+ else:
42
+ sequence = list(strings)
43
+
44
+ return f"{', '.join(sequence[:-1])} {bind_word} {sequence[-1]}"
45
+
46
+
47
+ def title_case(s: str) -> str:
48
+ """Convert a string to title case, handling underscores and hyphens.
49
+
50
+ Args:
51
+ s: The string to convert.
52
+ Returns:
53
+ The title-cased string.
54
+ Examples:
55
+ >>> title_case("hello world")
56
+ 'Hello World'
57
+ >>> title_case("hello_world")
58
+ 'Hello World'
59
+ >>> title_case("hello-world")
60
+ 'Hello World'
61
+ >>> title_case("hello_world-and-universe")
62
+ 'Hello World And Universe'
63
+ >>> title_case("HELLO WORLD")
64
+ 'Hello World'
65
+ """
66
+ return " ".join(word.capitalize() for word in s.replace("_", " ").replace("-", " ").split())
67
+
68
+
69
+ def split_on_capitals(text: str) -> list[str]:
70
+ """Split a string at capital letters."""
71
+ return re.findall(r"[A-Z][a-z]*", text)
@@ -0,0 +1,37 @@
1
+ from collections.abc import Hashable
2
+ from datetime import date, datetime, time, timedelta
3
+ from typing import Literal, TypeAlias, TypeVar
4
+
5
+ from pydantic import BaseModel
6
+ from pydantic.alias_generators import to_camel
7
+
8
+ JsonVal: TypeAlias = None | str | int | float | bool | dict[str, "JsonVal"] | list["JsonVal"]
9
+ PrimaryTypes: TypeAlias = str | int | float | bool
10
+
11
+ T_ID = TypeVar("T_ID", bound=Hashable)
12
+ # These are the types that openpyxl supports in cells
13
+ CellValueType: TypeAlias = str | int | float | bool | datetime | date | time | timedelta | None
14
+
15
+ # The format expected for excel sheets representing a data model
16
+ DataModelTableType: TypeAlias = dict[str, list[dict[str, CellValueType]]]
17
+ PrimitiveType: TypeAlias = str | int | float | bool
18
+
19
+
20
+ class BaseModelObject(BaseModel, alias_generator=to_camel, extra="ignore"):
21
+ """Base class for all object. This includes resources and nested objects."""
22
+
23
+ ...
24
+
25
+
26
+ T_Item = TypeVar("T_Item", bound=BaseModelObject)
27
+
28
+
29
+ class ReferenceObject(BaseModelObject, frozen=True, populate_by_name=True):
30
+ """Base class for all reference objects - these are identifiers."""
31
+
32
+ ...
33
+
34
+
35
+ T_Reference = TypeVar("T_Reference", bound=ReferenceObject, covariant=True)
36
+
37
+ ModusOperandi: TypeAlias = Literal["rebuild", "additive"]
@@ -0,0 +1,154 @@
1
+ from collections.abc import Callable, Mapping
2
+ from dataclasses import dataclass, field
3
+ from typing import Literal
4
+
5
+ from pydantic_core import ErrorDetails
6
+
7
+
8
+ def as_json_path(loc: tuple[str | int, ...]) -> str:
9
+ """Converts a location tuple to a JSON path.
10
+
11
+ Args:
12
+ loc: The location tuple to convert.
13
+
14
+ Returns:
15
+ A JSON path string.
16
+ """
17
+ if not loc:
18
+ return ""
19
+ # +1 to convert from 0-based to 1-based indexing
20
+ prefix = ""
21
+ if isinstance(loc[0], int):
22
+ prefix = "item"
23
+
24
+ suffix = ".".join([str(x) if isinstance(x, str) else f"[{x + 1}]" for x in loc]).replace(".[", "[")
25
+ return f"{prefix}{suffix}"
26
+
27
+
28
+ @dataclass
29
+ class ValidationContext:
30
+ """
31
+ Context for validation errors providing configuration for error message formatting.
32
+
33
+ This class configures how validation errors are reported, including location formatting,
34
+ field naming conventions, and how to present missing required fields.
35
+
36
+ Attributes:
37
+ parent_loc: Optional location tuple to prepend to each error location.
38
+ This is useful when the error is for a nested model and you want to include the location
39
+ of the parent model.
40
+ humanize_location: A function that converts a location tuple to a human-readable string.
41
+ The default is `as_json_path`, which converts the location to a JSON path.
42
+ This can for example be replaced when the location comes from an Excel table.
43
+ field_name: The name use for "field" in error messages. Default is "field". This can be changed to
44
+ "column" or "value" to better fit the context.
45
+ field_renaming: Optional mapping of field names to source names.
46
+ This is useful when the field names in the model are different from the names in the source.
47
+ For example, if the model field is "asset_id" but the source column is "Asset ID",
48
+ you can provide a mapping {"asset_id": "Asset ID"} to have the error messages use the source names.
49
+ missing_required_descriptor: How to describe missing required fields. Default is "missing".
50
+ Other option is "empty" which can be more suitable for table data.
51
+ """
52
+
53
+ parent_loc: tuple[int | str, ...] = field(default_factory=tuple)
54
+ humanize_location: Callable[[tuple[int | str, ...]], str] = as_json_path
55
+ field_name: Literal["field", "column", "value"] = "field"
56
+ field_renaming: Mapping[str, str] = field(default_factory=dict)
57
+ missing_required_descriptor: Literal["empty", "missing"] = "missing"
58
+
59
+
60
+ def humanize_validation_error(
61
+ error: ErrorDetails,
62
+ context: ValidationContext | None = None,
63
+ ) -> str:
64
+ """Converts a pydantic ErrorDetails object to a human-readable format.
65
+ This overwrites the default error messages from Pydantic to be better suited for NEAT users.
66
+ Args:
67
+ error: The ErrorDetails object to convert.
68
+ context: The context for humanizing the error.
69
+ Returns:
70
+ A human-readable error message.
71
+ """
72
+
73
+ context = context or ValidationContext()
74
+
75
+ loc = (*context.parent_loc, *error["loc"])
76
+ type_ = error["type"]
77
+
78
+ if type_ == "missing":
79
+ msg = f"Missing required {context.field_name}: {loc[-1]!r}"
80
+ elif type_ == "extra_forbidden":
81
+ msg = f"Unused {context.field_name}: {loc[-1]!r}"
82
+ elif type_ == "value_error":
83
+ msg = str(error["ctx"]["error"])
84
+ elif type_ == "literal_error":
85
+ msg = f"{error['msg']}. Got {error['input']!r}."
86
+ elif type_ == "string_type":
87
+ msg = f"{error['msg']}. Got {error['input']!r} of type {type(error['input']).__name__}. "
88
+ elif type_ == "model_type":
89
+ model_name = error["ctx"].get("class_name", "unknown")
90
+ msg = (
91
+ f"Input must be an object of type {model_name}. Got {error['input']!r} of "
92
+ f"type {type(error['input']).__name__}."
93
+ )
94
+ elif type_ == "union_tag_invalid":
95
+ msg = error["msg"].replace(", 'direct'", "").replace("found using 'type' ", "").replace("tag", "value")
96
+ elif type_ == "string_pattern_mismatch":
97
+ msg = f"string '{error['input']}' does not match the required pattern: '{error['ctx']['pattern']}'."
98
+
99
+ elif type_.endswith("_type"):
100
+ msg = f"{error['msg']}. Got {error['input']!r} of type {type(error['input']).__name__}."
101
+ else:
102
+ # Default to the Pydantic error message
103
+ msg = error["msg"]
104
+
105
+ if type_.endswith("dict_type") and len(loc) > 1:
106
+ # If this is a dict_type error for a JSON field, the location will be:
107
+ # dict[str,json-or-python[json=any,python=tagged-union[list[...],dict[str,...],str,bool,int,float,none]]]
108
+ # This is hard to read, so we simplify it to just the field name.
109
+ loc = tuple(["dict" if isinstance(x, str) and "json-or-python" in x else x for x in loc])
110
+
111
+ error_suffix = f"{msg[:1].casefold()}{msg[1:]}"
112
+
113
+ if len(loc) >= 3 and context.field_name == "column" and loc[-3:] == ("type", "enum", "values"):
114
+ # Special handling for enum errors in table columns
115
+ msg = _enum_message(type_, loc, context)
116
+ elif len(loc) > 1 and type_ in {"extra_forbidden", "missing"}:
117
+ if context.missing_required_descriptor == "empty" and type_ == "missing":
118
+ # This is a table so we modify the error message.
119
+ msg = (
120
+ f"In {context.humanize_location(loc[:-1])} the {context.field_name}"
121
+ f" {context.field_renaming.get(str(loc[-1]), loc[-1])!r} "
122
+ "cannot be empty."
123
+ )
124
+ else:
125
+ # We skip the last element as this is in the message already
126
+ msg = f"In {context.humanize_location(loc[:-1])} {error_suffix.replace('field', context.field_name)}"
127
+ elif len(loc) > 1:
128
+ if context.parent_loc == ("Metadata",) and len(loc) == 2:
129
+ msg = f"In table '{loc[0]}' '{loc[1]}' {error_suffix}"
130
+ else:
131
+ msg = f"In {context.humanize_location(loc)} {error_suffix}"
132
+ elif len(loc) == 1 and isinstance(loc[0], str) and type_ not in {"extra_forbidden", "missing"}:
133
+ msg = f"In {context.field_name} {loc[0]!r}, {error_suffix}"
134
+
135
+ msg = msg.strip()
136
+ if not msg.endswith("."):
137
+ msg += "."
138
+ return msg
139
+
140
+
141
+ def _enum_message(type_: str, loc: tuple[int | str, ...], context: ValidationContext) -> str:
142
+ """Special handling of enum errors in table columns."""
143
+
144
+ if loc[-1] != "values":
145
+ raise RuntimeError("This is a neat bug, report to the team.")
146
+ if type_ == "missing":
147
+ return (
148
+ f"In {context.humanize_location(loc[:-1])} definition should include "
149
+ "a reference to a collection in the 'Enum' sheet (e.g., collection='MyEnumCollection')."
150
+ )
151
+ elif type_ == "too_short":
152
+ return f"In {context.humanize_location(loc[:-1])} collection is not defined in the 'Enum' sheet"
153
+ else:
154
+ raise RuntimeError("This is a neat bug, report to the team.")
cognite/neat/_version.py CHANGED
@@ -1,2 +1,2 @@
1
- __version__ = "0.123.2"
1
+ __version__ = "0.127.30"
2
2
  __engine__ = "^2.0.4"
File without changes
File without changes
File without changes