cognite-neat 0.123.26__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.
- cognite/neat/__init__.py +4 -3
- cognite/neat/_client/__init__.py +5 -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 +138 -0
- cognite/neat/_client/data_classes.py +44 -0
- cognite/neat/_client/data_model_api.py +115 -0
- cognite/neat/_client/init/credentials.py +70 -0
- cognite/neat/_client/init/env_vars.py +131 -0
- cognite/neat/_client/init/main.py +51 -0
- cognite/neat/_client/spaces_api.py +115 -0
- cognite/neat/_client/statistics_api.py +24 -0
- cognite/neat/_client/views_api.py +144 -0
- cognite/neat/_config.py +266 -0
- cognite/neat/_data_model/_analysis.py +571 -0
- cognite/neat/_data_model/_constants.py +74 -0
- cognite/neat/_data_model/_identifiers.py +61 -0
- cognite/neat/_data_model/_shared.py +41 -0
- cognite/neat/_data_model/_snapshot.py +134 -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 +644 -0
- cognite/neat/_data_model/deployer/deployer.py +431 -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 +480 -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 +344 -0
- cognite/neat/_data_model/importers/_table_importer/importer.py +192 -0
- cognite/neat/_data_model/importers/_table_importer/reader.py +1102 -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 +141 -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 +310 -0
- cognite/neat/_data_model/models/dms/_view_property.py +235 -0
- cognite/neat/_data_model/models/dms/_views.py +216 -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 +381 -0
- cognite/neat/_data_model/validation/dms/_base.py +25 -0
- cognite/neat/_data_model/validation/dms/_connections.py +681 -0
- cognite/neat/_data_model/validation/dms/_consistency.py +58 -0
- cognite/neat/_data_model/validation/dms/_containers.py +199 -0
- cognite/neat/_data_model/validation/dms/_limits.py +368 -0
- cognite/neat/_data_model/validation/dms/_orchestrator.py +70 -0
- cognite/neat/_data_model/validation/dms/_views.py +164 -0
- cognite/neat/_exceptions.py +68 -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 +476 -0
- cognite/neat/_session/_html/static/deployment.js +181 -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 +80 -0
- cognite/neat/_session/_html/templates/issues.html +45 -0
- cognite/neat/_session/_issues.py +81 -0
- cognite/neat/_session/_physical.py +294 -0
- cognite/neat/_session/_result/__init__.py +3 -0
- cognite/neat/_session/_result/_deployment/__init__.py +0 -0
- cognite/neat/_session/_result/_deployment/_physical/__init__.py +0 -0
- cognite/neat/_session/_result/_deployment/_physical/_changes.py +196 -0
- cognite/neat/_session/_result/_deployment/_physical/_statistics.py +180 -0
- cognite/neat/_session/_result/_deployment/_physical/serializer.py +35 -0
- cognite/neat/_session/_result/_result.py +31 -0
- cognite/neat/_session/_session.py +81 -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 +101 -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 +88 -0
- cognite/neat/_store/_store.py +220 -0
- cognite/neat/_utils/__init__.py +0 -0
- cognite/neat/_utils/_reader.py +194 -0
- cognite/neat/_utils/auxiliary.py +49 -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/repo.py +19 -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/_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 +8 -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 +5 -3
- cognite/neat/_v0/core/_data_model/__init__.py +0 -0
- cognite/neat/{core → _v0/core}/_data_model/_constants.py +7 -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 +18 -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 +16 -10
- 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 +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 +26 -19
- cognite/neat/{core → _v0/core}/_data_model/models/physical/_unverified.py +133 -37
- 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 +3 -2
- 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 +7 -3
- 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 +22 -12
- 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/{session → _v0}/engine/_load.py +1 -1
- 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 -15
- 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 +34 -21
- 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}/exceptions.py +5 -5
- cognite/neat/_version.py +1 -1
- cognite/neat/legacy.py +6 -0
- cognite_neat-1.0.22.dist-info/METADATA +123 -0
- cognite_neat-1.0.22.dist-info/RECORD +329 -0
- cognite_neat-1.0.22.dist-info/WHEEL +4 -0
- 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/session/_session/_data_model/__init__.py +0 -3
- cognite/neat/session/_session/_data_model/_read.py +0 -193
- cognite/neat/session/_session/_data_model/_routes.py +0 -45
- cognite/neat/session/_session/_data_model/_show.py +0 -147
- cognite/neat/session/_session/_data_model/_write.py +0 -335
- cognite_neat-0.123.26.dist-info/METADATA +0 -144
- cognite_neat-0.123.26.dist-info/RECORD +0 -201
- cognite_neat-0.123.26.dist-info/WHEEL +0 -4
- cognite_neat-0.123.26.dist-info/licenses/LICENSE +0 -201
- /cognite/neat/{core → _client/init}/__init__.py +0 -0
- /cognite/neat/{core/_client/_api → _data_model}/__init__.py +0 -0
- /cognite/neat/{core/_client/data_classes → _data_model/deployer}/__init__.py +0 -0
- /cognite/neat/{core/_data_model → _data_model/exporters/_table_exporter}/__init__.py +0 -0
- /cognite/neat/{core/_instances → _data_model/importers/_table_importer}/__init__.py +0 -0
- /cognite/neat/{core/_instances/extractors/_classic_cdf → _data_model/models}/__init__.py +0 -0
- /cognite/neat/{core/_utils → _data_model/models/conceptual}/__init__.py +0 -0
- /cognite/neat/{plugins/data_model → _data_model/validation}/__init__.py +0 -0
- /cognite/neat/{session/_session → _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/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}/engine/__init__.py +0 -0
- /cognite/neat/{session → _v0}/engine/_import.py +0 -0
- /cognite/neat/{session → _v0}/engine/_interface.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
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from cognite.neat._utils.useful_types import ReferenceObject
|
|
6
|
+
|
|
7
|
+
from ._constants import (
|
|
8
|
+
CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
|
|
9
|
+
DM_EXTERNAL_ID_PATTERN,
|
|
10
|
+
DM_VERSION_PATTERN,
|
|
11
|
+
INSTANCE_ID_PATTERN,
|
|
12
|
+
SPACE_FORMAT_PATTERN,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SpaceReference(ReferenceObject):
|
|
17
|
+
space: str = Field(
|
|
18
|
+
description="Id of the space.",
|
|
19
|
+
min_length=1,
|
|
20
|
+
max_length=43,
|
|
21
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ContainerReference(ReferenceObject):
|
|
26
|
+
type: Literal["container"] = Field("container", exclude=True)
|
|
27
|
+
space: str = Field(
|
|
28
|
+
description="Id of the space hosting (containing) the container.",
|
|
29
|
+
min_length=1,
|
|
30
|
+
max_length=43,
|
|
31
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
32
|
+
)
|
|
33
|
+
external_id: str = Field(
|
|
34
|
+
description="External-id of the container.",
|
|
35
|
+
min_length=1,
|
|
36
|
+
max_length=255,
|
|
37
|
+
pattern=DM_EXTERNAL_ID_PATTERN,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def __str__(self) -> str:
|
|
41
|
+
return f"{self.space}:{self.external_id}"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ViewReference(ReferenceObject):
|
|
45
|
+
type: Literal["view"] = Field("view", exclude=True)
|
|
46
|
+
space: str = Field(
|
|
47
|
+
description="Id of the space that the view belongs to.",
|
|
48
|
+
min_length=1,
|
|
49
|
+
max_length=43,
|
|
50
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
51
|
+
)
|
|
52
|
+
external_id: str = Field(
|
|
53
|
+
description="External-id of the view.",
|
|
54
|
+
min_length=1,
|
|
55
|
+
max_length=255,
|
|
56
|
+
pattern=DM_EXTERNAL_ID_PATTERN,
|
|
57
|
+
)
|
|
58
|
+
version: str = Field(
|
|
59
|
+
description="Version of the view.",
|
|
60
|
+
max_length=43,
|
|
61
|
+
pattern=DM_VERSION_PATTERN,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def __str__(self) -> str:
|
|
65
|
+
return f"{self.space}:{self.external_id}(version={self.version})"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class DataModelReference(ReferenceObject):
|
|
69
|
+
space: str = Field(
|
|
70
|
+
description="Id of the space that the data model belongs to.",
|
|
71
|
+
min_length=1,
|
|
72
|
+
max_length=43,
|
|
73
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
74
|
+
)
|
|
75
|
+
external_id: str = Field(
|
|
76
|
+
description="External-id of the data model.",
|
|
77
|
+
min_length=1,
|
|
78
|
+
max_length=255,
|
|
79
|
+
pattern=DM_EXTERNAL_ID_PATTERN,
|
|
80
|
+
)
|
|
81
|
+
version: str = Field(
|
|
82
|
+
description="Version of the data model.",
|
|
83
|
+
max_length=43,
|
|
84
|
+
pattern=DM_VERSION_PATTERN,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def __str__(self) -> str:
|
|
88
|
+
return f"{self.space}:{self.external_id}(version={self.version})"
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class NodeReference(ReferenceObject):
|
|
92
|
+
space: str = Field(
|
|
93
|
+
description="Id of the space hosting (containing) the node.",
|
|
94
|
+
min_length=1,
|
|
95
|
+
max_length=43,
|
|
96
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
97
|
+
)
|
|
98
|
+
external_id: str = Field(
|
|
99
|
+
description="External-id of the node.",
|
|
100
|
+
min_length=1,
|
|
101
|
+
max_length=255,
|
|
102
|
+
pattern=INSTANCE_ID_PATTERN,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ContainerDirectReference(ReferenceObject):
|
|
107
|
+
source: ContainerReference = Field(
|
|
108
|
+
description="Reference to the container from where this relation is inherited.",
|
|
109
|
+
)
|
|
110
|
+
identifier: str = Field(
|
|
111
|
+
description="Identifier of the relation in the source container.",
|
|
112
|
+
min_length=1,
|
|
113
|
+
max_length=255,
|
|
114
|
+
pattern=CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def __str__(self) -> str:
|
|
118
|
+
return f"{self.source!s}.{self.identifier}"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class ViewDirectReference(ReferenceObject):
|
|
122
|
+
source: ViewReference = Field(
|
|
123
|
+
description="Reference to the view from where this relation is inherited.",
|
|
124
|
+
)
|
|
125
|
+
identifier: str = Field(
|
|
126
|
+
description="Identifier of the relation in the source view.",
|
|
127
|
+
min_length=1,
|
|
128
|
+
max_length=255,
|
|
129
|
+
pattern=CONTAINER_AND_VIEW_PROPERTIES_IDENTIFIER_PATTERN,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def __str__(self) -> str:
|
|
133
|
+
return f"{self.source!s}.{self.identifier}"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class ContainerIndexReference(ContainerReference):
|
|
137
|
+
identifier: str
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class ContainerConstraintReference(ContainerReference):
|
|
141
|
+
identifier: str
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
|
|
3
|
+
from ._base import Resource
|
|
4
|
+
from ._container import ContainerRequest
|
|
5
|
+
from ._data_model import DataModelRequest
|
|
6
|
+
from ._references import NodeReference
|
|
7
|
+
from ._space import SpaceRequest
|
|
8
|
+
from ._views import ViewRequest
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RequestSchema(Resource):
|
|
12
|
+
"""Represents a schema for creating or updating a data model in DMS."""
|
|
13
|
+
|
|
14
|
+
data_model: DataModelRequest
|
|
15
|
+
views: list[ViewRequest] = Field(default_factory=list)
|
|
16
|
+
containers: list[ContainerRequest] = Field(default_factory=list)
|
|
17
|
+
spaces: list[SpaceRequest] = Field(default_factory=list)
|
|
18
|
+
node_types: list[NodeReference] = Field(default_factory=list)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
|
|
3
|
+
from pydantic import Field, field_validator
|
|
4
|
+
|
|
5
|
+
from cognite.neat._data_model.models.dms._references import SpaceReference
|
|
6
|
+
from cognite.neat._utils.text import humanize_collection
|
|
7
|
+
|
|
8
|
+
from ._base import APIResource, Resource, WriteableResource
|
|
9
|
+
from ._constants import FORBIDDEN_SPACES, SPACE_FORMAT_PATTERN
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Space(Resource, APIResource[SpaceReference], ABC):
|
|
13
|
+
space: str = Field(
|
|
14
|
+
description="The Space identifier (id).",
|
|
15
|
+
min_length=1,
|
|
16
|
+
max_length=43,
|
|
17
|
+
pattern=SPACE_FORMAT_PATTERN,
|
|
18
|
+
)
|
|
19
|
+
name: str | None = Field(None, description="Name of the space.", max_length=255)
|
|
20
|
+
description: str | None = Field(None, description="The description of the space.", max_length=1024)
|
|
21
|
+
|
|
22
|
+
@field_validator("space")
|
|
23
|
+
def check_forbidden_space_value(cls, val: str) -> str:
|
|
24
|
+
"""Check the space name not present in forbidden set"""
|
|
25
|
+
if val in FORBIDDEN_SPACES:
|
|
26
|
+
raise ValueError(f"{val!r} is a reserved space. Reserved Spaces: {humanize_collection(FORBIDDEN_SPACES)}")
|
|
27
|
+
return val
|
|
28
|
+
|
|
29
|
+
def as_reference(self) -> SpaceReference:
|
|
30
|
+
return SpaceReference(space=self.space)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SpaceRequest(Space): ...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SpaceResponse(Space, WriteableResource[Space]):
|
|
37
|
+
created_time: int = Field(
|
|
38
|
+
description="When the space was created. The number of milliseconds since 00:00:00 Thursday, 1 January 1970, "
|
|
39
|
+
"Coordinated Universal Time (UTC), minus leap seconds."
|
|
40
|
+
)
|
|
41
|
+
last_updated_time: int = Field(
|
|
42
|
+
description="When the space was last updated. The number of milliseconds since 00:00:00 Thursday, "
|
|
43
|
+
"1 January 1970, Coordinated Universal Time (UTC), minus leap seconds."
|
|
44
|
+
)
|
|
45
|
+
is_global: bool = Field(description="Whether the space is a global space.")
|
|
46
|
+
|
|
47
|
+
def as_request(self) -> "SpaceRequest":
|
|
48
|
+
return SpaceRequest.model_validate(self.model_dump(by_alias=True))
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import Annotated, Any
|
|
2
|
+
|
|
3
|
+
from pydantic import BeforeValidator
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def str_as_bool(value: Any) -> Any:
|
|
7
|
+
if isinstance(value, str):
|
|
8
|
+
val = value.lower()
|
|
9
|
+
if val in {"true", "1", "yes"}:
|
|
10
|
+
return True
|
|
11
|
+
if val in {"false", "0", "no"}:
|
|
12
|
+
return False
|
|
13
|
+
# All other cases are handled by Pydantic's built-in bool validator
|
|
14
|
+
return value
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
Bool = Annotated[bool, BeforeValidator(str_as_bool, str)]
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
from typing import Annotated, Any, Literal, TypeAlias, get_args
|
|
3
|
+
|
|
4
|
+
from pydantic import BeforeValidator, Field, JsonValue, TypeAdapter, model_serializer
|
|
5
|
+
from pydantic_core.core_schema import FieldSerializationInfo
|
|
6
|
+
|
|
7
|
+
from cognite.neat._utils.text import humanize_collection
|
|
8
|
+
from cognite.neat._utils.useful_types import BaseModelObject
|
|
9
|
+
|
|
10
|
+
from ._references import ContainerReference, NodeReference, ViewReference
|
|
11
|
+
|
|
12
|
+
# Base classes and helpers
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Parameter(BaseModelObject):
|
|
16
|
+
parameter: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class FilterDataDefinition(BaseModelObject, ABC):
|
|
20
|
+
"""Base class for filter data models."""
|
|
21
|
+
|
|
22
|
+
# This is an internal field used for discriminating between filter types. It is not part of the actual
|
|
23
|
+
# data sent to or received from the API. See the _move_filter_key function for more details.
|
|
24
|
+
filter_type: str = Field(..., exclude=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PropertyReference(FilterDataDefinition, ABC):
|
|
28
|
+
"""Represents the property path in filters."""
|
|
29
|
+
|
|
30
|
+
property: list[str] = Field(..., min_length=2, max_length=3)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Leaf filters that follows the standard pattern
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class EqualsFilterData(PropertyReference):
|
|
37
|
+
filter_type: Literal["equals"] = Field("equals", exclude=True)
|
|
38
|
+
value: JsonValue | PropertyReference
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class InFilterData(PropertyReference):
|
|
42
|
+
filter_type: Literal["in"] = Field("in", exclude=True)
|
|
43
|
+
values: list[JsonValue] | PropertyReference
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class RangeFilterData(PropertyReference):
|
|
47
|
+
filter_type: Literal["range"] = Field("range", exclude=True)
|
|
48
|
+
gt: str | int | float | PropertyReference | None = None
|
|
49
|
+
gte: str | int | float | PropertyReference | None = None
|
|
50
|
+
lt: str | int | float | PropertyReference | None = None
|
|
51
|
+
lte: str | int | float | PropertyReference | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class PrefixFilterData(PropertyReference):
|
|
55
|
+
filter_type: Literal["prefix"] = Field("prefix", exclude=True)
|
|
56
|
+
value: str | Parameter
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ExistsFilterData(PropertyReference):
|
|
60
|
+
filter_type: Literal["exists"] = Field("exists", exclude=True)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ContainsAnyFilterData(PropertyReference):
|
|
64
|
+
filter_type: Literal["containsAny"] = Field("containsAny", exclude=True)
|
|
65
|
+
values: list[JsonValue] | PropertyReference
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class ContainsAllFilterData(PropertyReference):
|
|
69
|
+
filter_type: Literal["containsAll"] = Field("containsAll", exclude=True)
|
|
70
|
+
values: list[JsonValue] | PropertyReference
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class MatchAllFilterData(FilterDataDefinition):
|
|
74
|
+
filter_type: Literal["matchAll"] = Field("matchAll", exclude=True)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class NestedFilterData(FilterDataDefinition):
|
|
78
|
+
filter_type: Literal["nested"] = Field("nested", exclude=True)
|
|
79
|
+
scope: list[str] = Field(..., min_length=1, max_length=3)
|
|
80
|
+
filter: "Filter"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class OverlapsFilterData(PropertyReference):
|
|
84
|
+
filter_type: Literal["overlaps"] = Field("overlaps", exclude=True)
|
|
85
|
+
start_property: list[str] = Field(..., min_length=1, max_length=3)
|
|
86
|
+
end_property: list[str] = Field(..., min_length=1, max_length=3)
|
|
87
|
+
gt: str | int | float | PropertyReference | None = None
|
|
88
|
+
gte: str | int | float | PropertyReference | None = None
|
|
89
|
+
lt: str | int | float | PropertyReference | None = None
|
|
90
|
+
lte: str | int | float | PropertyReference | None = None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class ListFilterDataDefinition(FilterDataDefinition, ABC):
|
|
94
|
+
"""Base class for filters that operate on lists of values."""
|
|
95
|
+
|
|
96
|
+
data: list[Any]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
## Leaf filters with custom serialization logic due to creativity in the API design
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class HasDataFilter(ListFilterDataDefinition):
|
|
103
|
+
filter_type: Literal["hasData"] = Field("hasData", exclude=True)
|
|
104
|
+
data: list[ViewReference | ContainerReference]
|
|
105
|
+
|
|
106
|
+
# MyPy complains about thet signature of the method here, even though its compatible with the pydantic source code.
|
|
107
|
+
# And tests are passing fine.
|
|
108
|
+
@model_serializer(mode="plain") # type: ignore[type-var]
|
|
109
|
+
def serialize_model(self, info: FieldSerializationInfo) -> list[dict[str, Any]]:
|
|
110
|
+
output: list[dict[str, Any]] = []
|
|
111
|
+
for item in self.data:
|
|
112
|
+
item_dict = item.model_dump(**vars(info))
|
|
113
|
+
if isinstance(item, ViewReference):
|
|
114
|
+
item_dict["type"] = "view"
|
|
115
|
+
elif isinstance(item, ContainerReference):
|
|
116
|
+
item_dict["type"] = "container"
|
|
117
|
+
output.append(item_dict)
|
|
118
|
+
return output
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class InstanceReferencesFilterData(ListFilterDataDefinition):
|
|
122
|
+
filter_type: Literal["instanceReferences"] = Field("instanceReferences", exclude=True)
|
|
123
|
+
data: list[NodeReference]
|
|
124
|
+
|
|
125
|
+
# MyPy complains about thet signature of the method here, even though its compatible with the pydantic source code.
|
|
126
|
+
# And tests are passing fine.
|
|
127
|
+
@model_serializer(mode="plain") # type: ignore[type-var]
|
|
128
|
+
def serialize_model(self, info: FieldSerializationInfo) -> list[dict[str, Any]]:
|
|
129
|
+
return [item.model_dump(**vars(info)) for item in self.data]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
## Logical filters combining other filters
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class AndFilter(ListFilterDataDefinition):
|
|
136
|
+
filter_type: Literal["and"] = Field("and", exclude=True)
|
|
137
|
+
data: "list[Filter]"
|
|
138
|
+
|
|
139
|
+
# MyPy complains about thet signature of the method here, even though its compatible with the pydantic source code.
|
|
140
|
+
# And tests are passing fine.
|
|
141
|
+
@model_serializer(mode="plain") # type: ignore[type-var]
|
|
142
|
+
def serialize_model(self, info: FieldSerializationInfo) -> list[dict[str, Any]]:
|
|
143
|
+
return [FilterAdapter.dump_python(item, **vars(info)) for item in self.data]
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class OrFilter(ListFilterDataDefinition):
|
|
147
|
+
filter_type: Literal["or"] = Field("or", exclude=True)
|
|
148
|
+
data: "list[Filter]"
|
|
149
|
+
|
|
150
|
+
# MyPy complains about thet signature of the method here, even though its compatible with the pydantic source code.
|
|
151
|
+
# And tests are passing fine.
|
|
152
|
+
@model_serializer(mode="plain") # type: ignore[type-var]
|
|
153
|
+
def serialize_model(self, info: FieldSerializationInfo) -> list[dict[str, Any]]:
|
|
154
|
+
return [FilterAdapter.dump_python(item, **vars(info)) for item in self.data]
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class NotFilter(FilterDataDefinition):
|
|
158
|
+
filter_type: Literal["not"] = Field("not", exclude=True)
|
|
159
|
+
data: "Filter"
|
|
160
|
+
|
|
161
|
+
# MyPy complains about thet signature of the method here, even though its compatible with the pydantic source code.
|
|
162
|
+
# And tests are passing fine.
|
|
163
|
+
@model_serializer(mode="plain") # type: ignore[type-var]
|
|
164
|
+
def serialize_model(self, info: FieldSerializationInfo) -> dict[str, Any]:
|
|
165
|
+
return FilterAdapter.dump_python(self.data, **vars(info))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
FilterData = Annotated[
|
|
169
|
+
EqualsFilterData
|
|
170
|
+
| PrefixFilterData
|
|
171
|
+
| InFilterData
|
|
172
|
+
| RangeFilterData
|
|
173
|
+
| ExistsFilterData
|
|
174
|
+
| ContainsAnyFilterData
|
|
175
|
+
| ContainsAllFilterData
|
|
176
|
+
| MatchAllFilterData
|
|
177
|
+
| NestedFilterData
|
|
178
|
+
| OverlapsFilterData
|
|
179
|
+
| HasDataFilter
|
|
180
|
+
| InstanceReferencesFilterData
|
|
181
|
+
| AndFilter
|
|
182
|
+
| OrFilter
|
|
183
|
+
| NotFilter,
|
|
184
|
+
Field(discriminator="filter_type"),
|
|
185
|
+
]
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
FilterTypes: TypeAlias = Literal[
|
|
189
|
+
"equals",
|
|
190
|
+
"prefix",
|
|
191
|
+
"in",
|
|
192
|
+
"range",
|
|
193
|
+
"exists",
|
|
194
|
+
"containsAny",
|
|
195
|
+
"containsAll",
|
|
196
|
+
"matchAll",
|
|
197
|
+
"nested",
|
|
198
|
+
"overlaps",
|
|
199
|
+
"hasData",
|
|
200
|
+
"instanceReferences",
|
|
201
|
+
"and",
|
|
202
|
+
"or",
|
|
203
|
+
"not",
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
LegacyFilterTypes: TypeAlias = Literal["invalid"]
|
|
207
|
+
|
|
208
|
+
AVAILABLE_FILTERS: frozenset[str] = frozenset(get_args(FilterTypes))
|
|
209
|
+
LEGACY_FILTERS: frozenset[str] = frozenset(get_args(LegacyFilterTypes))
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _move_filter_key(value: Any) -> Any:
|
|
213
|
+
"""The DMS API filters have an unusual structure.
|
|
214
|
+
|
|
215
|
+
It has the filter type as the key of the outer dict, and then the actual filter data as the value, e.g.,
|
|
216
|
+
{
|
|
217
|
+
"equals": {
|
|
218
|
+
"property": [...],
|
|
219
|
+
"value": ...
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
We could have modeled it that way with Pydantic, and had an union of pydantic models of all possible filter types.
|
|
223
|
+
However, validating union types in Pydantic without a discriminator leads to poor error messages. If the filter
|
|
224
|
+
data does not comply with any of the union types, Pydantic will give one error message per union type. For exampl,
|
|
225
|
+
if the user writes
|
|
226
|
+
{
|
|
227
|
+
"equals": {
|
|
228
|
+
"property": "my_property" # Should be a list,
|
|
229
|
+
"value": 'my_value'
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
Pydantic will give 15 error messages, one for each filter type in the union, saying that the data does not
|
|
233
|
+
comply with that filter type. This is not very user-friendly.
|
|
234
|
+
|
|
235
|
+
Instead, we introduce an internal field "filter_type" inside the filter data models, and use that as a
|
|
236
|
+
discriminator. This will enable the validation to be two steps. First, we validate the outer key and
|
|
237
|
+
that it is a known filter type. Then, we move that key inside the filter data as the "filter_type" field, and
|
|
238
|
+
validate the filter data against the correct model based on that discriminator.
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
This function transforms the data from the outer-key format to the inner-key format. For example, it transforms
|
|
242
|
+
the equals filter form above into
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
"equals": {
|
|
246
|
+
"property": [...],
|
|
247
|
+
"value": ...,
|
|
248
|
+
"filterType": "equals"
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
"""
|
|
252
|
+
# legacy filter which we want to ignore
|
|
253
|
+
if _is_legacy_filter(value):
|
|
254
|
+
return None
|
|
255
|
+
if not isinstance(value, dict):
|
|
256
|
+
return value
|
|
257
|
+
if len(value) != 1:
|
|
258
|
+
raise ValueError("Filter data must have exactly one key.")
|
|
259
|
+
if "filterType" in value:
|
|
260
|
+
# Already in the correct format
|
|
261
|
+
return value
|
|
262
|
+
key, data = next(iter(value.items()))
|
|
263
|
+
# Check if inner data already has filterType (already processed by a previous recursive call)
|
|
264
|
+
if isinstance(data, dict) and "filterType" in data:
|
|
265
|
+
return value
|
|
266
|
+
if key not in AVAILABLE_FILTERS:
|
|
267
|
+
raise ValueError(
|
|
268
|
+
f"Unknown filter type: {key!r}. Available filter types: {humanize_collection(AVAILABLE_FILTERS)}."
|
|
269
|
+
)
|
|
270
|
+
if isinstance(data, dict) and key == "not":
|
|
271
|
+
# Not is a recursive filter, so we need to move the filter key inside its data as well
|
|
272
|
+
output = _move_filter_key(data.copy())
|
|
273
|
+
return {key: {"filterType": key, "data": output}}
|
|
274
|
+
elif isinstance(data, dict):
|
|
275
|
+
output = data.copy()
|
|
276
|
+
output["filterType"] = key
|
|
277
|
+
return {key: output}
|
|
278
|
+
elif isinstance(data, list) and key in {"and", "or"}:
|
|
279
|
+
# And and Or are recursive filters, so we need to move the filter key inside each of their data items as well
|
|
280
|
+
return {key: {"filterType": key, "data": [_move_filter_key(item) for item in data]}}
|
|
281
|
+
elif isinstance(data, list):
|
|
282
|
+
# Leaf list filters, hasData and instanceReferences
|
|
283
|
+
return {key: {"filterType": key, "data": data}}
|
|
284
|
+
else:
|
|
285
|
+
# Let the regular validation handle it (possible not an issue)
|
|
286
|
+
return value
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _is_legacy_filter(filter_obj: Any) -> bool:
|
|
290
|
+
"""Check if filter is a legacy filter no longer supported by DMS API"""
|
|
291
|
+
|
|
292
|
+
def traverse(obj: Any) -> bool:
|
|
293
|
+
if isinstance(obj, dict):
|
|
294
|
+
for key, value in obj.items():
|
|
295
|
+
if key in LEGACY_FILTERS:
|
|
296
|
+
return True
|
|
297
|
+
if traverse(value):
|
|
298
|
+
return True
|
|
299
|
+
elif isinstance(obj, list):
|
|
300
|
+
for item in obj:
|
|
301
|
+
if traverse(item):
|
|
302
|
+
return True
|
|
303
|
+
return False
|
|
304
|
+
|
|
305
|
+
return traverse(filter_obj)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
Filter = Annotated[dict[FilterTypes, FilterData] | None, BeforeValidator(_move_filter_key)]
|
|
309
|
+
|
|
310
|
+
FilterAdapter: TypeAdapter[Filter] = TypeAdapter(Filter)
|