cognite-neat 0.123.24__py3-none-any.whl → 1.0.22__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 (342) hide show
  1. cognite/neat/__init__.py +4 -3
  2. cognite/neat/_client/__init__.py +5 -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 +138 -0
  7. cognite/neat/_client/data_classes.py +44 -0
  8. cognite/neat/_client/data_model_api.py +115 -0
  9. cognite/neat/_client/init/credentials.py +70 -0
  10. cognite/neat/_client/init/env_vars.py +131 -0
  11. cognite/neat/_client/init/main.py +51 -0
  12. cognite/neat/_client/spaces_api.py +115 -0
  13. cognite/neat/_client/statistics_api.py +24 -0
  14. cognite/neat/_client/views_api.py +144 -0
  15. cognite/neat/_config.py +266 -0
  16. cognite/neat/_data_model/_analysis.py +571 -0
  17. cognite/neat/_data_model/_constants.py +74 -0
  18. cognite/neat/_data_model/_identifiers.py +61 -0
  19. cognite/neat/_data_model/_shared.py +41 -0
  20. cognite/neat/_data_model/_snapshot.py +134 -0
  21. cognite/neat/_data_model/deployer/_differ.py +140 -0
  22. cognite/neat/_data_model/deployer/_differ_container.py +360 -0
  23. cognite/neat/_data_model/deployer/_differ_data_model.py +54 -0
  24. cognite/neat/_data_model/deployer/_differ_space.py +9 -0
  25. cognite/neat/_data_model/deployer/_differ_view.py +299 -0
  26. cognite/neat/_data_model/deployer/data_classes.py +644 -0
  27. cognite/neat/_data_model/deployer/deployer.py +431 -0
  28. cognite/neat/_data_model/exporters/__init__.py +15 -0
  29. cognite/neat/_data_model/exporters/_api_exporter.py +37 -0
  30. cognite/neat/_data_model/exporters/_base.py +24 -0
  31. cognite/neat/_data_model/exporters/_table_exporter/exporter.py +128 -0
  32. cognite/neat/_data_model/exporters/_table_exporter/workbook.py +409 -0
  33. cognite/neat/_data_model/exporters/_table_exporter/writer.py +480 -0
  34. cognite/neat/_data_model/importers/__init__.py +5 -0
  35. cognite/neat/_data_model/importers/_api_importer.py +166 -0
  36. cognite/neat/_data_model/importers/_base.py +16 -0
  37. cognite/neat/_data_model/importers/_table_importer/data_classes.py +344 -0
  38. cognite/neat/_data_model/importers/_table_importer/importer.py +192 -0
  39. cognite/neat/_data_model/importers/_table_importer/reader.py +1102 -0
  40. cognite/neat/_data_model/importers/_table_importer/source.py +94 -0
  41. cognite/neat/_data_model/models/conceptual/_base.py +18 -0
  42. cognite/neat/_data_model/models/conceptual/_concept.py +67 -0
  43. cognite/neat/_data_model/models/conceptual/_data_model.py +51 -0
  44. cognite/neat/_data_model/models/conceptual/_properties.py +104 -0
  45. cognite/neat/_data_model/models/conceptual/_property.py +105 -0
  46. cognite/neat/_data_model/models/dms/__init__.py +206 -0
  47. cognite/neat/_data_model/models/dms/_base.py +31 -0
  48. cognite/neat/_data_model/models/dms/_constants.py +48 -0
  49. cognite/neat/_data_model/models/dms/_constraints.py +42 -0
  50. cognite/neat/_data_model/models/dms/_container.py +159 -0
  51. cognite/neat/_data_model/models/dms/_data_model.py +95 -0
  52. cognite/neat/_data_model/models/dms/_data_types.py +195 -0
  53. cognite/neat/_data_model/models/dms/_http.py +28 -0
  54. cognite/neat/_data_model/models/dms/_indexes.py +30 -0
  55. cognite/neat/_data_model/models/dms/_limits.py +96 -0
  56. cognite/neat/_data_model/models/dms/_references.py +141 -0
  57. cognite/neat/_data_model/models/dms/_schema.py +18 -0
  58. cognite/neat/_data_model/models/dms/_space.py +48 -0
  59. cognite/neat/_data_model/models/dms/_types.py +17 -0
  60. cognite/neat/_data_model/models/dms/_view_filter.py +310 -0
  61. cognite/neat/_data_model/models/dms/_view_property.py +235 -0
  62. cognite/neat/_data_model/models/dms/_views.py +216 -0
  63. cognite/neat/_data_model/models/entities/__init__.py +50 -0
  64. cognite/neat/_data_model/models/entities/_base.py +101 -0
  65. cognite/neat/_data_model/models/entities/_constants.py +22 -0
  66. cognite/neat/_data_model/models/entities/_data_types.py +144 -0
  67. cognite/neat/_data_model/models/entities/_identifiers.py +61 -0
  68. cognite/neat/_data_model/models/entities/_parser.py +226 -0
  69. cognite/neat/_data_model/validation/dms/__init__.py +75 -0
  70. cognite/neat/_data_model/validation/dms/_ai_readiness.py +381 -0
  71. cognite/neat/_data_model/validation/dms/_base.py +25 -0
  72. cognite/neat/_data_model/validation/dms/_connections.py +681 -0
  73. cognite/neat/_data_model/validation/dms/_consistency.py +58 -0
  74. cognite/neat/_data_model/validation/dms/_containers.py +199 -0
  75. cognite/neat/_data_model/validation/dms/_limits.py +368 -0
  76. cognite/neat/_data_model/validation/dms/_orchestrator.py +70 -0
  77. cognite/neat/_data_model/validation/dms/_views.py +164 -0
  78. cognite/neat/_exceptions.py +68 -0
  79. cognite/neat/_issues.py +68 -0
  80. cognite/neat/_session/__init__.py +3 -0
  81. cognite/neat/_session/_html/_render.py +30 -0
  82. cognite/neat/_session/_html/static/__init__.py +8 -0
  83. cognite/neat/_session/_html/static/deployment.css +476 -0
  84. cognite/neat/_session/_html/static/deployment.js +181 -0
  85. cognite/neat/_session/_html/static/issues.css +211 -0
  86. cognite/neat/_session/_html/static/issues.js +168 -0
  87. cognite/neat/_session/_html/static/shared.css +186 -0
  88. cognite/neat/_session/_html/templates/__init__.py +4 -0
  89. cognite/neat/_session/_html/templates/deployment.html +80 -0
  90. cognite/neat/_session/_html/templates/issues.html +45 -0
  91. cognite/neat/_session/_issues.py +81 -0
  92. cognite/neat/_session/_physical.py +294 -0
  93. cognite/neat/_session/_result/__init__.py +3 -0
  94. cognite/neat/_session/_result/_deployment/__init__.py +0 -0
  95. cognite/neat/_session/_result/_deployment/_physical/__init__.py +0 -0
  96. cognite/neat/_session/_result/_deployment/_physical/_changes.py +196 -0
  97. cognite/neat/_session/_result/_deployment/_physical/_statistics.py +180 -0
  98. cognite/neat/_session/_result/_deployment/_physical/serializer.py +35 -0
  99. cognite/neat/_session/_result/_result.py +31 -0
  100. cognite/neat/_session/_session.py +81 -0
  101. cognite/neat/_session/_usage_analytics/__init__.py +0 -0
  102. cognite/neat/_session/_usage_analytics/_collector.py +131 -0
  103. cognite/neat/_session/_usage_analytics/_constants.py +23 -0
  104. cognite/neat/_session/_usage_analytics/_storage.py +240 -0
  105. cognite/neat/_session/_wrappers.py +101 -0
  106. cognite/neat/_state_machine/__init__.py +10 -0
  107. cognite/neat/_state_machine/_base.py +37 -0
  108. cognite/neat/_state_machine/_states.py +52 -0
  109. cognite/neat/_store/__init__.py +3 -0
  110. cognite/neat/_store/_provenance.py +88 -0
  111. cognite/neat/_store/_store.py +220 -0
  112. cognite/neat/_utils/__init__.py +0 -0
  113. cognite/neat/_utils/_reader.py +194 -0
  114. cognite/neat/_utils/auxiliary.py +49 -0
  115. cognite/neat/_utils/collection.py +11 -0
  116. cognite/neat/_utils/http_client/__init__.py +39 -0
  117. cognite/neat/_utils/http_client/_client.py +245 -0
  118. cognite/neat/_utils/http_client/_config.py +19 -0
  119. cognite/neat/_utils/http_client/_data_classes.py +294 -0
  120. cognite/neat/_utils/http_client/_tracker.py +31 -0
  121. cognite/neat/_utils/repo.py +19 -0
  122. cognite/neat/_utils/text.py +71 -0
  123. cognite/neat/_utils/useful_types.py +37 -0
  124. cognite/neat/_utils/validation.py +154 -0
  125. cognite/neat/_v0/__init__.py +0 -0
  126. cognite/neat/_v0/core/__init__.py +0 -0
  127. cognite/neat/_v0/core/_client/_api/__init__.py +0 -0
  128. cognite/neat/{core → _v0/core}/_client/_api/data_modeling_loaders.py +8 -7
  129. cognite/neat/{core → _v0/core}/_client/_api/neat_instances.py +5 -5
  130. cognite/neat/{core → _v0/core}/_client/_api/schema.py +5 -5
  131. cognite/neat/{core → _v0/core}/_client/_api/statistics.py +3 -3
  132. cognite/neat/{core → _v0/core}/_client/_api_client.py +1 -1
  133. cognite/neat/_v0/core/_client/data_classes/__init__.py +0 -0
  134. cognite/neat/{core → _v0/core}/_client/data_classes/schema.py +4 -4
  135. cognite/neat/{core → _v0/core}/_client/testing.py +1 -1
  136. cognite/neat/{core → _v0/core}/_constants.py +5 -3
  137. cognite/neat/_v0/core/_data_model/__init__.py +0 -0
  138. cognite/neat/{core → _v0/core}/_data_model/_constants.py +7 -0
  139. cognite/neat/{core → _v0/core}/_data_model/_shared.py +4 -4
  140. cognite/neat/{core → _v0/core}/_data_model/analysis/_base.py +8 -8
  141. cognite/neat/{core → _v0/core}/_data_model/exporters/__init__.py +1 -2
  142. cognite/neat/{core → _v0/core}/_data_model/exporters/_base.py +7 -7
  143. cognite/neat/{core → _v0/core}/_data_model/exporters/_data_model2dms.py +9 -9
  144. cognite/neat/{core → _v0/core}/_data_model/exporters/_data_model2excel.py +12 -12
  145. cognite/neat/{core → _v0/core}/_data_model/exporters/_data_model2instance_template.py +4 -4
  146. cognite/neat/{core/_data_model/exporters/_data_model2ontology.py → _v0/core/_data_model/exporters/_data_model2semantic_model.py} +126 -116
  147. cognite/neat/{core → _v0/core}/_data_model/exporters/_data_model2yaml.py +1 -1
  148. cognite/neat/{core → _v0/core}/_data_model/importers/_base.py +5 -5
  149. cognite/neat/{core → _v0/core}/_data_model/importers/_base_file_reader.py +2 -2
  150. cognite/neat/{core → _v0/core}/_data_model/importers/_dict2data_model.py +5 -5
  151. cognite/neat/{core → _v0/core}/_data_model/importers/_dms2data_model.py +18 -15
  152. cognite/neat/{core → _v0/core}/_data_model/importers/_graph2data_model.py +12 -12
  153. cognite/neat/{core → _v0/core}/_data_model/importers/_rdf/_base.py +12 -12
  154. cognite/neat/{core → _v0/core}/_data_model/importers/_rdf/_inference2rdata_model.py +14 -14
  155. cognite/neat/_v0/core/_data_model/importers/_rdf/_owl2data_model.py +144 -0
  156. cognite/neat/{core → _v0/core}/_data_model/importers/_rdf/_shared.py +17 -13
  157. cognite/neat/{core → _v0/core}/_data_model/importers/_spreadsheet2data_model.py +92 -12
  158. cognite/neat/{core → _v0/core}/_data_model/models/__init__.py +3 -3
  159. cognite/neat/{core → _v0/core}/_data_model/models/_base_verified.py +5 -5
  160. cognite/neat/{core → _v0/core}/_data_model/models/_import_contexts.py +1 -1
  161. cognite/neat/{core → _v0/core}/_data_model/models/_types.py +5 -5
  162. cognite/neat/{core → _v0/core}/_data_model/models/conceptual/_unverified.py +16 -10
  163. cognite/neat/{core → _v0/core}/_data_model/models/conceptual/_validation.py +12 -12
  164. cognite/neat/{core → _v0/core}/_data_model/models/conceptual/_verified.py +9 -9
  165. cognite/neat/{core → _v0/core}/_data_model/models/data_types.py +14 -4
  166. cognite/neat/{core → _v0/core}/_data_model/models/entities/__init__.py +6 -0
  167. cognite/neat/_v0/core/_data_model/models/entities/_loaders.py +155 -0
  168. cognite/neat/{core → _v0/core}/_data_model/models/entities/_multi_value.py +2 -2
  169. cognite/neat/_v0/core/_data_model/models/entities/_restrictions.py +230 -0
  170. cognite/neat/{core → _v0/core}/_data_model/models/entities/_single_value.py +121 -16
  171. cognite/neat/{core → _v0/core}/_data_model/models/entities/_types.py +10 -0
  172. cognite/neat/{core → _v0/core}/_data_model/models/mapping/_classic2core.py +5 -5
  173. cognite/neat/{core → _v0/core}/_data_model/models/physical/__init__.py +1 -1
  174. cognite/neat/{core → _v0/core}/_data_model/models/physical/_exporter.py +26 -19
  175. cognite/neat/{core → _v0/core}/_data_model/models/physical/_unverified.py +133 -37
  176. cognite/neat/{core → _v0/core}/_data_model/models/physical/_validation.py +24 -20
  177. cognite/neat/{core → _v0/core}/_data_model/models/physical/_verified.py +95 -24
  178. cognite/neat/{core → _v0/core}/_data_model/transformers/_base.py +4 -4
  179. cognite/neat/{core → _v0/core}/_data_model/transformers/_converters.py +35 -28
  180. cognite/neat/{core → _v0/core}/_data_model/transformers/_mapping.py +7 -7
  181. cognite/neat/{core → _v0/core}/_data_model/transformers/_union_conceptual.py +5 -5
  182. cognite/neat/{core → _v0/core}/_data_model/transformers/_verification.py +7 -7
  183. cognite/neat/_v0/core/_instances/__init__.py +0 -0
  184. cognite/neat/{core → _v0/core}/_instances/_tracking/base.py +1 -1
  185. cognite/neat/{core → _v0/core}/_instances/_tracking/log.py +1 -1
  186. cognite/neat/{core → _v0/core}/_instances/extractors/__init__.py +3 -2
  187. cognite/neat/{core → _v0/core}/_instances/extractors/_base.py +6 -6
  188. cognite/neat/_v0/core/_instances/extractors/_classic_cdf/__init__.py +0 -0
  189. cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_base.py +7 -7
  190. cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_classic.py +12 -12
  191. cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_relationships.py +3 -3
  192. cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_sequences.py +2 -2
  193. cognite/neat/{core → _v0/core}/_instances/extractors/_dict.py +6 -3
  194. cognite/neat/{core → _v0/core}/_instances/extractors/_dms.py +6 -6
  195. cognite/neat/{core → _v0/core}/_instances/extractors/_dms_graph.py +11 -11
  196. cognite/neat/{core → _v0/core}/_instances/extractors/_mock_graph_generator.py +10 -10
  197. cognite/neat/{core → _v0/core}/_instances/extractors/_raw.py +3 -3
  198. cognite/neat/{core → _v0/core}/_instances/extractors/_rdf_file.py +7 -7
  199. cognite/neat/{core → _v0/core}/_instances/loaders/_base.py +5 -5
  200. cognite/neat/{core → _v0/core}/_instances/loaders/_rdf2dms.py +17 -17
  201. cognite/neat/{core → _v0/core}/_instances/loaders/_rdf_to_instance_space.py +11 -11
  202. cognite/neat/{core → _v0/core}/_instances/queries/_select.py +29 -3
  203. cognite/neat/{core → _v0/core}/_instances/queries/_update.py +1 -1
  204. cognite/neat/{core → _v0/core}/_instances/transformers/_base.py +4 -4
  205. cognite/neat/{core → _v0/core}/_instances/transformers/_classic_cdf.py +6 -6
  206. cognite/neat/{core → _v0/core}/_instances/transformers/_prune_graph.py +4 -4
  207. cognite/neat/{core → _v0/core}/_instances/transformers/_rdfpath.py +1 -1
  208. cognite/neat/{core → _v0/core}/_instances/transformers/_value_type.py +4 -4
  209. cognite/neat/{core → _v0/core}/_issues/_base.py +5 -5
  210. cognite/neat/{core → _v0/core}/_issues/_contextmanagers.py +1 -1
  211. cognite/neat/{core → _v0/core}/_issues/_factory.py +3 -3
  212. cognite/neat/{core → _v0/core}/_issues/errors/__init__.py +1 -1
  213. cognite/neat/{core → _v0/core}/_issues/errors/_external.py +1 -1
  214. cognite/neat/{core → _v0/core}/_issues/errors/_general.py +1 -1
  215. cognite/neat/{core → _v0/core}/_issues/errors/_properties.py +1 -1
  216. cognite/neat/{core → _v0/core}/_issues/errors/_resources.py +2 -2
  217. cognite/neat/{core → _v0/core}/_issues/errors/_wrapper.py +7 -3
  218. cognite/neat/{core → _v0/core}/_issues/warnings/__init__.py +1 -1
  219. cognite/neat/{core → _v0/core}/_issues/warnings/_external.py +1 -1
  220. cognite/neat/{core → _v0/core}/_issues/warnings/_general.py +1 -1
  221. cognite/neat/{core → _v0/core}/_issues/warnings/_models.py +2 -2
  222. cognite/neat/{core → _v0/core}/_issues/warnings/_properties.py +2 -2
  223. cognite/neat/{core → _v0/core}/_issues/warnings/_resources.py +1 -1
  224. cognite/neat/{core → _v0/core}/_issues/warnings/user_modeling.py +1 -1
  225. cognite/neat/{core → _v0/core}/_store/_data_model.py +12 -12
  226. cognite/neat/{core → _v0/core}/_store/_instance.py +43 -10
  227. cognite/neat/{core → _v0/core}/_store/_provenance.py +3 -3
  228. cognite/neat/{core → _v0/core}/_store/exceptions.py +4 -4
  229. cognite/neat/_v0/core/_utils/__init__.py +0 -0
  230. cognite/neat/{core → _v0/core}/_utils/auth.py +22 -12
  231. cognite/neat/{core → _v0/core}/_utils/auxiliary.py +1 -1
  232. cognite/neat/{core → _v0/core}/_utils/collection_.py +2 -2
  233. cognite/neat/{core → _v0/core}/_utils/graph_transformations_report.py +1 -1
  234. cognite/neat/{core → _v0/core}/_utils/rdf_.py +1 -1
  235. cognite/neat/{core → _v0/core}/_utils/reader/_base.py +1 -1
  236. cognite/neat/{core → _v0/core}/_utils/spreadsheet.py +18 -4
  237. cognite/neat/{core → _v0/core}/_utils/text.py +1 -1
  238. cognite/neat/{core → _v0/core}/_utils/upload.py +3 -3
  239. cognite/neat/{session → _v0}/engine/_load.py +1 -1
  240. cognite/neat/_v0/plugins/__init__.py +4 -0
  241. cognite/neat/_v0/plugins/_base.py +9 -0
  242. cognite/neat/_v0/plugins/_data_model.py +48 -0
  243. cognite/neat/{plugins → _v0/plugins}/_issues.py +1 -1
  244. cognite/neat/{plugins → _v0/plugins}/_manager.py +7 -16
  245. cognite/neat/{session → _v0/session}/_base.py +13 -15
  246. cognite/neat/{session → _v0/session}/_collector.py +1 -1
  247. cognite/neat/_v0/session/_diff.py +51 -0
  248. cognite/neat/{session → _v0/session}/_drop.py +3 -3
  249. cognite/neat/{session → _v0/session}/_explore.py +2 -2
  250. cognite/neat/{session → _v0/session}/_fix.py +2 -2
  251. cognite/neat/{session → _v0/session}/_inspect.py +3 -3
  252. cognite/neat/{session → _v0/session}/_mapping.py +3 -3
  253. cognite/neat/{session → _v0/session}/_plugin.py +4 -5
  254. cognite/neat/{session → _v0/session}/_prepare.py +8 -8
  255. cognite/neat/{session → _v0/session}/_read.py +34 -21
  256. cognite/neat/{session → _v0/session}/_set.py +8 -8
  257. cognite/neat/{session → _v0/session}/_show.py +5 -5
  258. cognite/neat/{session → _v0/session}/_state.py +10 -10
  259. cognite/neat/{session → _v0/session}/_subset.py +4 -4
  260. cognite/neat/{session → _v0/session}/_template.py +11 -11
  261. cognite/neat/{session → _v0/session}/_to.py +12 -12
  262. cognite/neat/{session → _v0/session}/_wizard.py +1 -1
  263. cognite/neat/{session → _v0/session}/exceptions.py +5 -5
  264. cognite/neat/_version.py +1 -1
  265. cognite/neat/legacy.py +6 -0
  266. cognite_neat-1.0.22.dist-info/METADATA +123 -0
  267. cognite_neat-1.0.22.dist-info/RECORD +329 -0
  268. cognite_neat-1.0.22.dist-info/WHEEL +4 -0
  269. cognite/neat/core/_data_model/importers/_rdf/_owl2data_model.py +0 -91
  270. cognite/neat/core/_data_model/models/entities/_loaders.py +0 -75
  271. cognite/neat/plugins/__init__.py +0 -3
  272. cognite/neat/plugins/data_model/importers/__init__.py +0 -5
  273. cognite/neat/plugins/data_model/importers/_base.py +0 -28
  274. cognite/neat/session/_session/_data_model/__init__.py +0 -3
  275. cognite/neat/session/_session/_data_model/_read.py +0 -193
  276. cognite/neat/session/_session/_data_model/_routes.py +0 -45
  277. cognite/neat/session/_session/_data_model/_show.py +0 -147
  278. cognite/neat/session/_session/_data_model/_write.py +0 -335
  279. cognite_neat-0.123.24.dist-info/METADATA +0 -144
  280. cognite_neat-0.123.24.dist-info/RECORD +0 -201
  281. cognite_neat-0.123.24.dist-info/WHEEL +0 -4
  282. cognite_neat-0.123.24.dist-info/licenses/LICENSE +0 -201
  283. /cognite/neat/{core → _client/init}/__init__.py +0 -0
  284. /cognite/neat/{core/_client/_api → _data_model}/__init__.py +0 -0
  285. /cognite/neat/{core/_client/data_classes → _data_model/deployer}/__init__.py +0 -0
  286. /cognite/neat/{core/_data_model → _data_model/exporters/_table_exporter}/__init__.py +0 -0
  287. /cognite/neat/{core/_instances → _data_model/importers/_table_importer}/__init__.py +0 -0
  288. /cognite/neat/{core/_instances/extractors/_classic_cdf → _data_model/models}/__init__.py +0 -0
  289. /cognite/neat/{core/_utils → _data_model/models/conceptual}/__init__.py +0 -0
  290. /cognite/neat/{plugins/data_model → _data_model/validation}/__init__.py +0 -0
  291. /cognite/neat/{session/_session → _session/_html}/__init__.py +0 -0
  292. /cognite/neat/{core → _v0/core}/_client/__init__.py +0 -0
  293. /cognite/neat/{core → _v0/core}/_client/data_classes/data_modeling.py +0 -0
  294. /cognite/neat/{core → _v0/core}/_client/data_classes/neat_sequence.py +0 -0
  295. /cognite/neat/{core → _v0/core}/_client/data_classes/statistics.py +0 -0
  296. /cognite/neat/{core → _v0/core}/_config.py +0 -0
  297. /cognite/neat/{core → _v0/core}/_data_model/analysis/__init__.py +0 -0
  298. /cognite/neat/{core → _v0/core}/_data_model/catalog/__init__.py +0 -0
  299. /cognite/neat/{core → _v0/core}/_data_model/catalog/classic_model.xlsx +0 -0
  300. /cognite/neat/{core → _v0/core}/_data_model/catalog/conceptual-imf-data-model.xlsx +0 -0
  301. /cognite/neat/{core → _v0/core}/_data_model/catalog/hello_world_pump.xlsx +0 -0
  302. /cognite/neat/{core → _v0/core}/_data_model/importers/__init__.py +0 -0
  303. /cognite/neat/{core → _v0/core}/_data_model/importers/_rdf/__init__.py +0 -0
  304. /cognite/neat/{core → _v0/core}/_data_model/models/_base_unverified.py +0 -0
  305. /cognite/neat/{core → _v0/core}/_data_model/models/conceptual/__init__.py +0 -0
  306. /cognite/neat/{core → _v0/core}/_data_model/models/entities/_constants.py +0 -0
  307. /cognite/neat/{core → _v0/core}/_data_model/models/entities/_wrapped.py +0 -0
  308. /cognite/neat/{core → _v0/core}/_data_model/models/mapping/__init__.py +0 -0
  309. /cognite/neat/{core → _v0/core}/_data_model/models/mapping/_classic2core.yaml +0 -0
  310. /cognite/neat/{core → _v0/core}/_data_model/transformers/__init__.py +0 -0
  311. /cognite/neat/{core → _v0/core}/_instances/_shared.py +0 -0
  312. /cognite/neat/{core → _v0/core}/_instances/_tracking/__init__.py +0 -0
  313. /cognite/neat/{core → _v0/core}/_instances/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -0
  314. /cognite/neat/{core → _v0/core}/_instances/examples/Knowledge-Graph-Nordic44.xml +0 -0
  315. /cognite/neat/{core → _v0/core}/_instances/examples/__init__.py +0 -0
  316. /cognite/neat/{core → _v0/core}/_instances/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
  317. /cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_assets.py +0 -0
  318. /cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_data_sets.py +0 -0
  319. /cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_events.py +0 -0
  320. /cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_files.py +0 -0
  321. /cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_labels.py +0 -0
  322. /cognite/neat/{core → _v0/core}/_instances/extractors/_classic_cdf/_timeseries.py +0 -0
  323. /cognite/neat/{core → _v0/core}/_instances/loaders/__init__.py +0 -0
  324. /cognite/neat/{core → _v0/core}/_instances/queries/__init__.py +0 -0
  325. /cognite/neat/{core → _v0/core}/_instances/queries/_base.py +0 -0
  326. /cognite/neat/{core → _v0/core}/_instances/queries/_queries.py +0 -0
  327. /cognite/neat/{core → _v0/core}/_instances/transformers/__init__.py +0 -0
  328. /cognite/neat/{core → _v0/core}/_issues/__init__.py +0 -0
  329. /cognite/neat/{core → _v0/core}/_issues/formatters.py +0 -0
  330. /cognite/neat/{core → _v0/core}/_shared.py +0 -0
  331. /cognite/neat/{core → _v0/core}/_store/__init__.py +0 -0
  332. /cognite/neat/{core → _v0/core}/_utils/io_.py +0 -0
  333. /cognite/neat/{core → _v0/core}/_utils/reader/__init__.py +0 -0
  334. /cognite/neat/{core → _v0/core}/_utils/tarjan.py +0 -0
  335. /cognite/neat/{core → _v0/core}/_utils/time_.py +0 -0
  336. /cognite/neat/{core → _v0/core}/_utils/xml_.py +0 -0
  337. /cognite/neat/{session → _v0}/engine/__init__.py +0 -0
  338. /cognite/neat/{session → _v0}/engine/_import.py +0 -0
  339. /cognite/neat/{session → _v0}/engine/_interface.py +0 -0
  340. /cognite/neat/{session → _v0/session}/__init__.py +0 -0
  341. /cognite/neat/{session → _v0/session}/_experimental.py +0 -0
  342. /cognite/neat/{session → _v0/session}/_state/README.md +0 -0
@@ -0,0 +1,344 @@
1
+ from collections.abc import Mapping
2
+ from typing import Annotated, Literal, cast, get_args
3
+
4
+ from pydantic import (
5
+ AliasGenerator,
6
+ BaseModel,
7
+ BeforeValidator,
8
+ Field,
9
+ PlainSerializer,
10
+ field_validator,
11
+ model_validator,
12
+ )
13
+ from pydantic.alias_generators import to_camel
14
+ from pydantic.fields import FieldInfo
15
+ from traitlets import Any
16
+
17
+ from cognite.neat._data_model.models.entities import ParsedEntity, parse_entities, parse_entity
18
+ from cognite.neat._utils.text import title_case
19
+ from cognite.neat._utils.useful_types import CellValueType
20
+
21
+ # This marker is used to identify creator in the description field.
22
+ CREATOR_MARKER = "Creator: "
23
+ CREATOR_KEY = "creator"
24
+
25
+
26
+ def parse_entity_str(v: str) -> ParsedEntity:
27
+ if isinstance(v, ParsedEntity):
28
+ return v
29
+ try:
30
+ return parse_entity(v)
31
+ except ValueError as e:
32
+ raise ValueError(f"Invalid entity syntax: {e}") from e
33
+
34
+
35
+ def parse_entities_str(v: str) -> list[ParsedEntity] | None:
36
+ if isinstance(v, list) and all(isinstance(item, ParsedEntity) for item in v):
37
+ return v
38
+ try:
39
+ return parse_entities(v)
40
+ except ValueError as e:
41
+ raise ValueError(f"Invalid entity list syntax: {e}") from e
42
+
43
+
44
+ Entity = Annotated[ParsedEntity, BeforeValidator(parse_entity_str, str), PlainSerializer(func=str)]
45
+ EntityList = Annotated[
46
+ list[ParsedEntity],
47
+ BeforeValidator(parse_entities_str, str),
48
+ PlainSerializer(func=lambda v: ",".join([str(item) for item in v])),
49
+ ]
50
+
51
+
52
+ class TableObj(
53
+ BaseModel,
54
+ extra="ignore",
55
+ alias_generator=AliasGenerator(
56
+ alias=to_camel,
57
+ validation_alias=title_case,
58
+ serialization_alias=title_case,
59
+ ),
60
+ populate_by_name=True,
61
+ ): ...
62
+
63
+
64
+ class MetadataValue(TableObj):
65
+ key: str
66
+ value: CellValueType
67
+
68
+ @field_validator("key", mode="after")
69
+ def _legacy_external_id(cls, value: str) -> str:
70
+ return "externalId" if value.lower() == "external_id" else value
71
+
72
+
73
+ class DMSProperty(TableObj):
74
+ view: Entity
75
+ view_property: str
76
+ name: str | None = None
77
+ description: str | None = None
78
+ connection: Entity | None
79
+ value_type: Entity
80
+ min_count: int | None
81
+ max_count: int | None
82
+ immutable: bool | None = None
83
+ default: CellValueType | None = None
84
+ auto_increment: bool | None = None
85
+ container: Entity | None = None
86
+ container_property: str | None = None
87
+ container_property_name: str | None = None
88
+ container_property_description: str | None = None
89
+ index: EntityList | None = None
90
+ constraint: EntityList | None = None
91
+
92
+ @field_validator("max_count", mode="before")
93
+ @classmethod
94
+ def _legacy_max_count(cls, value: Any) -> Any | None:
95
+ """Validates and converts the max_count field if it uses the legacy 'inf' value."""
96
+ if isinstance(value, str) and value.lower() == "inf":
97
+ return None
98
+ return value
99
+
100
+ @model_validator(mode="before")
101
+ def _legacy_cardinality(cls, data: dict[str, Any]) -> dict[str, Any]:
102
+ """Converts Is List to Max Count and Nullable to Min Count."""
103
+ if not data:
104
+ return data
105
+
106
+ if "Max Count" not in data and "Is List" in data:
107
+ is_list = data.pop("Is List")
108
+ if isinstance(is_list, bool):
109
+ data["Max Count"] = None if is_list else 1
110
+
111
+ if "Min Count" not in data and "Nullable" in data:
112
+ nullable = data.pop("Nullable")
113
+ if isinstance(nullable, bool):
114
+ data["Min Count"] = 0 if nullable else 1
115
+
116
+ return data
117
+
118
+ @model_validator(mode="after")
119
+ def _legacy_index(self) -> "DMSProperty":
120
+ """Converts Is List to Max Count and Nullable to Min Count."""
121
+ if not self.index:
122
+ return self
123
+
124
+ for index in self.index:
125
+ if not index.prefix:
126
+ index.prefix = "inverted" if not self.max_count or self.max_count > 1 else "btree"
127
+
128
+ return self
129
+
130
+ @model_validator(mode="after")
131
+ def _legacy_constraint(self) -> "DMSProperty":
132
+ """Converts Is List to Max Count and Nullable to Min Count."""
133
+ if not self.constraint:
134
+ return self
135
+
136
+ for constraint in self.constraint:
137
+ if not constraint.prefix:
138
+ constraint.prefix = "uniqueness"
139
+
140
+ return self
141
+
142
+
143
+ class EntityTableFilter(BaseModel):
144
+ """These are special formats that Neat Table format supports for filters."""
145
+
146
+ type: Literal["hasData", "nodeType"]
147
+ entities: EntityList
148
+
149
+ def __str__(self) -> str:
150
+ entities_str = ",".join(str(entity) for entity in self.entities)
151
+ return f"{self.type}({entities_str})"
152
+
153
+
154
+ class RAWFilterTableFilter(BaseModel):
155
+ """This is a generic filter that holds raw JSON filter."""
156
+
157
+ type: Literal["rawFilter"] = "rawFilter"
158
+ filter: str
159
+
160
+ def __str__(self) -> str:
161
+ return f"rawFilter({self.filter})"
162
+
163
+
164
+ def _parse_table_filter(v: str) -> dict[str, str] | EntityTableFilter | RAWFilterTableFilter:
165
+ if isinstance(v, EntityTableFilter | RAWFilterTableFilter):
166
+ return v
167
+ filter_configs = {
168
+ "hasdata(": ("hasData", "entities"),
169
+ "nodetype(": ("nodeType", "entities"),
170
+ "rawfilter(": ("rawFilter", "filter"),
171
+ }
172
+ v_lowered = v.casefold()
173
+ for prefix, (filter_type, field_name) in filter_configs.items():
174
+ if v_lowered.startswith(prefix) and v_lowered.endswith(")"):
175
+ return {"type": filter_type, field_name: v[len(prefix) : -1]}
176
+ # Fallback to raw filter with the whole string
177
+ return {"type": "rawFilter", "filter": v}
178
+
179
+
180
+ TableViewFilter = Annotated[
181
+ EntityTableFilter | RAWFilterTableFilter,
182
+ Field(discriminator="type"),
183
+ BeforeValidator(_parse_table_filter, str),
184
+ PlainSerializer(func=str),
185
+ ]
186
+
187
+
188
+ class DMSView(TableObj):
189
+ view: Entity
190
+ name: str | None = None
191
+ description: str | None = None
192
+ implements: EntityList | None = None
193
+ filter: TableViewFilter | None = None
194
+ in_model: bool | None = Field(None, exclude=True, description="Legacy column")
195
+
196
+
197
+ class DMSContainer(TableObj):
198
+ container: Entity
199
+ name: str | None = None
200
+ description: str | None = None
201
+ constraint: EntityList | None = None
202
+ used_for: str | None = None
203
+
204
+ @model_validator(mode="after")
205
+ def _legacy_constraint(self) -> "DMSContainer":
206
+ """Converts legacy constraint formats to the current standard."""
207
+ if not self.constraint:
208
+ return self
209
+
210
+ for constraint in self.constraint:
211
+ # Skip if already in correct format or being wrong but not legacy
212
+ if constraint.prefix == "requires" or constraint.properties:
213
+ continue
214
+
215
+ # This part handles legacy constraints
216
+ if not constraint.prefix:
217
+ constraint.prefix = "requires"
218
+ constraint.properties = {"require": constraint.suffix}
219
+
220
+ else:
221
+ container_space = constraint.prefix
222
+ container_external_id = constraint.suffix
223
+ constraint.prefix = "requires"
224
+ constraint.suffix = f"{container_space}_{container_external_id}"
225
+ constraint.properties = {"require": f"{container_space}:{container_external_id}"}
226
+
227
+ return self
228
+
229
+
230
+ class DMSEnum(TableObj):
231
+ collection: str
232
+ value: str
233
+ name: str | None = None
234
+ description: str | None = None
235
+
236
+
237
+ class DMSNode(TableObj):
238
+ node: Entity
239
+
240
+
241
+ class TableDMS(TableObj):
242
+ metadata: list[MetadataValue]
243
+ properties: list[DMSProperty]
244
+ views: list[DMSView]
245
+ containers: list[DMSContainer] = Field(default_factory=list)
246
+ enum: list[DMSEnum] = Field(default_factory=list)
247
+ nodes: list[DMSNode] = Field(default_factory=list)
248
+
249
+ @model_validator(mode="before")
250
+ def _title_case_keys(
251
+ cls, data: dict[str, list[dict[str, CellValueType]]]
252
+ ) -> dict[str, list[dict[str, CellValueType]]]:
253
+ if isinstance(data, dict):
254
+ # We are case-insensitive on the table names.
255
+ return {title_case(k): v for k, v in data.items()}
256
+ return data
257
+
258
+ @model_validator(mode="after")
259
+ def _drop_in_model_false_views_definitions(self) -> "TableDMS":
260
+ """These method is used to drop definition of legacy views which have In Model column set to False
261
+ We need to drop these views from Views sheet and also drop their properties from Properties sheet.
262
+ """
263
+
264
+ views_to_drop: set[Entity] = set()
265
+ for view in self.views:
266
+ if isinstance(view.in_model, bool) and not view.in_model:
267
+ views_to_drop.add(view.view)
268
+
269
+ if not views_to_drop:
270
+ return self
271
+
272
+ print(
273
+ "You are using legacy `In Model` column which is no longer in use!"
274
+ f"\nTotal of {len(views_to_drop)} views has `In Model` set to False."
275
+ f"\nThese views and their property definitions will be dropped from the session!"
276
+ )
277
+
278
+ self.views = [view for view in self.views if view.view not in views_to_drop]
279
+ self.properties = [prop for prop in self.properties if prop.view not in views_to_drop]
280
+
281
+ return self
282
+
283
+ @classmethod
284
+ def get_sheet_columns(
285
+ cls, sheet_id: str, sheet: FieldInfo | None = None, *, column_type: Literal["all", "required"] = "required"
286
+ ) -> list[str]:
287
+ if sheet_id not in cls.model_fields.keys():
288
+ raise KeyError(f"Invalid field id: {sheet_id}")
289
+ if sheet is None:
290
+ sheet = cls.model_fields[sheet_id]
291
+ return [
292
+ # We know all fields has validation_alias because of the alias_generator in TableDMS
293
+ cast(str, sheet_field.validation_alias)
294
+ # All the fields in the sheet's model are lists.
295
+ for sheet_field in get_args(sheet.annotation)[0].model_fields.values()
296
+ if sheet_field.is_required() or column_type == "all"
297
+ ]
298
+
299
+ @classmethod
300
+ def get_sheet_column_by_name(
301
+ cls, sheet_name: str, *, column_type: Literal["all", "required"] = "required"
302
+ ) -> list[str]:
303
+ for field_id, field_ in cls.model_fields.items():
304
+ if cast(str, field_.validation_alias) == sheet_name:
305
+ return cls.get_sheet_columns(field_id, field_, column_type=column_type)
306
+ raise KeyError(f"Invalid field alias: {sheet_name}")
307
+
308
+ @classmethod
309
+ def required_sheets(cls) -> set[str]:
310
+ return {cast(str, field_.validation_alias) for field_ in cls.model_fields.values() if field_.is_required()}
311
+
312
+
313
+ DMS_API_MAPPING: Mapping[str, Mapping[str, str]] = {
314
+ "Views": {
315
+ "space": "View",
316
+ "externalId": "View",
317
+ "version": "View",
318
+ **{
319
+ cast(str, field_.alias): cast(str, field_.validation_alias)
320
+ for field_id, field_ in DMSView.model_fields.items()
321
+ if field_id != "View"
322
+ },
323
+ },
324
+ "Containers": {
325
+ "space": "Container",
326
+ "externalId": "Container",
327
+ **{
328
+ cast(str, field_.alias): cast(str, field_.validation_alias)
329
+ for field_id, field_ in DMSContainer.model_fields.items()
330
+ if field_id != "Container"
331
+ },
332
+ },
333
+ "Properties": {
334
+ "space": "View",
335
+ "externalId": "View",
336
+ "property": "ViewProperty",
337
+ "type": "Value Type",
338
+ **{
339
+ cast(str, field_.alias): cast(str, field_.validation_alias)
340
+ for field_id, field_ in DMSProperty.model_fields.items()
341
+ if field_id not in ("View", "ViewProperty")
342
+ },
343
+ },
344
+ }
@@ -0,0 +1,192 @@
1
+ import warnings
2
+ from collections.abc import Mapping
3
+ from pathlib import Path
4
+ from typing import ClassVar, cast
5
+
6
+ import yaml
7
+ from openpyxl import load_workbook
8
+ from openpyxl.worksheet.worksheet import Worksheet
9
+ from pydantic import ValidationError
10
+
11
+ from cognite.neat._data_model.importers._base import DMSImporter
12
+ from cognite.neat._data_model.models.dms import (
13
+ RequestSchema,
14
+ )
15
+ from cognite.neat._exceptions import DataModelImportException
16
+ from cognite.neat._issues import ModelSyntaxError
17
+ from cognite.neat._utils.text import humanize_collection
18
+ from cognite.neat._utils.useful_types import CellValueType, DataModelTableType
19
+ from cognite.neat._utils.validation import ValidationContext, as_json_path, humanize_validation_error
20
+
21
+ from .data_classes import MetadataValue, TableDMS
22
+ from .reader import DMSTableReader
23
+ from .source import SpreadsheetReadContext, TableSource
24
+
25
+
26
+ class DMSTableImporter(DMSImporter):
27
+ """Imports DMS from a table structure.
28
+
29
+ The tables can are expected to be a dictionary where the keys are the table names and the values
30
+ are lists of dictionaries representing the rows in the table.
31
+ """
32
+
33
+ # We can safely cast as we know the validation_alias is always set to a str.
34
+ REQUIRED_SHEETS = tuple(
35
+ cast(str, field_.validation_alias) for field_ in TableDMS.model_fields.values() if field_.is_required()
36
+ )
37
+ REQUIRED_SHEET_MESSAGES: ClassVar[Mapping[str, str]] = {
38
+ f"Missing required column: {sheet!r}": f"Missing required sheet: {sheet!r}" for sheet in REQUIRED_SHEETS
39
+ }
40
+ MetadataSheet = cast(str, TableDMS.model_fields["metadata"].validation_alias)
41
+
42
+ def __init__(self, tables: DataModelTableType, source: TableSource | None = None) -> None:
43
+ self._table = tables
44
+ self._source = source or TableSource("Unknown")
45
+
46
+ def to_data_model(self) -> RequestSchema:
47
+ tables = self._read_tables()
48
+
49
+ space, version = self._read_defaults(tables.metadata)
50
+ reader = DMSTableReader(space, version, self._source)
51
+ return reader.read_tables(tables)
52
+
53
+ @classmethod
54
+ def from_yaml(cls, yaml_file: Path) -> "DMSTableImporter":
55
+ """Create a DMSTableImporter from a YAML file."""
56
+ source = cls._display_name(yaml_file)
57
+ return cls(yaml.safe_load(yaml_file.read_text()), TableSource(source.as_posix()))
58
+
59
+ @classmethod
60
+ def from_json(cls, json_file: Path) -> "DMSTableImporter":
61
+ """Create a DMSTableImporter from a JSON file."""
62
+ return cls.from_yaml(json_file)
63
+
64
+ @classmethod
65
+ def from_excel(cls, excel_file: Path) -> "DMSTableImporter":
66
+ """Create a DMSTableImporter from an Excel file."""
67
+ tables: DataModelTableType = {}
68
+ source = TableSource(cls._display_name(excel_file).as_posix())
69
+ workbook = load_workbook(excel_file, read_only=True, data_only=True, rich_text=False)
70
+ try:
71
+ for column_id, column_info in TableDMS.model_fields.items():
72
+ sheet_name = cast(str, column_info.validation_alias)
73
+ if sheet_name not in workbook.sheetnames:
74
+ continue
75
+ required_columns = TableDMS.get_sheet_columns(column_id, column_info, column_type="required")
76
+ sheet = workbook[sheet_name]
77
+ context = SpreadsheetReadContext()
78
+ table_rows = cls._read_rows(sheet, required_columns, context)
79
+ tables[sheet_name] = table_rows
80
+ source.table_read[sheet_name] = context
81
+ return cls(tables, source)
82
+ finally:
83
+ workbook.close()
84
+
85
+ def _read_tables(self) -> TableDMS:
86
+ try:
87
+ # Check tables, columns, data type and entity syntax.
88
+ table = TableDMS.model_validate(self._table)
89
+ except ValidationError as e:
90
+ errors = self._create_error_messages(e)
91
+ raise DataModelImportException(errors) from None
92
+ return table
93
+
94
+ def _create_error_messages(self, error: ValidationError) -> list[ModelSyntaxError]:
95
+ errors: list[ModelSyntaxError] = []
96
+ context = ValidationContext(
97
+ humanize_location=self._location,
98
+ field_name="column",
99
+ missing_required_descriptor="missing",
100
+ )
101
+ seen: set[str] = set()
102
+
103
+ for error_details in error.errors(include_input=True, include_url=False):
104
+ message = humanize_validation_error(error_details, context)
105
+ # Replace messages about missing required columns with missing required sheets.
106
+ message = self.REQUIRED_SHEET_MESSAGES.get(message, message)
107
+ if message in seen:
108
+ # We treat all rows as the same, so we get duplicated errors for each row.
109
+ continue
110
+
111
+ seen.add(message)
112
+ errors.append(ModelSyntaxError(message=message))
113
+
114
+ return errors
115
+
116
+ def _location(self, loc: tuple[str | int, ...]) -> str:
117
+ if isinstance(loc[0], str) and len(loc) == 2: # Sheet + row.
118
+ # We skip the row as we treat all rows as the same. For example, if a required column is missing in one
119
+ # row, it is missing in all rows.
120
+ return f"{loc[0]} sheet"
121
+ elif len(loc) == 3 and isinstance(loc[0], str) and isinstance(loc[1], int) and isinstance(loc[2], str):
122
+ # This means there is something wrong in a specific cell.
123
+
124
+ sheet = loc[0]
125
+ row = loc[1]
126
+ if self._source and sheet in self._source.table_read:
127
+ context = self._source.table_read[sheet]
128
+ row = context.adjusted_row_number(row) - 1
129
+
130
+ return f"{sheet} sheet row {row + 1} column {loc[2]!r}"
131
+ # This should be unreachable as the TableDMS model only has 2 levels.
132
+ return as_json_path(loc)
133
+
134
+ @staticmethod
135
+ def _read_defaults(metadata: list[MetadataValue]) -> tuple[str, str]:
136
+ """Reads the space and version from the metadata table."""
137
+ default_space: str | None = None
138
+ default_version: str | None = None
139
+ missing = {"space", "version"}
140
+ for meta in metadata:
141
+ if meta.key == "space":
142
+ default_space = str(meta.value)
143
+ missing.remove("space")
144
+ elif meta.key == "version":
145
+ default_version = str(meta.value)
146
+ missing.remove("version")
147
+ if missing:
148
+ error = ModelSyntaxError(message=f"In Metadata missing required values: {humanize_collection(missing)}")
149
+ # If space or version is missing, we cannot continue parsing the model as these are used as defaults.
150
+ raise DataModelImportException([error]) from None
151
+ return str(default_space), str(default_version)
152
+
153
+ @classmethod
154
+ def _display_name(cls, filepath: Path) -> Path:
155
+ """Get a display-friendly version of the file path."""
156
+ cwd = Path.cwd()
157
+ source = filepath
158
+ if filepath.is_relative_to(cwd):
159
+ source = filepath.relative_to(cwd)
160
+ return source
161
+
162
+ @classmethod
163
+ def _read_rows(
164
+ cls, sheet: Worksheet, required_columns: list[str], context: SpreadsheetReadContext
165
+ ) -> list[dict[str, CellValueType]]:
166
+ table_rows: list[dict[str, CellValueType]] = []
167
+ # Metadata sheet is just a key-value pair of the first two columns.
168
+ # For other sheets, we need to find the column header row first.
169
+ columns: list[str] = [] if sheet.title != cls.MetadataSheet else required_columns
170
+ # Ignore warnings about Data Validation extension not being supported in read-only mode.
171
+ warnings.filterwarnings("ignore", category=UserWarning, message="Data Validation extension is not supported*")
172
+ # The .iter_rows with values_only=True raises the warning `UserWarning: Data Validation extension is
173
+ # not supported and will be removed`
174
+ # which confuses the user and we do not depend on data validation here, so we suppress it.
175
+ for row_no, row in enumerate(sheet.iter_rows(values_only=True)):
176
+ if columns:
177
+ # We have found the column header row, read the data rows.
178
+ if all(cell is None for cell in row):
179
+ context.empty_rows.append(row_no)
180
+ else:
181
+ record = dict(zip(columns, row, strict=False))
182
+ # MyPy complains as it thinks DataTableFormula | ArrayFormula could be cell values,
183
+ # but as we used values_only=True, this is not the case.
184
+ table_rows.append(record) # type: ignore[arg-type]
185
+ else:
186
+ # Look for the column header row.
187
+ row_values = [str(cell) for cell in row]
188
+ if set(row_values).intersection(required_columns):
189
+ columns = row_values
190
+ context.header_row = row_no
191
+
192
+ return table_rows