cognite-neat 0.123.32__py3-none-any.whl → 0.127.30__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +198 -2
- cognite/neat/_data_model/models/dms/_base.py +13 -9
- cognite/neat/_data_model/models/dms/_constants.py +47 -1
- 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 +14 -10
- 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 → _data_model}/models/entities/_constants.py +5 -0
- cognite/neat/_data_model/models/entities/_data_types.py +144 -0
- cognite/neat/{data_model → _data_model}/models/entities/_identifiers.py +1 -1
- 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/_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/_reader.py +194 -0
- cognite/neat/_utils/auxiliary.py +7 -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/core/_client/_api/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_client/_api/data_modeling_loaders.py +6 -6
- 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 +5 -3
- cognite/neat/v0/core/_data_model/__init__.py +0 -0
- cognite/neat/{core → v0/core}/_data_model/_constants.py +3 -0
- cognite/neat/{core → v0/core}/_data_model/_shared.py +4 -4
- cognite/neat/{core → v0/core}/_data_model/analysis/_base.py +8 -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 +12 -12
- 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 -116
- cognite/neat/{core → v0/core}/_data_model/exporters/_data_model2yaml.py +1 -1
- 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 +5 -5
- cognite/neat/{core → v0/core}/_data_model/importers/_dms2data_model.py +16 -15
- cognite/neat/{core → v0/core}/_data_model/importers/_graph2data_model.py +12 -12
- cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_base.py +12 -12
- cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_inference2rdata_model.py +14 -14
- cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_owl2data_model.py +41 -21
- cognite/neat/{core → v0/core}/_data_model/importers/_rdf/_shared.py +9 -9
- cognite/neat/{core → v0/core}/_data_model/importers/_spreadsheet2data_model.py +92 -12
- 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/{core → v0/core}/_data_model/models/_import_contexts.py +1 -1
- cognite/neat/{core → v0/core}/_data_model/models/_types.py +5 -5
- cognite/neat/{core → v0/core}/_data_model/models/conceptual/_unverified.py +5 -5
- cognite/neat/{core → v0/core}/_data_model/models/conceptual/_validation.py +12 -12
- cognite/neat/{core → v0/core}/_data_model/models/conceptual/_verified.py +9 -9
- cognite/neat/{core → v0/core}/_data_model/models/data_types.py +4 -4
- cognite/neat/{core → v0/core}/_data_model/models/entities/__init__.py +2 -0
- cognite/neat/{core → v0/core}/_data_model/models/entities/_loaders.py +2 -2
- cognite/neat/{core → v0/core}/_data_model/models/entities/_multi_value.py +2 -2
- cognite/neat/{core → v0/core}/_data_model/models/entities/_restrictions.py +6 -6
- cognite/neat/{core → v0/core}/_data_model/models/entities/_single_value.py +17 -3
- 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 +24 -19
- cognite/neat/{core → v0/core}/_data_model/models/physical/_unverified.py +69 -20
- cognite/neat/{core → v0/core}/_data_model/models/physical/_validation.py +24 -20
- cognite/neat/{core → v0/core}/_data_model/models/physical/_verified.py +95 -24
- cognite/neat/{core → v0/core}/_data_model/transformers/_base.py +4 -4
- cognite/neat/{core → v0/core}/_data_model/transformers/_converters.py +35 -28
- cognite/neat/{core → v0/core}/_data_model/transformers/_mapping.py +7 -7
- cognite/neat/{core → v0/core}/_data_model/transformers/_union_conceptual.py +5 -5
- 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 +5 -5
- cognite/neat/{core → v0/core}/_issues/_contextmanagers.py +1 -1
- cognite/neat/{core → v0/core}/_issues/_factory.py +3 -3
- cognite/neat/{core → v0/core}/_issues/errors/__init__.py +1 -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 +1 -1
- cognite/neat/{core → v0/core}/_issues/errors/_resources.py +2 -2
- cognite/neat/{core → v0/core}/_issues/errors/_wrapper.py +2 -2
- cognite/neat/{core → v0/core}/_issues/warnings/__init__.py +1 -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 +2 -2
- cognite/neat/{core → v0/core}/_issues/warnings/_properties.py +2 -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 +12 -12
- cognite/neat/{core → v0/core}/_store/_instance.py +43 -10
- 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 +1 -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 +1 -1
- cognite/neat/{core → v0/core}/_utils/reader/_base.py +1 -1
- cognite/neat/{core → v0/core}/_utils/spreadsheet.py +18 -4
- 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 +12 -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 -20
- 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 +10 -10
- 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.32.dist-info → cognite_neat-0.127.30.dist-info}/METADATA +7 -6
- cognite_neat-0.127.30.dist-info/RECORD +319 -0
- {cognite_neat-0.123.32.dist-info → cognite_neat-0.127.30.dist-info}/WHEEL +1 -1
- cognite/neat/data_model/models/entities/__init__.py +0 -9
- 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.32.dist-info/RECORD +0 -209
- /cognite/neat/{core → _data_model/deployer}/__init__.py +0 -0
- /cognite/neat/{core/_client/_api → _data_model/exporters/_table_exporter}/__init__.py +0 -0
- /cognite/neat/{core/_client/data_classes → _data_model/importers/_table_importer}/__init__.py +0 -0
- /cognite/neat/{core/_data_model → _data_model/models/conceptual}/__init__.py +0 -0
- /cognite/neat/{core/_instances → _data_model/validation}/__init__.py +0 -0
- /cognite/neat/{core/_instances/extractors/_classic_cdf → _session/_html}/__init__.py +0 -0
- /cognite/neat/{core/_utils → _session/_usage_analytics}/__init__.py +0 -0
- /cognite/neat/{data_model → v0}/__init__.py +0 -0
- /cognite/neat/{plugins/data_model → v0/core}/__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/importers/__init__.py +0 -0
- /cognite/neat/{core → v0/core}/_data_model/importers/_rdf/__init__.py +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}/_data_model/transformers/__init__.py +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/tarjan.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.32.dist-info → cognite_neat-0.127.30.dist-info}/licenses/LICENSE +0 -0
cognite/neat/_config.py
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
from cognite.neat._issues import ConsistencyError, ModelSyntaxError
|
|
7
|
+
from cognite.neat._utils.useful_types import ModusOperandi
|
|
8
|
+
|
|
9
|
+
if sys.version_info >= (3, 11):
|
|
10
|
+
import tomllib as tomli # Python 3.11+
|
|
11
|
+
else:
|
|
12
|
+
import tomli # type: ignore
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ValidationConfig(BaseModel, populate_by_name=True):
|
|
16
|
+
"""Validation configuration."""
|
|
17
|
+
|
|
18
|
+
exclude: list[str] = Field(default_factory=list)
|
|
19
|
+
|
|
20
|
+
def can_run_validator(self, code: str, issue_type: type) -> bool:
|
|
21
|
+
"""
|
|
22
|
+
Check if a specific validator should run.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
code: Validation code (e.g., "NEAT-DMS-CONTAINER-001")
|
|
26
|
+
issue_type: Issue type (e.g., ModelSyntaxError, ConsistencyError, Recommendation)
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
True if validator should run, False otherwise
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
is_excluded = self._is_excluded(code, self.exclude)
|
|
33
|
+
|
|
34
|
+
if issue_type in [ModelSyntaxError, ConsistencyError] and is_excluded:
|
|
35
|
+
print(f"Validator {code} was excluded however it is a critical validator and will still run.")
|
|
36
|
+
return True
|
|
37
|
+
else:
|
|
38
|
+
return not is_excluded
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def _is_excluded(cls, code: str, patterns: list[str]) -> bool:
|
|
42
|
+
"""Check if code matches any pattern (supports wildcards)."""
|
|
43
|
+
for pattern in patterns:
|
|
44
|
+
if "*" in pattern:
|
|
45
|
+
# Split both pattern and code by hyphens
|
|
46
|
+
pattern_parts = pattern.split("-")
|
|
47
|
+
code_parts = code.split("-")
|
|
48
|
+
|
|
49
|
+
# Pattern must have same or fewer parts than code
|
|
50
|
+
if len(pattern_parts) > len(code_parts):
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
# Check if all pattern parts match (allowing wildcards)
|
|
54
|
+
match = True
|
|
55
|
+
for p_part, c_part in zip(pattern_parts, code_parts, strict=False):
|
|
56
|
+
if p_part != "*" and p_part != c_part:
|
|
57
|
+
match = False
|
|
58
|
+
break
|
|
59
|
+
|
|
60
|
+
if match:
|
|
61
|
+
return True
|
|
62
|
+
elif code == pattern:
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
def __str__(self) -> str:
|
|
68
|
+
"""Human-readable configuration summary."""
|
|
69
|
+
if not self.exclude:
|
|
70
|
+
return "All validators enabled"
|
|
71
|
+
return f"Excluded Rules: {', '.join(self.exclude)}"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ModelingConfig(BaseModel, populate_by_name=True):
|
|
75
|
+
"""Modeling configuration."""
|
|
76
|
+
|
|
77
|
+
mode: ModusOperandi = "additive"
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class NeatConfig(BaseModel, populate_by_name=True):
|
|
81
|
+
"""Configuration for a custom profile."""
|
|
82
|
+
|
|
83
|
+
profile: str
|
|
84
|
+
validation: ValidationConfig
|
|
85
|
+
modeling: ModelingConfig
|
|
86
|
+
|
|
87
|
+
def __str__(self) -> str:
|
|
88
|
+
"""Human-readable configuration summary."""
|
|
89
|
+
lines = [
|
|
90
|
+
f"Profile: {self.profile}",
|
|
91
|
+
f"Modeling Mode: {self.modeling.mode}",
|
|
92
|
+
f"Validation: {self.validation}",
|
|
93
|
+
]
|
|
94
|
+
return "\n".join(lines)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def internal_profiles() -> dict[str, NeatConfig]:
|
|
98
|
+
"""Get internal NeatConfig profile by name."""
|
|
99
|
+
return {
|
|
100
|
+
"legacy-additive": NeatConfig(
|
|
101
|
+
profile="legacy-additive",
|
|
102
|
+
modeling=ModelingConfig(mode="additive"),
|
|
103
|
+
validation=ValidationConfig(
|
|
104
|
+
exclude=[
|
|
105
|
+
"NEAT-DMS-AI-READINESS-*",
|
|
106
|
+
"NEAT-DMS-CONNECTIONS-002",
|
|
107
|
+
"NEAT-DMS-CONNECTIONS-REVERSE-007",
|
|
108
|
+
"NEAT-DMS-CONNECTIONS-REVERSE-008",
|
|
109
|
+
"NEAT-DMS-CONSISTENCY-001",
|
|
110
|
+
]
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
"legacy-rebuild": NeatConfig(
|
|
114
|
+
profile="legacy-rebuild",
|
|
115
|
+
modeling=ModelingConfig(mode="rebuild"),
|
|
116
|
+
validation=ValidationConfig(
|
|
117
|
+
exclude=[
|
|
118
|
+
"NEAT-DMS-AI-READINESS-*",
|
|
119
|
+
"NEAT-DMS-CONNECTIONS-002",
|
|
120
|
+
"NEAT-DMS-CONNECTIONS-REVERSE-007",
|
|
121
|
+
"NEAT-DMS-CONNECTIONS-REVERSE-008",
|
|
122
|
+
"NEAT-DMS-CONSISTENCY-001",
|
|
123
|
+
]
|
|
124
|
+
),
|
|
125
|
+
),
|
|
126
|
+
"deep-additive": NeatConfig(
|
|
127
|
+
profile="deep-additive",
|
|
128
|
+
modeling=ModelingConfig(mode="additive"),
|
|
129
|
+
validation=ValidationConfig(exclude=[]),
|
|
130
|
+
),
|
|
131
|
+
"deep-rebuild": NeatConfig(
|
|
132
|
+
profile="deep-rebuild",
|
|
133
|
+
modeling=ModelingConfig(mode="rebuild"),
|
|
134
|
+
validation=ValidationConfig(exclude=[]),
|
|
135
|
+
),
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def get_neat_config(config_file_name: str, profile: str) -> NeatConfig:
|
|
140
|
+
"""Get NeatConfig from file or internal profiles.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
config_file_name: Path to configuration file.
|
|
144
|
+
profile: Profile name to use.
|
|
145
|
+
Returns:
|
|
146
|
+
NeatConfig instance.
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
if not config_file_name.endswith(".toml"):
|
|
150
|
+
raise ValueError("config_file_name must end with '.toml'")
|
|
151
|
+
|
|
152
|
+
file_path = Path.cwd() / config_file_name
|
|
153
|
+
|
|
154
|
+
if file_path.exists():
|
|
155
|
+
with file_path.open("rb") as f:
|
|
156
|
+
toml = tomli.load(f)
|
|
157
|
+
|
|
158
|
+
if "tool" in toml and "neat" in toml["tool"]:
|
|
159
|
+
data = toml["tool"]["neat"]
|
|
160
|
+
elif "neat" in toml:
|
|
161
|
+
data = toml["neat"]
|
|
162
|
+
else:
|
|
163
|
+
raise ValueError("No [tool.neat] or [neat] section found in the configuration file.")
|
|
164
|
+
|
|
165
|
+
toml_profile = data.get("profile")
|
|
166
|
+
toml_profiles = data.get("profiles")
|
|
167
|
+
hardcoded_profiles = internal_profiles()
|
|
168
|
+
|
|
169
|
+
if toml_profile and toml_profile in hardcoded_profiles:
|
|
170
|
+
raise ValueError(f"Internal profile '{toml_profile}' cannot be used in external configuration file.")
|
|
171
|
+
|
|
172
|
+
if toml_profiles and any(p in hardcoded_profiles for p in toml_profiles.keys()):
|
|
173
|
+
raise ValueError(
|
|
174
|
+
"Internal profiles cannot be redefined in external configuration file: "
|
|
175
|
+
f"{set(hardcoded_profiles.keys()).intersection(toml_profiles.keys())}"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
if toml_profile and profile == toml_profile:
|
|
179
|
+
return NeatConfig(**data)
|
|
180
|
+
elif (built_in_profiles := data.get("profiles")) and profile in built_in_profiles:
|
|
181
|
+
return NeatConfig(profile=profile, **data["profiles"][profile])
|
|
182
|
+
else:
|
|
183
|
+
raise ValueError(f"Profile '{profile}' not found in configuration file.")
|
|
184
|
+
else:
|
|
185
|
+
raise FileNotFoundError(f"Configuration file '{file_path}' not found.")
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
from graphlib import TopologicalSorter
|
|
2
|
+
|
|
3
|
+
from cognite.neat._data_model.models.dms._constraints import RequiresConstraintDefinition
|
|
4
|
+
from cognite.neat._data_model.models.dms._container import ContainerPropertyDefinition, ContainerRequest
|
|
5
|
+
from cognite.neat._data_model.models.dms._data_types import DirectNodeRelation
|
|
6
|
+
from cognite.neat._data_model.models.dms._references import (
|
|
7
|
+
ContainerDirectReference,
|
|
8
|
+
ContainerReference,
|
|
9
|
+
ViewDirectReference,
|
|
10
|
+
ViewReference,
|
|
11
|
+
)
|
|
12
|
+
from cognite.neat._data_model.models.dms._schema import RequestSchema
|
|
13
|
+
from cognite.neat._data_model.models.dms._view_property import (
|
|
14
|
+
EdgeProperty,
|
|
15
|
+
ReverseDirectRelationProperty,
|
|
16
|
+
ViewCorePropertyRequest,
|
|
17
|
+
ViewRequestProperty,
|
|
18
|
+
)
|
|
19
|
+
from cognite.neat._data_model.models.dms._views import ViewRequest
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DataModelAnalysis:
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
physical: RequestSchema | None = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
self._physical = physical
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def physical(self) -> RequestSchema:
|
|
31
|
+
if self._physical is None:
|
|
32
|
+
raise ValueError("Physical Data Model is required for this analysis")
|
|
33
|
+
return self._physical
|
|
34
|
+
|
|
35
|
+
def referenced_views(self, include_connection_end_node_types: bool = False) -> set[ViewReference]:
|
|
36
|
+
"""Get all referenced views in the physical data model."""
|
|
37
|
+
referenced_views = set()
|
|
38
|
+
|
|
39
|
+
for view in self.physical.views:
|
|
40
|
+
referenced_views.add(view.as_reference())
|
|
41
|
+
if view.implements:
|
|
42
|
+
for implement in view.implements:
|
|
43
|
+
referenced_views.add(implement)
|
|
44
|
+
|
|
45
|
+
if include_connection_end_node_types:
|
|
46
|
+
referenced_views |= {view for view in self.connection_end_node_types.values() if view is not None}
|
|
47
|
+
|
|
48
|
+
return referenced_views
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def referenced_containers(self) -> set[ContainerReference]:
|
|
52
|
+
"""Get all referenced containers in the physical data model."""
|
|
53
|
+
referenced_containers = set()
|
|
54
|
+
|
|
55
|
+
for view in self.physical.views:
|
|
56
|
+
for property_ in view.properties.values():
|
|
57
|
+
if isinstance(property_, ViewCorePropertyRequest):
|
|
58
|
+
referenced_containers.add(property_.container)
|
|
59
|
+
|
|
60
|
+
for container in self.physical.containers:
|
|
61
|
+
referenced_containers.add(container.as_reference())
|
|
62
|
+
if container.constraints:
|
|
63
|
+
for constraint in container.constraints.values():
|
|
64
|
+
if isinstance(constraint, RequiresConstraintDefinition):
|
|
65
|
+
referenced_containers.add(constraint.require)
|
|
66
|
+
|
|
67
|
+
return referenced_containers
|
|
68
|
+
|
|
69
|
+
def view_by_reference(self, include_inherited_properties: bool = True) -> dict[ViewReference, ViewRequest]:
|
|
70
|
+
"""Get a mapping of view references to their corresponding ViewRequest objects."""
|
|
71
|
+
view_ancestors = self.ancestors_by_view(self.physical.views)
|
|
72
|
+
|
|
73
|
+
view_by_reference: dict[ViewReference, ViewRequest] = {
|
|
74
|
+
view.as_reference(): view.model_copy(deep=True) for view in self.physical.views
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if include_inherited_properties:
|
|
78
|
+
for ref, view in view_by_reference.items():
|
|
79
|
+
for ancestor in view_ancestors.get(ref, set()):
|
|
80
|
+
if ancestor_view := view_by_reference.get(ancestor):
|
|
81
|
+
if ancestor_view.properties:
|
|
82
|
+
view.properties.update(ancestor_view.properties)
|
|
83
|
+
|
|
84
|
+
return view_by_reference
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def properties_by_view(self) -> dict[ViewReference, dict[str, ViewRequestProperty]]:
|
|
88
|
+
"""Get a mapping of view references to their corresponding properties."""
|
|
89
|
+
view_by_reference = self.view_by_reference(include_inherited_properties=False)
|
|
90
|
+
return {
|
|
91
|
+
view_ref: {prop_name: prop for prop_name, prop in view.properties.items()}
|
|
92
|
+
for view_ref, view in view_by_reference.items()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def ancestors_by_view(views: list[ViewRequest]) -> dict[ViewReference, set[ViewReference]]:
|
|
97
|
+
"""Get a mapping of each view to its ancestors in the physical data model."""
|
|
98
|
+
implements_by_view = DataModelAnalysis.implements_by_view(views)
|
|
99
|
+
|
|
100
|
+
# Topological sort to ensure that concepts include all ancestors
|
|
101
|
+
for view in list(TopologicalSorter(implements_by_view).static_order()):
|
|
102
|
+
if view not in implements_by_view:
|
|
103
|
+
continue
|
|
104
|
+
implements_by_view[view] |= {
|
|
105
|
+
grand_parent
|
|
106
|
+
for parent in implements_by_view[view]
|
|
107
|
+
for grand_parent in implements_by_view.get(parent, set())
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return implements_by_view
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def implements_by_view(views: list[ViewRequest]) -> dict[ViewReference, set[ViewReference]]:
|
|
114
|
+
"""Get a mapping of each view to the views it implements."""
|
|
115
|
+
implements_mapping: dict[ViewReference, set[ViewReference]] = {}
|
|
116
|
+
|
|
117
|
+
for view in views:
|
|
118
|
+
view_ref = view.as_reference()
|
|
119
|
+
if view_ref not in implements_mapping:
|
|
120
|
+
implements_mapping[view_ref] = set()
|
|
121
|
+
if view.implements:
|
|
122
|
+
for implement in view.implements:
|
|
123
|
+
implements_mapping[view_ref].add(implement)
|
|
124
|
+
|
|
125
|
+
return implements_mapping
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def container_by_reference(self) -> dict[ContainerReference, ContainerRequest]:
|
|
129
|
+
"""Get a mapping of container references to their corresponding ContainerRequest objects."""
|
|
130
|
+
return {container.as_reference(): container.model_copy(deep=True) for container in self.physical.containers}
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def container_properties(self) -> dict[tuple[ContainerReference, str], ContainerPropertyDefinition]:
|
|
134
|
+
"""Get a mapping from (container reference, property name) to the property definition."""
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
(container.as_reference(), prop_name): property_
|
|
138
|
+
for container in self.physical.containers
|
|
139
|
+
for prop_name, property_ in container.properties.items()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def connection_end_node_types(self) -> dict[tuple[ViewReference, str], ViewReference | None]:
|
|
144
|
+
"""Get a mapping of view references to their corresponding ViewRequest objects."""
|
|
145
|
+
view_by_reference = self.view_by_reference(include_inherited_properties=False)
|
|
146
|
+
connection_end_node_types: dict[tuple[ViewReference, str], ViewReference | None] = {}
|
|
147
|
+
container_properties = self.container_properties
|
|
148
|
+
|
|
149
|
+
for view_ref, view in view_by_reference.items():
|
|
150
|
+
if not view.properties:
|
|
151
|
+
continue
|
|
152
|
+
for prop_ref, property_ in view.properties.items():
|
|
153
|
+
# direct relation
|
|
154
|
+
if isinstance(property_, ViewCorePropertyRequest):
|
|
155
|
+
# explicit set of end node type via 'source' which is View reference
|
|
156
|
+
if property_.source:
|
|
157
|
+
connection_end_node_types[(view_ref, prop_ref)] = property_.source
|
|
158
|
+
|
|
159
|
+
# implicit end node type via container property, without actual knowledge of end node type
|
|
160
|
+
elif (
|
|
161
|
+
container_property := container_properties.get(
|
|
162
|
+
(property_.container, property_.container_property_identifier)
|
|
163
|
+
)
|
|
164
|
+
) and isinstance(container_property.type, DirectNodeRelation):
|
|
165
|
+
connection_end_node_types[(view_ref, prop_ref)] = None
|
|
166
|
+
|
|
167
|
+
# reverse direct relation
|
|
168
|
+
if isinstance(property_, ReverseDirectRelationProperty) and property_.source:
|
|
169
|
+
connection_end_node_types[(view_ref, prop_ref)] = property_.source
|
|
170
|
+
|
|
171
|
+
# edge property
|
|
172
|
+
if isinstance(property_, EdgeProperty) and property_.source:
|
|
173
|
+
connection_end_node_types[(view_ref, prop_ref)] = property_.source
|
|
174
|
+
|
|
175
|
+
return connection_end_node_types
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def reverse_to_direct_mapping(
|
|
179
|
+
self,
|
|
180
|
+
) -> dict[tuple[ViewReference, str], tuple[ViewReference, ContainerDirectReference | ViewDirectReference]]:
|
|
181
|
+
"""Get a mapping of reverse direct relations to their corresponding source view and 'through' property."""
|
|
182
|
+
view_by_reference = self.view_by_reference(include_inherited_properties=False)
|
|
183
|
+
bidirectional_connections = {}
|
|
184
|
+
|
|
185
|
+
for view_ref, view in view_by_reference.items():
|
|
186
|
+
if not view.properties:
|
|
187
|
+
continue
|
|
188
|
+
for prop_ref, property_ in view.properties.items():
|
|
189
|
+
# reverse direct relation
|
|
190
|
+
if isinstance(property_, ReverseDirectRelationProperty):
|
|
191
|
+
bidirectional_connections[(view_ref, prop_ref)] = (
|
|
192
|
+
property_.source,
|
|
193
|
+
property_.through,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
return bidirectional_connections
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from ._identifiers import NameSpace
|
|
2
|
+
|
|
3
|
+
XML_SCHEMA_NAMESPACE = NameSpace("http://www.w3.org/2001/XMLSchema#")
|
|
4
|
+
|
|
5
|
+
CDF_CDM_SPACE = "cdf_cdm"
|
|
6
|
+
CDF_CDM_VERSION = "v1"
|
|
7
|
+
|
|
8
|
+
COGNITE_CONCEPTS_MAIN = (
|
|
9
|
+
"CogniteAsset",
|
|
10
|
+
"CogniteEquipment",
|
|
11
|
+
"CogniteActivity",
|
|
12
|
+
"CogniteTimeSeries",
|
|
13
|
+
"CogniteFile",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
COGNITE_CONCEPTS_INTERFACES = (
|
|
17
|
+
"CogniteDescribable",
|
|
18
|
+
"CogniteSourceable",
|
|
19
|
+
"CogniteSchedulable",
|
|
20
|
+
"CogniteVisualizable",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
COGNITE_CONCEPTS_CONFIGURATIONS = (
|
|
24
|
+
"CogniteSourceSystem",
|
|
25
|
+
"CogniteUnit",
|
|
26
|
+
"CogniteAssetClass",
|
|
27
|
+
"CogniteAssetType",
|
|
28
|
+
"CogniteEquipmentType",
|
|
29
|
+
"CogniteFileCategory",
|
|
30
|
+
)
|
|
31
|
+
COGNITE_CONCEPTS_ANNOTATIONS = (
|
|
32
|
+
"CogniteAnnotation",
|
|
33
|
+
"CogniteDiagramAnnotation",
|
|
34
|
+
)
|
|
35
|
+
COGNITE_CONCEPTS_3D = (
|
|
36
|
+
"CogniteCubeMap",
|
|
37
|
+
"CogniteCADRevision",
|
|
38
|
+
"CognitePointCloudVolume",
|
|
39
|
+
"Cognite360ImageAnnotation",
|
|
40
|
+
"Cognite3DObject",
|
|
41
|
+
"Cognite3DRevision",
|
|
42
|
+
"Cognite360Image",
|
|
43
|
+
"Cognite360ImageCollection",
|
|
44
|
+
"Cognite360ImageStation",
|
|
45
|
+
"CognitePointCloudModel",
|
|
46
|
+
"Cognite3DTransformation",
|
|
47
|
+
"Cognite360ImageModel",
|
|
48
|
+
"Cognite3DModel",
|
|
49
|
+
"CogniteCADModel",
|
|
50
|
+
"CognitePointCloudRevision",
|
|
51
|
+
"CogniteCADNode",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
COGNITE_CONCEPTS: tuple[str, ...] = (
|
|
55
|
+
*COGNITE_CONCEPTS_MAIN,
|
|
56
|
+
*COGNITE_CONCEPTS_INTERFACES,
|
|
57
|
+
*COGNITE_CONCEPTS_CONFIGURATIONS,
|
|
58
|
+
*COGNITE_CONCEPTS_ANNOTATIONS,
|
|
59
|
+
*COGNITE_CONCEPTS_3D,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
COGNITE_SPACES = (CDF_CDM_SPACE,)
|
|
63
|
+
|
|
64
|
+
# Defaults from https://docs.cognite.com/cdf/dm/dm_reference/dm_limits_and_restrictions#list-size-limits
|
|
65
|
+
|
|
66
|
+
DEFAULT_MAX_LIST_SIZE = 1000
|
|
67
|
+
DEFAULT_MAX_LIST_SIZE_DIRECT_RELATIONS = 100
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from pydantic import HttpUrl, RootModel, ValidationError
|
|
2
|
+
|
|
3
|
+
from cognite.neat.v0.core._utils.auxiliary import local_import
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class URI(RootModel[str]):
|
|
7
|
+
def __init__(self, value: str):
|
|
8
|
+
try:
|
|
9
|
+
# Use Pydantic's AnyUrl to validate the URI
|
|
10
|
+
_ = HttpUrl(value)
|
|
11
|
+
except ValidationError as e:
|
|
12
|
+
raise ValueError(f"Invalid URI: {value}") from e
|
|
13
|
+
super().__init__(value)
|
|
14
|
+
|
|
15
|
+
def __str__(self) -> str:
|
|
16
|
+
return self.root
|
|
17
|
+
|
|
18
|
+
def __repr__(self) -> str:
|
|
19
|
+
return f"URI({self.root!r})"
|
|
20
|
+
|
|
21
|
+
def as_rdflib_uriref(self): # type: ignore[no-untyped-def]
|
|
22
|
+
# rdflib is an optional dependency, so import here
|
|
23
|
+
local_import("rdflib", "rdflib")
|
|
24
|
+
from rdflib import URIRef
|
|
25
|
+
|
|
26
|
+
return URIRef(self.root)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class NameSpace(RootModel[str]):
|
|
30
|
+
def __init__(self, value: str):
|
|
31
|
+
try:
|
|
32
|
+
# Use Pydantic's AnyUrl to validate the URI
|
|
33
|
+
_ = HttpUrl(value)
|
|
34
|
+
except ValidationError as e:
|
|
35
|
+
raise ValueError(f"Invalid Namespace: {value}") from e
|
|
36
|
+
super().__init__(value)
|
|
37
|
+
|
|
38
|
+
def __str__(self) -> str:
|
|
39
|
+
return self.root
|
|
40
|
+
|
|
41
|
+
def __repr__(self) -> str:
|
|
42
|
+
return f"NameSpace({self.root!r})"
|
|
43
|
+
|
|
44
|
+
def term(self, name: str) -> URI:
|
|
45
|
+
# need to handle slices explicitly because of __getitem__ override
|
|
46
|
+
return URI(self.root + (name if isinstance(name, str) else ""))
|
|
47
|
+
|
|
48
|
+
def __getitem__(self, key: str) -> URI: # type: ignore[override]
|
|
49
|
+
return self.term(key)
|
|
50
|
+
|
|
51
|
+
def __getattr__(self, name: str) -> URI:
|
|
52
|
+
if name.startswith("__"): # ignore any special Python names!
|
|
53
|
+
raise AttributeError
|
|
54
|
+
return self.term(name)
|
|
55
|
+
|
|
56
|
+
def as_rdflib_namespace(self): # type: ignore[no-untyped-def]
|
|
57
|
+
# rdflib is an optional dependency, so import here
|
|
58
|
+
local_import("rdflib", "rdflib")
|
|
59
|
+
from rdflib import Namespace
|
|
60
|
+
|
|
61
|
+
return Namespace(self.root)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from cognite.neat._data_model.deployer.data_classes import DeploymentResult
|
|
5
|
+
from cognite.neat._issues import IssueList
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class OnSuccess(ABC):
|
|
9
|
+
"""Abstract base class for post-activity success handlers."""
|
|
10
|
+
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def run(self, data_model: Any) -> None:
|
|
13
|
+
"""Execute the success handler on the data model."""
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OnSuccessIssuesChecker(OnSuccess, ABC):
|
|
18
|
+
"""Abstract base class for post-activity success handlers that check for issues of the data model."""
|
|
19
|
+
|
|
20
|
+
def __init__(self) -> None:
|
|
21
|
+
self._issues = IssueList()
|
|
22
|
+
self._has_run = False
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def issues(self) -> IssueList:
|
|
26
|
+
if not self._has_run:
|
|
27
|
+
raise RuntimeError(f"{type(self).__name__} has not been run yet.")
|
|
28
|
+
return IssueList(self._issues)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class OnSuccessResultProducer(OnSuccess, ABC):
|
|
32
|
+
"""Abstract base class for post-activity success handlers that produce desired outcomes using the data model."""
|
|
33
|
+
|
|
34
|
+
def __init__(self) -> None:
|
|
35
|
+
self._results: DeploymentResult | None = None
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def result(self) -> DeploymentResult:
|
|
39
|
+
if self._results is None:
|
|
40
|
+
raise RuntimeError("SchemaDeployer has not been run yet.")
|
|
41
|
+
return self._results
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Generic
|
|
3
|
+
|
|
4
|
+
from cognite.neat._utils.useful_types import T_Item
|
|
5
|
+
|
|
6
|
+
from .data_classes import (
|
|
7
|
+
AddedField,
|
|
8
|
+
ChangedField,
|
|
9
|
+
FieldChange,
|
|
10
|
+
FieldChanges,
|
|
11
|
+
RemovedField,
|
|
12
|
+
SeverityType,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Differ(Generic[T_Item], ABC):
|
|
17
|
+
def __init__(self, parent_path: str | None = None) -> None:
|
|
18
|
+
self.parent_path = parent_path
|
|
19
|
+
|
|
20
|
+
def _get_path(self, field: str) -> str:
|
|
21
|
+
if self.parent_path:
|
|
22
|
+
return f"{self.parent_path}.{field}"
|
|
23
|
+
return field
|
|
24
|
+
|
|
25
|
+
def _diff_name_description(self, current: T_Item, new: T_Item, identifier: str | None = None) -> list[FieldChange]:
|
|
26
|
+
changes: list[FieldChange] = []
|
|
27
|
+
if hasattr(current, "name") and hasattr(new, "name"):
|
|
28
|
+
if current.name != new.name:
|
|
29
|
+
field_path = self._get_path(f"{identifier}.name" if identifier else "name")
|
|
30
|
+
changes.append(
|
|
31
|
+
ChangedField(
|
|
32
|
+
item_severity=SeverityType.SAFE,
|
|
33
|
+
field_path=field_path,
|
|
34
|
+
current_value=current.name,
|
|
35
|
+
new_value=new.name,
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
if hasattr(current, "description") and hasattr(new, "description"):
|
|
39
|
+
if current.description != new.description:
|
|
40
|
+
field_path = self._get_path(f"{identifier}.description" if identifier else "description")
|
|
41
|
+
changes.append(
|
|
42
|
+
ChangedField(
|
|
43
|
+
item_severity=SeverityType.SAFE,
|
|
44
|
+
field_path=field_path,
|
|
45
|
+
current_value=current.description,
|
|
46
|
+
new_value=new.description,
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
return changes
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class ItemDiffer(Differ[T_Item], ABC):
|
|
53
|
+
"""A generic class for comparing two items of the same type and reporting the differences."""
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def diff(self, current: T_Item, new: T_Item) -> list[FieldChange]:
|
|
57
|
+
"""Compare two items and return a list of changes.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
current: The resource as it is in CDF.
|
|
61
|
+
new: The resource as it is desired to be.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
A list of changes between the two resources.
|
|
65
|
+
"""
|
|
66
|
+
raise NotImplementedError()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ObjectDiffer(Differ[T_Item], ABC):
|
|
70
|
+
@abstractmethod
|
|
71
|
+
def diff(self, current: T_Item, new: T_Item, identifier: str) -> list[FieldChange]:
|
|
72
|
+
"""Compare two dict-like objects and return a list of changes.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
current: The resource as it is in CDF.
|
|
76
|
+
new: The resource as it is desired to be.
|
|
77
|
+
identifier: The field used to identify individual items within the objects.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
A list of changes between the two resources.
|
|
81
|
+
"""
|
|
82
|
+
raise NotImplementedError()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def field_differences(
|
|
86
|
+
parent_path: str,
|
|
87
|
+
current: dict[str, T_Item] | None,
|
|
88
|
+
new: dict[str, T_Item] | None,
|
|
89
|
+
add_severity: SeverityType,
|
|
90
|
+
remove_severity: SeverityType,
|
|
91
|
+
differ: ObjectDiffer[T_Item],
|
|
92
|
+
) -> list[FieldChange]:
|
|
93
|
+
"""Diff two containers of items.
|
|
94
|
+
|
|
95
|
+
A container is for example the properties, constraints, or indexes of a container,
|
|
96
|
+
properties of a space, views of a data model, etc.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
parent_path: The JSON path to the container being compared.
|
|
100
|
+
current: The items as they are in CDF.
|
|
101
|
+
new: The items as they are desired to be.
|
|
102
|
+
add_severity: The severity to assign to added items.
|
|
103
|
+
remove_severity: The severity to assign to removed items.
|
|
104
|
+
differ: The differ to use for comparing individual items.
|
|
105
|
+
|
|
106
|
+
"""
|
|
107
|
+
changes: list[FieldChange] = []
|
|
108
|
+
current_map = current or {}
|
|
109
|
+
new_map = new or {}
|
|
110
|
+
current_keys = set(current_map.keys())
|
|
111
|
+
new_keys = set(new_map.keys())
|
|
112
|
+
|
|
113
|
+
for key in sorted(new_keys - current_keys):
|
|
114
|
+
item_path = f"{parent_path}.{key}"
|
|
115
|
+
changes.append(
|
|
116
|
+
AddedField(
|
|
117
|
+
item_severity=add_severity,
|
|
118
|
+
field_path=item_path,
|
|
119
|
+
new_value=new_map[key],
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
for key in sorted(current_keys - new_keys):
|
|
124
|
+
changes.append(
|
|
125
|
+
RemovedField(
|
|
126
|
+
item_severity=remove_severity,
|
|
127
|
+
field_path=f"{parent_path}.{key}",
|
|
128
|
+
current_value=current_map[key],
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
for key in sorted(current_keys & new_keys):
|
|
133
|
+
item_path = f"{parent_path}.{key}"
|
|
134
|
+
cdf_item = current_map[key]
|
|
135
|
+
desired_item = new_map[key]
|
|
136
|
+
diffs = differ.diff(cdf_item, desired_item, identifier=key)
|
|
137
|
+
if diffs:
|
|
138
|
+
changes.append(FieldChanges(field_path=item_path, changes=diffs))
|
|
139
|
+
|
|
140
|
+
return changes
|