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.
- cognite/neat/__init__.py +2 -2
- cognite/neat/_client/__init__.py +4 -0
- cognite/neat/_client/api.py +8 -0
- cognite/neat/_client/client.py +21 -0
- cognite/neat/_client/config.py +40 -0
- cognite/neat/_client/containers_api.py +125 -0
- cognite/neat/_client/data_classes.py +44 -0
- cognite/neat/_client/data_model_api.py +115 -0
- cognite/neat/_client/spaces_api.py +115 -0
- cognite/neat/_client/statistics_api.py +24 -0
- cognite/neat/_client/views_api.py +129 -0
- cognite/neat/_config.py +185 -0
- cognite/neat/_data_model/_analysis.py +196 -0
- cognite/neat/_data_model/_constants.py +67 -0
- cognite/neat/_data_model/_identifiers.py +61 -0
- cognite/neat/_data_model/_shared.py +41 -0
- cognite/neat/_data_model/deployer/_differ.py +140 -0
- cognite/neat/_data_model/deployer/_differ_container.py +360 -0
- cognite/neat/_data_model/deployer/_differ_data_model.py +54 -0
- cognite/neat/_data_model/deployer/_differ_space.py +9 -0
- cognite/neat/_data_model/deployer/_differ_view.py +299 -0
- cognite/neat/_data_model/deployer/data_classes.py +529 -0
- cognite/neat/_data_model/deployer/deployer.py +401 -0
- cognite/neat/_data_model/exporters/__init__.py +15 -0
- cognite/neat/_data_model/exporters/_api_exporter.py +37 -0
- cognite/neat/_data_model/exporters/_base.py +24 -0
- cognite/neat/_data_model/exporters/_table_exporter/exporter.py +128 -0
- cognite/neat/_data_model/exporters/_table_exporter/workbook.py +409 -0
- cognite/neat/_data_model/exporters/_table_exporter/writer.py +421 -0
- cognite/neat/_data_model/importers/__init__.py +5 -0
- cognite/neat/_data_model/importers/_api_importer.py +166 -0
- cognite/neat/_data_model/importers/_base.py +16 -0
- cognite/neat/_data_model/importers/_table_importer/data_classes.py +295 -0
- cognite/neat/_data_model/importers/_table_importer/importer.py +192 -0
- cognite/neat/_data_model/importers/_table_importer/reader.py +1063 -0
- cognite/neat/_data_model/importers/_table_importer/source.py +94 -0
- cognite/neat/_data_model/models/conceptual/_base.py +18 -0
- cognite/neat/_data_model/models/conceptual/_concept.py +67 -0
- cognite/neat/_data_model/models/conceptual/_data_model.py +51 -0
- cognite/neat/_data_model/models/conceptual/_properties.py +104 -0
- cognite/neat/_data_model/models/conceptual/_property.py +105 -0
- cognite/neat/_data_model/models/dms/__init__.py +206 -0
- cognite/neat/_data_model/models/dms/_base.py +31 -0
- cognite/neat/_data_model/models/dms/_constants.py +48 -0
- cognite/neat/_data_model/models/dms/_constraints.py +42 -0
- cognite/neat/_data_model/models/dms/_container.py +159 -0
- cognite/neat/_data_model/models/dms/_data_model.py +95 -0
- cognite/neat/_data_model/models/dms/_data_types.py +195 -0
- cognite/neat/_data_model/models/dms/_http.py +28 -0
- cognite/neat/_data_model/models/dms/_indexes.py +30 -0
- cognite/neat/_data_model/models/dms/_limits.py +96 -0
- cognite/neat/_data_model/models/dms/_references.py +135 -0
- cognite/neat/_data_model/models/dms/_schema.py +18 -0
- cognite/neat/_data_model/models/dms/_space.py +48 -0
- cognite/neat/_data_model/models/dms/_types.py +17 -0
- cognite/neat/_data_model/models/dms/_view_filter.py +282 -0
- cognite/neat/_data_model/models/dms/_view_property.py +235 -0
- cognite/neat/_data_model/models/dms/_views.py +210 -0
- cognite/neat/_data_model/models/entities/__init__.py +50 -0
- cognite/neat/_data_model/models/entities/_base.py +101 -0
- cognite/neat/_data_model/models/entities/_constants.py +22 -0
- cognite/neat/_data_model/models/entities/_data_types.py +144 -0
- cognite/neat/_data_model/models/entities/_identifiers.py +61 -0
- cognite/neat/_data_model/models/entities/_parser.py +226 -0
- cognite/neat/_data_model/validation/dms/__init__.py +75 -0
- cognite/neat/_data_model/validation/dms/_ai_readiness.py +364 -0
- cognite/neat/_data_model/validation/dms/_base.py +307 -0
- cognite/neat/_data_model/validation/dms/_connections.py +638 -0
- cognite/neat/_data_model/validation/dms/_consistency.py +57 -0
- cognite/neat/_data_model/validation/dms/_containers.py +174 -0
- cognite/neat/_data_model/validation/dms/_limits.py +420 -0
- cognite/neat/_data_model/validation/dms/_orchestrator.py +222 -0
- cognite/neat/_data_model/validation/dms/_views.py +103 -0
- cognite/neat/_exceptions.py +56 -0
- cognite/neat/_issues.py +68 -0
- cognite/neat/_session/__init__.py +3 -0
- cognite/neat/_session/_html/_render.py +30 -0
- cognite/neat/_session/_html/static/__init__.py +8 -0
- cognite/neat/_session/_html/static/deployment.css +303 -0
- cognite/neat/_session/_html/static/deployment.js +150 -0
- cognite/neat/_session/_html/static/issues.css +211 -0
- cognite/neat/_session/_html/static/issues.js +168 -0
- cognite/neat/_session/_html/static/shared.css +186 -0
- cognite/neat/_session/_html/templates/__init__.py +4 -0
- cognite/neat/_session/_html/templates/deployment.html +75 -0
- cognite/neat/_session/_html/templates/issues.html +45 -0
- cognite/neat/_session/_issues.py +81 -0
- cognite/neat/_session/_opt.py +35 -0
- cognite/neat/_session/_physical.py +261 -0
- cognite/neat/_session/_result.py +236 -0
- cognite/neat/_session/_session.py +88 -0
- cognite/neat/_session/_usage_analytics/__init__.py +0 -0
- cognite/neat/_session/_usage_analytics/_collector.py +131 -0
- cognite/neat/_session/_usage_analytics/_constants.py +23 -0
- cognite/neat/_session/_usage_analytics/_storage.py +240 -0
- cognite/neat/_session/_wrappers.py +82 -0
- cognite/neat/_state_machine/__init__.py +10 -0
- cognite/neat/_state_machine/_base.py +37 -0
- cognite/neat/_state_machine/_states.py +52 -0
- cognite/neat/_store/__init__.py +3 -0
- cognite/neat/_store/_provenance.py +81 -0
- cognite/neat/_store/_store.py +156 -0
- cognite/neat/_utils/__init__.py +0 -0
- cognite/neat/_utils/_reader.py +194 -0
- cognite/neat/_utils/auxiliary.py +39 -0
- cognite/neat/_utils/collection.py +11 -0
- cognite/neat/_utils/http_client/__init__.py +39 -0
- cognite/neat/_utils/http_client/_client.py +245 -0
- cognite/neat/_utils/http_client/_config.py +19 -0
- cognite/neat/_utils/http_client/_data_classes.py +294 -0
- cognite/neat/_utils/http_client/_tracker.py +31 -0
- cognite/neat/_utils/text.py +71 -0
- cognite/neat/_utils/useful_types.py +37 -0
- cognite/neat/_utils/validation.py +154 -0
- cognite/neat/_version.py +1 -1
- cognite/neat/v0/__init__.py +0 -0
- cognite/neat/v0/core/__init__.py +0 -0
- cognite/neat/v0/core/_client/_api/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_client/_api/data_modeling_loaders.py +86 -7
- cognite/neat/{core → v0/core}/_client/_api/neat_instances.py +5 -5
- cognite/neat/{core → v0/core}/_client/_api/schema.py +5 -5
- cognite/neat/{core → v0/core}/_client/_api/statistics.py +3 -3
- cognite/neat/{core → v0/core}/_client/_api_client.py +1 -1
- cognite/neat/v0/core/_client/data_classes/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_client/data_classes/schema.py +4 -4
- cognite/neat/{core → v0/core}/_client/testing.py +1 -1
- cognite/neat/{core → v0/core}/_constants.py +10 -3
- cognite/neat/v0/core/_data_model/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_data_model/_constants.py +9 -6
- cognite/neat/{core → v0/core}/_data_model/_shared.py +5 -5
- cognite/neat/{core → v0/core}/_data_model/analysis/_base.py +12 -8
- cognite/neat/{core → v0/core}/_data_model/exporters/__init__.py +1 -2
- cognite/neat/{core → v0/core}/_data_model/exporters/_base.py +7 -7
- cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2dms.py +9 -9
- cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2excel.py +13 -13
- cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2instance_template.py +4 -4
- cognite/neat/{core/_data_model/exporters/_data_model2ontology.py → v0/core/_data_model/exporters/_data_model2semantic_model.py} +126 -133
- cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2yaml.py +1 -1
- cognite/neat/{core → v0/core}/_data_model/importers/__init__.py +4 -6
- cognite/neat/{core → v0/core}/_data_model/importers/_base.py +5 -5
- cognite/neat/{core → v0/core}/_data_model/importers/_base_file_reader.py +2 -2
- cognite/neat/{core → v0/core}/_data_model/importers/_dict2data_model.py +6 -6
- cognite/neat/{core → v0/core}/_data_model/importers/_dms2data_model.py +19 -16
- cognite/neat/v0/core/_data_model/importers/_graph2data_model.py +299 -0
- cognite/neat/v0/core/_data_model/importers/_rdf/__init__.py +4 -0
- cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_base.py +13 -13
- cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_inference2rdata_model.py +14 -14
- cognite/neat/v0/core/_data_model/importers/_rdf/_owl2data_model.py +144 -0
- cognite/neat/v0/core/_data_model/importers/_rdf/_shared.py +255 -0
- cognite/neat/{core → v0/core}/_data_model/importers/_spreadsheet2data_model.py +94 -13
- cognite/neat/{core → v0/core}/_data_model/models/__init__.py +3 -3
- cognite/neat/{core → v0/core}/_data_model/models/_base_verified.py +5 -5
- cognite/neat/v0/core/_data_model/models/_import_contexts.py +82 -0
- cognite/neat/{core → v0/core}/_data_model/models/_types.py +5 -5
- cognite/neat/{core → v0/core}/_data_model/models/conceptual/_unverified.py +18 -12
- cognite/neat/v0/core/_data_model/models/conceptual/_validation.py +308 -0
- cognite/neat/{core → v0/core}/_data_model/models/conceptual/_verified.py +13 -11
- cognite/neat/{core → v0/core}/_data_model/models/data_types.py +14 -4
- cognite/neat/{core → v0/core}/_data_model/models/entities/__init__.py +6 -0
- cognite/neat/v0/core/_data_model/models/entities/_loaders.py +155 -0
- cognite/neat/{core → v0/core}/_data_model/models/entities/_multi_value.py +2 -2
- cognite/neat/v0/core/_data_model/models/entities/_restrictions.py +230 -0
- cognite/neat/{core → v0/core}/_data_model/models/entities/_single_value.py +121 -16
- cognite/neat/{core → v0/core}/_data_model/models/entities/_types.py +10 -0
- cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.py +5 -5
- cognite/neat/{core → v0/core}/_data_model/models/physical/__init__.py +1 -1
- cognite/neat/{core → v0/core}/_data_model/models/physical/_exporter.py +28 -21
- cognite/neat/{core → v0/core}/_data_model/models/physical/_unverified.py +141 -38
- cognite/neat/{core → v0/core}/_data_model/models/physical/_validation.py +190 -24
- cognite/neat/{core → v0/core}/_data_model/models/physical/_verified.py +135 -15
- cognite/neat/{core → v0/core}/_data_model/transformers/__init__.py +2 -0
- cognite/neat/{core → v0/core}/_data_model/transformers/_base.py +4 -4
- cognite/neat/{core → v0/core}/_data_model/transformers/_converters.py +39 -32
- cognite/neat/{core → v0/core}/_data_model/transformers/_mapping.py +7 -7
- cognite/neat/v0/core/_data_model/transformers/_union_conceptual.py +208 -0
- cognite/neat/{core → v0/core}/_data_model/transformers/_verification.py +7 -7
- cognite/neat/v0/core/_instances/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_instances/_tracking/base.py +1 -1
- cognite/neat/{core → v0/core}/_instances/_tracking/log.py +1 -1
- cognite/neat/{core → v0/core}/_instances/extractors/__init__.py +1 -1
- cognite/neat/{core → v0/core}/_instances/extractors/_base.py +6 -6
- cognite/neat/v0/core/_instances/extractors/_classic_cdf/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_base.py +7 -7
- cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_classic.py +12 -12
- cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_relationships.py +3 -3
- cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_sequences.py +2 -2
- cognite/neat/{core → v0/core}/_instances/extractors/_dict.py +6 -3
- cognite/neat/{core → v0/core}/_instances/extractors/_dms.py +6 -6
- cognite/neat/{core → v0/core}/_instances/extractors/_dms_graph.py +11 -11
- cognite/neat/{core → v0/core}/_instances/extractors/_mock_graph_generator.py +10 -10
- cognite/neat/{core → v0/core}/_instances/extractors/_raw.py +3 -3
- cognite/neat/{core → v0/core}/_instances/extractors/_rdf_file.py +7 -7
- cognite/neat/{core → v0/core}/_instances/loaders/_base.py +5 -5
- cognite/neat/{core → v0/core}/_instances/loaders/_rdf2dms.py +17 -17
- cognite/neat/{core → v0/core}/_instances/loaders/_rdf_to_instance_space.py +11 -11
- cognite/neat/{core → v0/core}/_instances/queries/_select.py +29 -3
- cognite/neat/{core → v0/core}/_instances/queries/_update.py +1 -1
- cognite/neat/{core → v0/core}/_instances/transformers/_base.py +4 -4
- cognite/neat/{core → v0/core}/_instances/transformers/_classic_cdf.py +6 -6
- cognite/neat/{core → v0/core}/_instances/transformers/_prune_graph.py +4 -4
- cognite/neat/{core → v0/core}/_instances/transformers/_rdfpath.py +1 -1
- cognite/neat/{core → v0/core}/_instances/transformers/_value_type.py +4 -4
- cognite/neat/{core → v0/core}/_issues/_base.py +11 -6
- cognite/neat/{core → v0/core}/_issues/_contextmanagers.py +8 -6
- cognite/neat/{core → v0/core}/_issues/_factory.py +11 -8
- cognite/neat/{core → v0/core}/_issues/errors/__init__.py +3 -1
- cognite/neat/{core → v0/core}/_issues/errors/_external.py +1 -1
- cognite/neat/{core → v0/core}/_issues/errors/_general.py +1 -1
- cognite/neat/{core → v0/core}/_issues/errors/_properties.py +12 -1
- cognite/neat/{core → v0/core}/_issues/errors/_resources.py +2 -2
- cognite/neat/{core → v0/core}/_issues/errors/_wrapper.py +7 -3
- cognite/neat/{core → v0/core}/_issues/warnings/__init__.py +5 -1
- cognite/neat/{core → v0/core}/_issues/warnings/_external.py +1 -1
- cognite/neat/{core → v0/core}/_issues/warnings/_general.py +1 -1
- cognite/neat/{core → v0/core}/_issues/warnings/_models.py +39 -4
- cognite/neat/{core → v0/core}/_issues/warnings/_properties.py +13 -2
- cognite/neat/{core → v0/core}/_issues/warnings/_resources.py +1 -1
- cognite/neat/{core → v0/core}/_issues/warnings/user_modeling.py +1 -1
- cognite/neat/{core → v0/core}/_store/_data_model.py +13 -12
- cognite/neat/{core → v0/core}/_store/_instance.py +45 -12
- cognite/neat/{core → v0/core}/_store/_provenance.py +3 -3
- cognite/neat/{core → v0/core}/_store/exceptions.py +4 -4
- cognite/neat/v0/core/_utils/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_utils/auth.py +1 -1
- cognite/neat/{core → v0/core}/_utils/auxiliary.py +7 -1
- cognite/neat/{core → v0/core}/_utils/collection_.py +2 -2
- cognite/neat/{core → v0/core}/_utils/graph_transformations_report.py +1 -1
- cognite/neat/{core → v0/core}/_utils/rdf_.py +38 -14
- cognite/neat/{core → v0/core}/_utils/reader/_base.py +1 -1
- cognite/neat/{core → v0/core}/_utils/spreadsheet.py +22 -4
- cognite/neat/v0/core/_utils/tarjan.py +44 -0
- cognite/neat/{core → v0/core}/_utils/text.py +1 -1
- cognite/neat/{core → v0/core}/_utils/upload.py +3 -3
- cognite/neat/v0/plugins/__init__.py +4 -0
- cognite/neat/v0/plugins/_base.py +9 -0
- cognite/neat/v0/plugins/_data_model.py +48 -0
- cognite/neat/{plugins → v0/plugins}/_issues.py +1 -1
- cognite/neat/{plugins → v0/plugins}/_manager.py +7 -16
- cognite/neat/{session → v0/session}/_base.py +13 -10
- cognite/neat/{session → v0/session}/_collector.py +1 -1
- cognite/neat/v0/session/_diff.py +51 -0
- cognite/neat/{session → v0/session}/_drop.py +3 -3
- cognite/neat/{session → v0/session}/_explore.py +2 -2
- cognite/neat/{session → v0/session}/_fix.py +2 -2
- cognite/neat/{session → v0/session}/_inspect.py +3 -3
- cognite/neat/{session → v0/session}/_mapping.py +3 -3
- cognite/neat/{session → v0/session}/_plugin.py +4 -5
- cognite/neat/{session → v0/session}/_prepare.py +8 -8
- cognite/neat/{session → v0/session}/_read.py +33 -43
- cognite/neat/{session → v0/session}/_set.py +8 -8
- cognite/neat/{session → v0/session}/_show.py +5 -5
- cognite/neat/{session → v0/session}/_state.py +22 -8
- cognite/neat/{session → v0/session}/_subset.py +4 -4
- cognite/neat/{session → v0/session}/_template.py +11 -11
- cognite/neat/{session → v0/session}/_to.py +12 -12
- cognite/neat/{session → v0/session}/_wizard.py +1 -1
- cognite/neat/{session → v0/session}/engine/_load.py +1 -1
- cognite/neat/{session → v0/session}/exceptions.py +5 -5
- cognite/neat/v1.py +3 -0
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.127.30.dist-info}/METADATA +9 -8
- cognite_neat-0.127.30.dist-info/RECORD +319 -0
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.127.30.dist-info}/WHEEL +1 -1
- cognite/neat/core/_data_model/importers/_dtdl2data_model/__init__.py +0 -3
- cognite/neat/core/_data_model/importers/_dtdl2data_model/_unit_lookup.py +0 -224
- cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_converter.py +0 -320
- cognite/neat/core/_data_model/importers/_dtdl2data_model/dtdl_importer.py +0 -155
- cognite/neat/core/_data_model/importers/_dtdl2data_model/spec.py +0 -363
- cognite/neat/core/_data_model/importers/_rdf/__init__.py +0 -5
- cognite/neat/core/_data_model/importers/_rdf/_imf2data_model.py +0 -98
- cognite/neat/core/_data_model/importers/_rdf/_owl2data_model.py +0 -87
- cognite/neat/core/_data_model/importers/_rdf/_shared.py +0 -168
- cognite/neat/core/_data_model/models/conceptual/_validation.py +0 -294
- cognite/neat/core/_data_model/models/entities/_loaders.py +0 -75
- cognite/neat/plugins/__init__.py +0 -3
- cognite/neat/plugins/data_model/importers/__init__.py +0 -5
- cognite/neat/plugins/data_model/importers/_base.py +0 -28
- cognite_neat-0.123.2.dist-info/RECORD +0 -197
- /cognite/neat/{core → _data_model}/__init__.py +0 -0
- /cognite/neat/{core/_client/_api → _data_model/deployer}/__init__.py +0 -0
- /cognite/neat/{core/_client/data_classes → _data_model/exporters/_table_exporter}/__init__.py +0 -0
- /cognite/neat/{core/_data_model → _data_model/importers/_table_importer}/__init__.py +0 -0
- /cognite/neat/{core/_instances → _data_model/models}/__init__.py +0 -0
- /cognite/neat/{core/_instances/extractors/_classic_cdf → _data_model/models/conceptual}/__init__.py +0 -0
- /cognite/neat/{core/_utils → _data_model/validation}/__init__.py +0 -0
- /cognite/neat/{plugins/data_model → _session/_html}/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_client/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_client/data_classes/data_modeling.py +0 -0
- /cognite/neat/{core → v0/core}/_client/data_classes/neat_sequence.py +0 -0
- /cognite/neat/{core → v0/core}/_client/data_classes/statistics.py +0 -0
- /cognite/neat/{core → v0/core}/_config.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/analysis/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/catalog/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/catalog/classic_model.xlsx +0 -0
- /cognite/neat/{core → v0/core}/_data_model/catalog/conceptual-imf-data-model.xlsx +0 -0
- /cognite/neat/{core → v0/core}/_data_model/catalog/hello_world_pump.xlsx +0 -0
- /cognite/neat/{core → v0/core}/_data_model/models/_base_unverified.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/models/conceptual/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/models/entities/_constants.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/models/entities/_wrapped.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/models/mapping/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/models/mapping/_classic2core.yaml +0 -0
- /cognite/neat/{core → v0/core}/_instances/_shared.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/_tracking/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44-dirty.xml +0 -0
- /cognite/neat/{core → v0/core}/_instances/examples/Knowledge-Graph-Nordic44.xml +0 -0
- /cognite/neat/{core → v0/core}/_instances/examples/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/examples/skos-capturing-sheet-wind-topics.xlsx +0 -0
- /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_assets.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_data_sets.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_events.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_files.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_labels.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/extractors/_classic_cdf/_timeseries.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/loaders/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/queries/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/queries/_base.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/queries/_queries.py +0 -0
- /cognite/neat/{core → v0/core}/_instances/transformers/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_issues/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_issues/formatters.py +0 -0
- /cognite/neat/{core → v0/core}/_shared.py +0 -0
- /cognite/neat/{core → v0/core}/_store/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_utils/io_.py +0 -0
- /cognite/neat/{core → v0/core}/_utils/reader/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_utils/time_.py +0 -0
- /cognite/neat/{core → v0/core}/_utils/xml_.py +0 -0
- /cognite/neat/{session → v0/session}/__init__.py +0 -0
- /cognite/neat/{session → v0/session}/_experimental.py +0 -0
- /cognite/neat/{session → v0/session}/_state/README.md +0 -0
- /cognite/neat/{session → v0/session}/engine/__init__.py +0 -0
- /cognite/neat/{session → v0/session}/engine/_import.py +0 -0
- /cognite/neat/{session → v0/session}/engine/_interface.py +0 -0
- {cognite_neat-0.123.2.dist-info → cognite_neat-0.127.30.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
from typing import Annotated, Literal, cast, get_args
|
|
4
|
+
|
|
5
|
+
from pydantic import (
|
|
6
|
+
AliasGenerator,
|
|
7
|
+
BaseModel,
|
|
8
|
+
BeforeValidator,
|
|
9
|
+
Field,
|
|
10
|
+
PlainSerializer,
|
|
11
|
+
field_validator,
|
|
12
|
+
model_validator,
|
|
13
|
+
)
|
|
14
|
+
from pydantic.alias_generators import to_camel
|
|
15
|
+
from pydantic.fields import FieldInfo
|
|
16
|
+
from traitlets import Any
|
|
17
|
+
|
|
18
|
+
from cognite.neat._data_model.models.entities import ParsedEntity, parse_entities, parse_entity
|
|
19
|
+
from cognite.neat._utils.text import title_case
|
|
20
|
+
from cognite.neat._utils.useful_types import CellValueType
|
|
21
|
+
from cognite.neat.v0.core._data_model.models.entities import (
|
|
22
|
+
HasDataFilter,
|
|
23
|
+
NodeTypeFilter,
|
|
24
|
+
RawFilter,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# This marker is used to identify creator in the description field.
|
|
28
|
+
CREATOR_MARKER = "Creator: "
|
|
29
|
+
CREATOR_KEY = "creator"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def parse_entity_str(v: str) -> ParsedEntity:
|
|
33
|
+
if isinstance(v, ParsedEntity):
|
|
34
|
+
return v
|
|
35
|
+
try:
|
|
36
|
+
return parse_entity(v)
|
|
37
|
+
except ValueError as e:
|
|
38
|
+
raise ValueError(f"Invalid entity syntax: {e}") from e
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def parse_entities_str(v: str) -> list[ParsedEntity] | None:
|
|
42
|
+
if isinstance(v, list) and all(isinstance(item, ParsedEntity) for item in v):
|
|
43
|
+
return v
|
|
44
|
+
try:
|
|
45
|
+
return parse_entities(v)
|
|
46
|
+
except ValueError as e:
|
|
47
|
+
raise ValueError(f"Invalid entity list syntax: {e}") from e
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
Entity = Annotated[ParsedEntity, BeforeValidator(parse_entity_str, str), PlainSerializer(func=str)]
|
|
51
|
+
EntityList = Annotated[
|
|
52
|
+
list[ParsedEntity],
|
|
53
|
+
BeforeValidator(parse_entities_str, str),
|
|
54
|
+
PlainSerializer(func=lambda v: ",".join([str(item) for item in v])),
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TableObj(
|
|
59
|
+
BaseModel,
|
|
60
|
+
extra="ignore",
|
|
61
|
+
alias_generator=AliasGenerator(
|
|
62
|
+
alias=to_camel,
|
|
63
|
+
validation_alias=title_case,
|
|
64
|
+
serialization_alias=title_case,
|
|
65
|
+
),
|
|
66
|
+
populate_by_name=True,
|
|
67
|
+
): ...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class MetadataValue(TableObj):
|
|
71
|
+
key: str
|
|
72
|
+
value: CellValueType
|
|
73
|
+
|
|
74
|
+
@field_validator("key", mode="after")
|
|
75
|
+
def _legacy_external_id(cls, value: str) -> str:
|
|
76
|
+
return "externalId" if value.lower() == "external_id" else value
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class DMSProperty(TableObj):
|
|
80
|
+
view: Entity
|
|
81
|
+
view_property: str
|
|
82
|
+
name: str | None = None
|
|
83
|
+
description: str | None = None
|
|
84
|
+
connection: Entity | None
|
|
85
|
+
value_type: Entity
|
|
86
|
+
min_count: int | None
|
|
87
|
+
max_count: int | None
|
|
88
|
+
immutable: bool | None = None
|
|
89
|
+
default: CellValueType | None = None
|
|
90
|
+
auto_increment: bool | None = None
|
|
91
|
+
container: Entity | None = None
|
|
92
|
+
container_property: str | None = None
|
|
93
|
+
container_property_name: str | None = None
|
|
94
|
+
container_property_description: str | None = None
|
|
95
|
+
index: EntityList | None = None
|
|
96
|
+
constraint: EntityList | None = None
|
|
97
|
+
|
|
98
|
+
@field_validator("max_count", mode="before")
|
|
99
|
+
@classmethod
|
|
100
|
+
def _legacy_max_count(cls, value: Any) -> Any | None:
|
|
101
|
+
"""Validates and converts the max_count field if it uses the legacy 'inf' value."""
|
|
102
|
+
if isinstance(value, str) and value.lower() == "inf":
|
|
103
|
+
return None
|
|
104
|
+
return value
|
|
105
|
+
|
|
106
|
+
@model_validator(mode="before")
|
|
107
|
+
def _legacy_cardinality(cls, data: dict[str, Any]) -> dict[str, Any]:
|
|
108
|
+
"""Converts Is List to Max Count and Nullable to Min Count."""
|
|
109
|
+
if not data:
|
|
110
|
+
return data
|
|
111
|
+
|
|
112
|
+
if "Max Count" not in data and "Is List" in data:
|
|
113
|
+
is_list = data.pop("Is List")
|
|
114
|
+
if isinstance(is_list, bool):
|
|
115
|
+
data["Max Count"] = None if is_list else 1
|
|
116
|
+
|
|
117
|
+
if "Min Count" not in data and "Nullable" in data:
|
|
118
|
+
nullable = data.pop("Nullable")
|
|
119
|
+
if isinstance(nullable, bool):
|
|
120
|
+
data["Min Count"] = 0 if nullable else 1
|
|
121
|
+
|
|
122
|
+
return data
|
|
123
|
+
|
|
124
|
+
@model_validator(mode="after")
|
|
125
|
+
def _legacy_index(self) -> "DMSProperty":
|
|
126
|
+
"""Converts Is List to Max Count and Nullable to Min Count."""
|
|
127
|
+
if not self.index:
|
|
128
|
+
return self
|
|
129
|
+
|
|
130
|
+
for index in self.index:
|
|
131
|
+
if not index.prefix:
|
|
132
|
+
index.prefix = "inverted" if not self.max_count or self.max_count > 1 else "btree"
|
|
133
|
+
|
|
134
|
+
return self
|
|
135
|
+
|
|
136
|
+
@model_validator(mode="after")
|
|
137
|
+
def _legacy_constraint(self) -> "DMSProperty":
|
|
138
|
+
"""Converts Is List to Max Count and Nullable to Min Count."""
|
|
139
|
+
if not self.constraint:
|
|
140
|
+
return self
|
|
141
|
+
|
|
142
|
+
for constraint in self.constraint:
|
|
143
|
+
if not constraint.prefix:
|
|
144
|
+
constraint.prefix = "uniqueness"
|
|
145
|
+
|
|
146
|
+
return self
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class DMSView(TableObj):
|
|
150
|
+
view: Entity
|
|
151
|
+
name: str | None = None
|
|
152
|
+
description: str | None = None
|
|
153
|
+
implements: EntityList | None = None
|
|
154
|
+
filter: str | None = None
|
|
155
|
+
|
|
156
|
+
@field_validator("filter", mode="after")
|
|
157
|
+
def _legacy_filter(cls, value: str | None) -> str | None:
|
|
158
|
+
if value is None:
|
|
159
|
+
return value
|
|
160
|
+
|
|
161
|
+
value_lower = value.lower()
|
|
162
|
+
|
|
163
|
+
if value_lower.startswith("hasdata("):
|
|
164
|
+
return json.dumps(HasDataFilter.load(value).as_dms_filter().dump())
|
|
165
|
+
elif value_lower.startswith("nodetype("):
|
|
166
|
+
return json.dumps(NodeTypeFilter.load(value).as_dms_filter().dump())
|
|
167
|
+
elif value_lower.startswith("rawfilter("):
|
|
168
|
+
return json.dumps(RawFilter.load(value).as_dms_filter().dump())
|
|
169
|
+
|
|
170
|
+
return value
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class DMSContainer(TableObj):
|
|
174
|
+
container: Entity
|
|
175
|
+
name: str | None = None
|
|
176
|
+
description: str | None = None
|
|
177
|
+
constraint: EntityList | None = None
|
|
178
|
+
used_for: str | None = None
|
|
179
|
+
|
|
180
|
+
@model_validator(mode="after")
|
|
181
|
+
def _legacy_constraint(self) -> "DMSContainer":
|
|
182
|
+
"""Converts legacy constraint formats to the current standard."""
|
|
183
|
+
if not self.constraint:
|
|
184
|
+
return self
|
|
185
|
+
|
|
186
|
+
for constraint in self.constraint:
|
|
187
|
+
# Skip if already in correct format or being wrong but not legacy
|
|
188
|
+
if constraint.prefix == "requires" or constraint.properties:
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
# This part handles legacy constraints
|
|
192
|
+
if not constraint.prefix:
|
|
193
|
+
constraint.prefix = "requires"
|
|
194
|
+
constraint.properties = {"require": constraint.suffix}
|
|
195
|
+
|
|
196
|
+
else:
|
|
197
|
+
container_space = constraint.prefix
|
|
198
|
+
container_external_id = constraint.suffix
|
|
199
|
+
constraint.prefix = "requires"
|
|
200
|
+
constraint.suffix = f"{container_space}_{container_external_id}"
|
|
201
|
+
constraint.properties = {"require": f"{container_space}:{container_external_id}"}
|
|
202
|
+
|
|
203
|
+
return self
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class DMSEnum(TableObj):
|
|
207
|
+
collection: str
|
|
208
|
+
value: str
|
|
209
|
+
name: str | None = None
|
|
210
|
+
description: str | None = None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class DMSNode(TableObj):
|
|
214
|
+
node: Entity
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class TableDMS(TableObj):
|
|
218
|
+
metadata: list[MetadataValue]
|
|
219
|
+
properties: list[DMSProperty]
|
|
220
|
+
views: list[DMSView]
|
|
221
|
+
containers: list[DMSContainer] = Field(default_factory=list)
|
|
222
|
+
enum: list[DMSEnum] = Field(default_factory=list)
|
|
223
|
+
nodes: list[DMSNode] = Field(default_factory=list)
|
|
224
|
+
|
|
225
|
+
@model_validator(mode="before")
|
|
226
|
+
def _title_case_keys(
|
|
227
|
+
cls, data: dict[str, list[dict[str, CellValueType]]]
|
|
228
|
+
) -> dict[str, list[dict[str, CellValueType]]]:
|
|
229
|
+
if isinstance(data, dict):
|
|
230
|
+
# We are case-insensitive on the table names.
|
|
231
|
+
return {title_case(k): v for k, v in data.items()}
|
|
232
|
+
return data
|
|
233
|
+
|
|
234
|
+
@classmethod
|
|
235
|
+
def get_sheet_columns(
|
|
236
|
+
cls, sheet_id: str, sheet: FieldInfo | None = None, *, column_type: Literal["all", "required"] = "required"
|
|
237
|
+
) -> list[str]:
|
|
238
|
+
if sheet_id not in cls.model_fields.keys():
|
|
239
|
+
raise KeyError(f"Invalid field id: {sheet_id}")
|
|
240
|
+
if sheet is None:
|
|
241
|
+
sheet = cls.model_fields[sheet_id]
|
|
242
|
+
return [
|
|
243
|
+
# We know all fields has validation_alias because of the alias_generator in TableDMS
|
|
244
|
+
cast(str, sheet_field.validation_alias)
|
|
245
|
+
# All the fields in the sheet's model are lists.
|
|
246
|
+
for sheet_field in get_args(sheet.annotation)[0].model_fields.values()
|
|
247
|
+
if sheet_field.is_required() or column_type == "all"
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
@classmethod
|
|
251
|
+
def get_sheet_column_by_name(
|
|
252
|
+
cls, sheet_name: str, *, column_type: Literal["all", "required"] = "required"
|
|
253
|
+
) -> list[str]:
|
|
254
|
+
for field_id, field_ in cls.model_fields.items():
|
|
255
|
+
if cast(str, field_.validation_alias) == sheet_name:
|
|
256
|
+
return cls.get_sheet_columns(field_id, field_, column_type=column_type)
|
|
257
|
+
raise KeyError(f"Invalid field alias: {sheet_name}")
|
|
258
|
+
|
|
259
|
+
@classmethod
|
|
260
|
+
def required_sheets(cls) -> set[str]:
|
|
261
|
+
return {cast(str, field_.validation_alias) for field_ in cls.model_fields.values() if field_.is_required()}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
DMS_API_MAPPING: Mapping[str, Mapping[str, str]] = {
|
|
265
|
+
"Views": {
|
|
266
|
+
"space": "View",
|
|
267
|
+
"externalId": "View",
|
|
268
|
+
"version": "View",
|
|
269
|
+
**{
|
|
270
|
+
cast(str, field_.alias): cast(str, field_.validation_alias)
|
|
271
|
+
for field_id, field_ in DMSView.model_fields.items()
|
|
272
|
+
if field_id != "View"
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
"Containers": {
|
|
276
|
+
"space": "Container",
|
|
277
|
+
"externalId": "Container",
|
|
278
|
+
**{
|
|
279
|
+
cast(str, field_.alias): cast(str, field_.validation_alias)
|
|
280
|
+
for field_id, field_ in DMSContainer.model_fields.items()
|
|
281
|
+
if field_id != "Container"
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
"Properties": {
|
|
285
|
+
"space": "View",
|
|
286
|
+
"externalId": "View",
|
|
287
|
+
"property": "ViewProperty",
|
|
288
|
+
"type": "Value Type",
|
|
289
|
+
**{
|
|
290
|
+
cast(str, field_.alias): cast(str, field_.validation_alias)
|
|
291
|
+
for field_id, field_ in DMSProperty.model_fields.items()
|
|
292
|
+
if field_id not in ("View", "ViewProperty")
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
}
|
|
@@ -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
|