From bbeb0916b470122f36319587e6e8c2514d390587 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sat, 1 Mar 2025 11:59:27 +0100 Subject: [PATCH 1/6] tests: added test case --- .../data_models/1.Production.container.yaml | 38 ++++ .../data_models/10.SimNode.container.yaml | 22 +++ .../data_models/12.SimSubNode.container.yaml | 22 +++ .../data_models/13.SimEdge.container.yaml | 38 ++++ .../data_models/14.Property.container.yaml | 67 +++++++ .../data_models/15.Coordinate.container.yaml | 41 ++++ .../data_models/16.Coordinates.container.yaml | 49 +++++ .../17.ModelExecutionEnvironment.view.yaml | 25 +++ .../data_models/18.Coordinate.view.yaml | 35 ++++ .../data_models/19.Coordinates.view.yaml | 42 +++++ .../2.SimulationModel.container.yaml | 44 +++++ .../data_models/20.SimEdge.view.yaml | 47 +++++ .../21.ProductionTimeseries.view.yaml | 23 +++ .../data_models/22.SimNode.view.yaml | 39 ++++ .../data_models/23.Production.view.yaml | 58 ++++++ .../data_models/24.SimSubNode.view.yaml | 23 +++ .../25.SimulationResultFile.view.yaml | 23 +++ .../data_models/26.InputProperty.view.yaml | 17 ++ .../data_models/28.OutputProperty.view.yaml | 17 ++ .../data_models/29.Property.view.yaml | 69 +++++++ .../3.strongly-coupled-model.datamodel.yaml | 178 ++++++++++++++++++ .../data_models/30.SimulationModel.view.yaml | 81 ++++++++ .../data_models/31.SimNodeAndEdge.view.yaml | 88 +++++++++ .../data_models/5.my.space.yaml | 3 + ...6.ModelExecutionEnvironment.container.yaml | 32 ++++ .../7.ProductionTimeseries.container.yaml | 22 +++ .../8.SimNodeAndEdge.container.yaml | 48 +++++ .../9.SimulationResultFile.container.yaml | 22 +++ 28 files changed, 1213 insertions(+) create mode 100644 tests/data/strongly_coupled_model/data_models/1.Production.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/10.SimNode.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/12.SimSubNode.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/13.SimEdge.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/14.Property.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/15.Coordinate.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/16.Coordinates.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/17.ModelExecutionEnvironment.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/18.Coordinate.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/19.Coordinates.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/2.SimulationModel.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/20.SimEdge.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/21.ProductionTimeseries.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/22.SimNode.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/23.Production.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/24.SimSubNode.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/25.SimulationResultFile.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/26.InputProperty.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/28.OutputProperty.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/29.Property.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/3.strongly-coupled-model.datamodel.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/30.SimulationModel.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/31.SimNodeAndEdge.view.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/5.my.space.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/6.ModelExecutionEnvironment.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/7.ProductionTimeseries.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/8.SimNodeAndEdge.container.yaml create mode 100644 tests/data/strongly_coupled_model/data_models/9.SimulationResultFile.container.yaml diff --git a/tests/data/strongly_coupled_model/data_models/1.Production.container.yaml b/tests/data/strongly_coupled_model/data_models/1.Production.container.yaml new file mode 100644 index 000000000..fd395c25e --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/1.Production.container.yaml @@ -0,0 +1,38 @@ +space: strongly-coupled-model +externalId: Production +name: Production +description: Missing +properties: + id: + type: + list: false + collation: ucs_basic + type: text + immutable: false + nullable: true + autoIncrement: false + name: id + description: Missing + type: + type: + list: false + collation: ucs_basic + type: text + immutable: false + nullable: true + autoIncrement: false + name: type +constraints: + cogniteAssetPresent: + require: + space: cdf_cdm + externalId: CogniteAsset + type: container + constraintType: requires +indexes: + id: + properties: + - id + cursorable: true + indexType: btree +usedFor: node diff --git a/tests/data/strongly_coupled_model/data_models/10.SimNode.container.yaml b/tests/data/strongly_coupled_model/data_models/10.SimNode.container.yaml new file mode 100644 index 000000000..6a3da9263 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/10.SimNode.container.yaml @@ -0,0 +1,22 @@ +space: strongly-coupled-model +externalId: SimNode +name: SimNode +usedFor: node +description: Missing +properties: + coordinate: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: coordinate +constraints: + cogniteDescribablePresent: + require: + space: strongly-coupled-model + externalId: SimNodeAndEdge + type: container + constraintType: requires +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/12.SimSubNode.container.yaml b/tests/data/strongly_coupled_model/data_models/12.SimSubNode.container.yaml new file mode 100644 index 000000000..2df24d155 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/12.SimSubNode.container.yaml @@ -0,0 +1,22 @@ +space: strongly-coupled-model +externalId: SimSubNode +name: SimSubNode +usedFor: node +description: Missing +properties: + parent: + type: + list: false + type: direct + immutable: false + nullable: true + autoIncrement: false + name: parent +constraints: + cogniteDescribablePresent: + require: + space: strongly-coupled-model + externalId: SimNode + type: container + constraintType: requires +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/13.SimEdge.container.yaml b/tests/data/strongly_coupled_model/data_models/13.SimEdge.container.yaml new file mode 100644 index 000000000..f8412a63a --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/13.SimEdge.container.yaml @@ -0,0 +1,38 @@ +space: strongly-coupled-model +externalId: SimEdge +name: SimEdge +usedFor: node +description: Missing +properties: + source: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: source + destination: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: destination + coordinates: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: coordinates +constraints: + cogniteDescribablePresent: + require: + space: strongly-coupled-model + externalId: SimNodeAndEdge + type: container + constraintType: requires +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/14.Property.container.yaml b/tests/data/strongly_coupled_model/data_models/14.Property.container.yaml new file mode 100644 index 000000000..5ef9e1aee --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/14.Property.container.yaml @@ -0,0 +1,67 @@ +space: strongly-coupled-model +externalId: Property +name: Property +usedFor: node +description: Missing +properties: + type: + type: + type: enum + values: + Input: {} + Output: {} + immutable: true + nullable: false + autoIncrement: false + name: type + description: Missing + nodeOrEdge: + type: + list: false + type: direct + immutable: false + nullable: true + autoIncrement: false + name: nodeOrEdge + workflow: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: workflow + unit: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: unit + valueClassicRef: + type: + type: timeseries + list: false + immutable: false + nullable: true + autoIncrement: false + name: value + valueRef: + type: + list: false + type: direct + immutable: false + nullable: true + autoIncrement: false + name: valueRef +constraints: + cogniteDescribablePresent: + require: + space: cdf_cdm + externalId: CogniteDescribable + type: container + constraintType: requires +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/15.Coordinate.container.yaml b/tests/data/strongly_coupled_model/data_models/15.Coordinate.container.yaml new file mode 100644 index 000000000..d8f3bab95 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/15.Coordinate.container.yaml @@ -0,0 +1,41 @@ +space: strongly-coupled-model +externalId: Coordinate +name: Coordinate +usedFor: node +description: Missing +properties: + elevation: + type: + type: float64 + list: false + immutable: false + nullable: true + autoIncrement: false + name: elevation + lat: + type: + type: float64 + list: true + immutable: false + nullable: true + autoIncrement: false + name: lat + long: + type: + type: float64 + list: true + immutable: false + nullable: true + autoIncrement: false + name: long + crs: + type: + type: text + list: true + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: crs +constraints: {} +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/16.Coordinates.container.yaml b/tests/data/strongly_coupled_model/data_models/16.Coordinates.container.yaml new file mode 100644 index 000000000..0428c4590 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/16.Coordinates.container.yaml @@ -0,0 +1,49 @@ +space: strongly-coupled-model +externalId: Coordinates +name: Coordinates +usedFor: node +description: Missing +properties: + elevation: + type: + type: float64 + list: true + immutable: false + nullable: true + autoIncrement: false + name: elevation + lat: + type: + type: float64 + list: true + immutable: false + nullable: true + autoIncrement: false + name: lat + long: + type: + type: float64 + list: true + immutable: false + nullable: true + autoIncrement: false + name: long + horizontalDistance: + type: + type: float64 + list: true + immutable: false + nullable: true + autoIncrement: false + name: horizontalDistance + crs: + type: + type: text + list: true + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: crs +constraints: {} +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/17.ModelExecutionEnvironment.view.yaml b/tests/data/strongly_coupled_model/data_models/17.ModelExecutionEnvironment.view.yaml new file mode 100644 index 000000000..3878f7c08 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/17.ModelExecutionEnvironment.view.yaml @@ -0,0 +1,25 @@ +externalId: ModelExecutionEnvironment +space: strongly-coupled-model +version: v1 +name: ModelExecutionEnvironment +description: Missing +properties: + type: + container: + type: container + space: strongly-coupled-model + externalId: ModelExecutionEnvironment + containerPropertyIdentifier: type + name: type + version: + container: + type: container + space: strongly-coupled-model + externalId: ModelExecutionEnvironment + containerPropertyIdentifier: version + name: version +implements: +- type: view + space: cdf_cdm + externalId: CogniteDescribable + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/18.Coordinate.view.yaml b/tests/data/strongly_coupled_model/data_models/18.Coordinate.view.yaml new file mode 100644 index 000000000..19a0f90e4 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/18.Coordinate.view.yaml @@ -0,0 +1,35 @@ +externalId: Coordinate +space: strongly-coupled-model +version: v1 +name: Coordinate +description: Missing +properties: + elevation: + container: + type: container + space: strongly-coupled-model + externalId: Coordinate + containerPropertyIdentifier: elevation + name: elevation + lat: + container: + type: container + space: strongly-coupled-model + externalId: Coordinate + containerPropertyIdentifier: lat + name: lat + long: + container: + type: container + space: strongly-coupled-model + externalId: Coordinate + containerPropertyIdentifier: long + name: long + crs: + container: + type: container + space: strongly-coupled-model + externalId: Coordinate + containerPropertyIdentifier: crs + name: crs +implements: [] diff --git a/tests/data/strongly_coupled_model/data_models/19.Coordinates.view.yaml b/tests/data/strongly_coupled_model/data_models/19.Coordinates.view.yaml new file mode 100644 index 000000000..49efeb410 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/19.Coordinates.view.yaml @@ -0,0 +1,42 @@ +externalId: Coordinates +space: strongly-coupled-model +version: v1 +name: Coordinates +description: Missing +properties: + elevation: + container: + type: container + space: strongly-coupled-model + externalId: Coordinates + containerPropertyIdentifier: elevation + name: elevation + lat: + container: + type: container + space: strongly-coupled-model + externalId: Coordinates + containerPropertyIdentifier: lat + name: lat + long: + container: + type: container + space: strongly-coupled-model + externalId: Coordinates + containerPropertyIdentifier: long + name: long + horizontalDistance: + container: + type: container + space: strongly-coupled-model + externalId: Coordinates + containerPropertyIdentifier: horizontalDistance + name: horizontalDistance + crs: + container: + type: container + space: strongly-coupled-model + externalId: Coordinates + containerPropertyIdentifier: crs + name: crs +implements: [] diff --git a/tests/data/strongly_coupled_model/data_models/2.SimulationModel.container.yaml b/tests/data/strongly_coupled_model/data_models/2.SimulationModel.container.yaml new file mode 100644 index 000000000..96c4c021d --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/2.SimulationModel.container.yaml @@ -0,0 +1,44 @@ +space: strongly-coupled-model +externalId: SimulationModel +name: SimulationModel +usedFor: node +description: Missing +properties: + modelId: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: false + autoIncrement: false + name: modelId + modelExecutionEnvironment: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: modelExecutionEnvironment + entity: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: entity +constraints: + cogniteDescribablePresent: + require: + space: cdf_cdm + externalId: CogniteDescribable + type: container + constraintType: requires +indexes: + modelId: + properties: + - modelId + cursorable: true + indexType: btree diff --git a/tests/data/strongly_coupled_model/data_models/20.SimEdge.view.yaml b/tests/data/strongly_coupled_model/data_models/20.SimEdge.view.yaml new file mode 100644 index 000000000..54fccef04 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/20.SimEdge.view.yaml @@ -0,0 +1,47 @@ +externalId: SimEdge +space: strongly-coupled-model +version: v1 +name: SimEdge +description: Missing +properties: + source: + source: + type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimEdge + containerPropertyIdentifier: source + name: source + destination: + source: + type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimEdge + containerPropertyIdentifier: destination + name: destination + coordinates: + source: + type: view + space: strongly-coupled-model + externalId: Coordinates + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimEdge + containerPropertyIdentifier: coordinates + name: coordinates +implements: +- type: view + space: strongly-coupled-model + externalId: SimNodeAndEdge + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/21.ProductionTimeseries.view.yaml b/tests/data/strongly_coupled_model/data_models/21.ProductionTimeseries.view.yaml new file mode 100644 index 000000000..2bc6e7a03 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/21.ProductionTimeseries.view.yaml @@ -0,0 +1,23 @@ +externalId: ProductionTimeseries +space: strongly-coupled-model +version: v1 +name: ProductionTimeseries +description: Missing +properties: + entity: + source: + type: view + space: strongly-coupled-model + externalId: Production + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: ProductionTimeseries + containerPropertyIdentifier: entity + name: entity +implements: +- type: view + space: cdf_cdm + externalId: CogniteTimeSeries + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/22.SimNode.view.yaml b/tests/data/strongly_coupled_model/data_models/22.SimNode.view.yaml new file mode 100644 index 000000000..49f3e4c22 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/22.SimNode.view.yaml @@ -0,0 +1,39 @@ +externalId: SimNode +space: strongly-coupled-model +version: v1 +name: SimNode +description: Missing +properties: + coordinate: + source: + type: view + space: strongly-coupled-model + externalId: Coordinate + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimNode + containerPropertyIdentifier: coordinate + name: coordinate + children: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: SimSubNode + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: SimSubNode + version: v1 + identifier: parent + name: children + description: Missing +implements: +- type: view + space: strongly-coupled-model + externalId: SimNodeAndEdge + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/23.Production.view.yaml b/tests/data/strongly_coupled_model/data_models/23.Production.view.yaml new file mode 100644 index 000000000..102dae575 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/23.Production.view.yaml @@ -0,0 +1,58 @@ +externalId: Production +space: strongly-coupled-model +name: Production +version: v1 +description: Missing +properties: + id: + container: + type: container + space: strongly-coupled-model + externalId: Production + containerPropertyIdentifier: id + name: id + description: Missing + simpleType: + container: + type: container + space: strongly-coupled-model + externalId: Production + containerPropertyIdentifier: type + name: simpleType + files: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: SimulationResultFile + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: SimulationResultFile + version: v1 + identifier: entity + name: files + description: Missing + timeSeries: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: ProductionTimeseries + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: ProductionTimeseries + version: v1 + identifier: entity + name: timeSeries + description: Missing +implements: +- type: view + space: cdf_cdm + externalId: CogniteAsset + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/24.SimSubNode.view.yaml b/tests/data/strongly_coupled_model/data_models/24.SimSubNode.view.yaml new file mode 100644 index 000000000..716e51db1 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/24.SimSubNode.view.yaml @@ -0,0 +1,23 @@ +externalId: SimSubNode +space: strongly-coupled-model +version: v1 +name: SimSubNode +description: Missing +properties: + parent: + source: + type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimSubNode + containerPropertyIdentifier: parent + name: parent +implements: +- type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/25.SimulationResultFile.view.yaml b/tests/data/strongly_coupled_model/data_models/25.SimulationResultFile.view.yaml new file mode 100644 index 000000000..b43fd3687 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/25.SimulationResultFile.view.yaml @@ -0,0 +1,23 @@ +externalId: SimulationResultFile +space: strongly-coupled-model +name: SimulationResultFile +version: v1 +description: Missing +properties: + entity: + container: + type: container + space: strongly-coupled-model + externalId: SimulationResultFile + source: + type: view + space: strongly-coupled-model + externalId: Production + version: v1 + containerPropertyIdentifier: entity + name: entity +implements: +- type: view + space: cdf_cdm + externalId: CogniteFile + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/26.InputProperty.view.yaml b/tests/data/strongly_coupled_model/data_models/26.InputProperty.view.yaml new file mode 100644 index 000000000..a7ee4fbdb --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/26.InputProperty.view.yaml @@ -0,0 +1,17 @@ +externalId: InputProperty +space: strongly-coupled-model +version: v1 +name: InputProperty +description: Missing +filter: + equals: + property: + - strongly-coupled-model + - Property + - type + value: Input +implements: +- type: view + space: strongly-coupled-model + externalId: Property + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/28.OutputProperty.view.yaml b/tests/data/strongly_coupled_model/data_models/28.OutputProperty.view.yaml new file mode 100644 index 000000000..1bea7cbc2 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/28.OutputProperty.view.yaml @@ -0,0 +1,17 @@ +externalId: OutputProperty +space: strongly-coupled-model +version: v1 +name: OutputProperty +description: Missing +filter: + equals: + property: + - strongly-coupled-model + - Property + - type + value: Output +implements: +- type: view + space: strongly-coupled-model + externalId: Property + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/29.Property.view.yaml b/tests/data/strongly_coupled_model/data_models/29.Property.view.yaml new file mode 100644 index 000000000..9b6ee7b0a --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/29.Property.view.yaml @@ -0,0 +1,69 @@ +externalId: Property +space: strongly-coupled-model +version: v1 +name: Property +description: Missing +properties: + type: + container: + type: container + space: strongly-coupled-model + externalId: Property + containerPropertyIdentifier: type + nodeOrEdge: + source: + type: view + space: strongly-coupled-model + externalId: SimNodeAndEdge + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: Property + containerPropertyIdentifier: nodeOrEdge + name: nodeOrEdge + modelName: + container: + type: container + space: cdf_cdm + externalId: CogniteDescribable + containerPropertyIdentifier: name + name: modelName + workflow: + container: + type: container + space: strongly-coupled-model + externalId: Property + containerPropertyIdentifier: workflow + name: workflow + unit: + container: + type: container + space: strongly-coupled-model + externalId: Property + containerPropertyIdentifier: unit + name: unit + valueClassicRef: + container: + type: container + space: strongly-coupled-model + externalId: Property + containerPropertyIdentifier: valueClassicRef + name: valueClassicRef + valueRef: + source: + type: view + space: strongly-coupled-model + externalId: ProductionTimeseries + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: Property + containerPropertyIdentifier: valueRef + name: valueRef +implements: +- type: view + space: cdf_cdm + externalId: CogniteDescribable + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/3.strongly-coupled-model.datamodel.yaml b/tests/data/strongly_coupled_model/data_models/3.strongly-coupled-model.datamodel.yaml new file mode 100644 index 000000000..65a6623c9 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/3.strongly-coupled-model.datamodel.yaml @@ -0,0 +1,178 @@ +space: strongly-coupled-model +externalId: StronglyCoupledMappingModel +version: v0.1 +name: Strongly Coupled Mapping Model +description: Missing +views: +- type: view + space: strongly-coupled-model + externalId: SimulationModel + version: v1 +- type: view + space: strongly-coupled-model + externalId: ModelExecutionEnvironment + version: v1 +- type: view + space: strongly-coupled-model + externalId: SimNodeAndEdge + version: v1 +- type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 +- type: view + space: strongly-coupled-model + externalId: SimSubNode + version: v1 +- type: view + space: strongly-coupled-model + externalId: SimEdge + version: v1 +- type: view + space: strongly-coupled-model + externalId: Property + version: v1 +- type: view + space: strongly-coupled-model + externalId: InputProperty + version: v1 +- type: view + space: strongly-coupled-model + externalId: OutputProperty + version: v1 +- type: view + space: strongly-coupled-model + externalId: Coordinate + version: v1 +- type: view + space: strongly-coupled-model + externalId: Coordinates + version: v1 +- type: view + space: strongly-coupled-model + externalId: Production + version: v1 +- type: view + space: strongly-coupled-model + externalId: ProductionTimeseries + version: v1 +- type: view + space: strongly-coupled-model + externalId: SimulationResultFile + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteAsset + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteVisualizable + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteDescribable + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteSourceable + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite3DObject + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteSourceSystem + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteAssetClass + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteEquipment + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteActivity + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteFile + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteFileCategory + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteAssetType + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteTimeSeries + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteSchedulable + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteEquipmentType + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteCADNode + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite360Image + version: v1 +- type: view + space: cdf_cdm + externalId: CognitePointCloudVolume + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteUnit + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteCADModel + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteCADRevision + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite3DTransformation + version: v1 +- type: view + space: cdf_cdm + externalId: CogniteCubeMap + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite360ImageCollection + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite360ImageStation + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite3DModel + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite3DRevision + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite360ImageModel + version: v1 +- type: view + space: cdf_cdm + externalId: Cognite360ImageAnnotation + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/30.SimulationModel.view.yaml b/tests/data/strongly_coupled_model/data_models/30.SimulationModel.view.yaml new file mode 100644 index 000000000..576dc29fe --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/30.SimulationModel.view.yaml @@ -0,0 +1,81 @@ +externalId: SimulationModel +space: strongly-coupled-model +version: v1 +name: SimulationModel +description: Missing +properties: + modelName: + container: + type: container + space: cdf_cdm + externalId: CogniteDescribable + containerPropertyIdentifier: name + name: modelName + modelId: + container: + type: container + space: strongly-coupled-model + externalId: SimulationModel + containerPropertyIdentifier: modelId + name: modelId + modelExecutionEnvironment: + source: + type: view + space: strongly-coupled-model + externalId: ModelExecutionEnvironment + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimulationModel + containerPropertyIdentifier: modelExecutionEnvironment + name: modelExecutionEnvironment + entity: + source: + type: view + space: strongly-coupled-model + externalId: Production + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimulationModel + containerPropertyIdentifier: entity + name: entity + simEdges: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: SimEdge + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: SimEdge + version: v1 + identifier: model + name: simEdges + description: Missing + simNodes: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: SimNode + version: v1 + identifier: model + name: simNodes + description: Missing +implements: +- type: view + space: cdf_cdm + externalId: CogniteDescribable + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/31.SimNodeAndEdge.view.yaml b/tests/data/strongly_coupled_model/data_models/31.SimNodeAndEdge.view.yaml new file mode 100644 index 000000000..3cb8da8a0 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/31.SimNodeAndEdge.view.yaml @@ -0,0 +1,88 @@ +externalId: SimNodeAndEdge +space: strongly-coupled-model +version: v1 +name: SimNodeAndEdge +description: Missing +properties: + modelName: + container: + type: container + space: cdf_cdm + externalId: CogniteDescribable + containerPropertyIdentifier: name + name: modelName + modelId: + name: modelId + container: + type: container + space: strongly-coupled-model + externalId: SimNodeAndEdge + containerPropertyIdentifier: modelId + type: + container: + type: container + space: strongly-coupled-model + externalId: SimNodeAndEdge + containerPropertyIdentifier: type + name: type + entity: + source: + type: view + space: strongly-coupled-model + externalId: Production + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimNodeAndEdge + containerPropertyIdentifier: entity + name: entity + input: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: InputProperty + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: InputProperty + version: v1 + identifier: nodeOrEdge + name: input + description: Missing + output: + connectionType: multi_reverse_direct_relation + source: + type: view + space: strongly-coupled-model + externalId: OutputProperty + version: v1 + through: + source: + type: view + space: strongly-coupled-model + externalId: OutputProperty + version: v1 + identifier: nodeOrEdge + name: output + description: Missing + model: + source: + type: view + space: strongly-coupled-model + externalId: SimulationModel + version: v1 + container: + type: container + space: strongly-coupled-model + externalId: SimNodeAndEdge + containerPropertyIdentifier: model + name: model +implements: +- type: view + space: cdf_cdm + externalId: CogniteDescribable + version: v1 diff --git a/tests/data/strongly_coupled_model/data_models/5.my.space.yaml b/tests/data/strongly_coupled_model/data_models/5.my.space.yaml new file mode 100644 index 000000000..e85b58386 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/5.my.space.yaml @@ -0,0 +1,3 @@ +space: strongly-coupled-model +name: strongly-coupled-model +description: Missing diff --git a/tests/data/strongly_coupled_model/data_models/6.ModelExecutionEnvironment.container.yaml b/tests/data/strongly_coupled_model/data_models/6.ModelExecutionEnvironment.container.yaml new file mode 100644 index 000000000..f78c4ebb7 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/6.ModelExecutionEnvironment.container.yaml @@ -0,0 +1,32 @@ +space: strongly-coupled-model +externalId: ModelExecutionEnvironment +name: ModelExecutionEnvironment +usedFor: node +description: Missing +properties: + type: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: type + version: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: version +constraints: + cogniteDescribablePresent: + require: + space: cdf_cdm + externalId: CogniteDescribable + type: container + constraintType: requires +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/7.ProductionTimeseries.container.yaml b/tests/data/strongly_coupled_model/data_models/7.ProductionTimeseries.container.yaml new file mode 100644 index 000000000..187381d7c --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/7.ProductionTimeseries.container.yaml @@ -0,0 +1,22 @@ +space: strongly-coupled-model +externalId: ProductionTimeseries +name: ProductionTimeseries +description: Missing +properties: + entity: + type: + list: false + type: direct + immutable: false + nullable: true + autoIncrement: false + name: entity +constraints: + cogniteTimeSeriesPresent: + require: + space: cdf_cdm + externalId: CogniteTimeSeries + type: container + constraintType: requires +indexes: {} +usedFor: node diff --git a/tests/data/strongly_coupled_model/data_models/8.SimNodeAndEdge.container.yaml b/tests/data/strongly_coupled_model/data_models/8.SimNodeAndEdge.container.yaml new file mode 100644 index 000000000..9d1b48539 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/8.SimNodeAndEdge.container.yaml @@ -0,0 +1,48 @@ +space: strongly-coupled-model +externalId: SimNodeAndEdge +name: SimNodeAndEdge +description: Missing +usedFor: node +properties: + modelId: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: modelId + type: + type: + type: text + list: false + collation: ucs_basic + immutable: false + nullable: true + autoIncrement: false + name: type + entity: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: entity + model: + type: + type: direct + list: false + immutable: false + nullable: true + autoIncrement: false + name: model +constraints: + cogniteDescribablePresent: + require: + space: cdf_cdm + externalId: CogniteDescribable + type: container + constraintType: requires +indexes: {} diff --git a/tests/data/strongly_coupled_model/data_models/9.SimulationResultFile.container.yaml b/tests/data/strongly_coupled_model/data_models/9.SimulationResultFile.container.yaml new file mode 100644 index 000000000..c35d931a0 --- /dev/null +++ b/tests/data/strongly_coupled_model/data_models/9.SimulationResultFile.container.yaml @@ -0,0 +1,22 @@ +space: strongly-coupled-model +externalId: SimulationResultFile +name: SimulationResultFile +description: Missing +properties: + entity: + type: + list: false + type: direct + immutable: false + nullable: true + autoIncrement: false + name: entity +constraints: + cogniteFilePresent: + require: + space: cdf_cdm + externalId: CogniteFile + type: container + constraintType: requires +indexes: {} +usedFor: node From 970243d4fae8e57a0be54ff596996bc9f569ef95 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sat, 1 Mar 2025 12:09:39 +0100 Subject: [PATCH 2/6] tests: created failing test --- tests/data/__init__.py | 2 + .../test_commands/test_deploy_data_model.py | 39 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/test_integration/test_commands/test_deploy_data_model.py diff --git a/tests/data/__init__.py b/tests/data/__init__.py index 8edaa8f4e..8720c4f09 100644 --- a/tests/data/__init__.py +++ b/tests/data/__init__.py @@ -17,6 +17,7 @@ COMPLETE_ORG = DATA_FOLDER / "complete_org" COMPLETE_ORG_ALPHA_FLAGS = DATA_FOLDER / "complete_org_alpha_flags" CDF_TOML_DATA = DATA_FOLDER / "cdf_toml_data" +STRONGLY_COUPLED_MODEL = DATA_FOLDER / "strongly_coupled_model" __all__ = [ "AUTH_DATA", @@ -32,5 +33,6 @@ "PROJECT_WITH_DUPLICATES", "RESOURCES_WITH_ENVIRONMENT_VARIABLES", "RUN_DATA", + "STRONGLY_COUPLED_MODEL", "TRANSFORMATION_CLI", ] diff --git a/tests/test_integration/test_commands/test_deploy_data_model.py b/tests/test_integration/test_commands/test_deploy_data_model.py new file mode 100644 index 000000000..bee07d64e --- /dev/null +++ b/tests/test_integration/test_commands/test_deploy_data_model.py @@ -0,0 +1,39 @@ +import pytest +from cognite.client import data_modeling as dm + +from cognite_toolkit._cdf_tk.client import ToolkitClient +from cognite_toolkit._cdf_tk.loaders import ContainerLoader, SpaceLoader, ViewLoader +from tests.data import STRONGLY_COUPLED_MODEL + + +@pytest.fixture() +def deployed_container_space_coupled_model(toolkit_client: ToolkitClient) -> None: + space_loader = SpaceLoader(toolkit_client, STRONGLY_COUPLED_MODEL, None) + files = space_loader.find_files() + assert len(files) == 1 + space = dm.SpaceApply.load(files[0].read_text(encoding="utf-8")) + if not space_loader.retrieve([space.as_id()]): + created_space = space_loader.create([space]) + assert len(created_space) == 1 + + container_loader = ContainerLoader(toolkit_client, STRONGLY_COUPLED_MODEL, None) + containers = dm.ContainerApplyList( + [dm.ContainerApply.load(file.read_text(encoding="utf-8")) for file in container_loader.find_files()] + ) + + if len(container_loader.retrieve(containers.as_ids())) != len(containers): + created_containers = container_loader.create(containers) + assert len(created_containers) == len(containers) + + +@pytest.mark.usefixtures("deployed_container_space_coupled_model") +def test_deploy_strongly_coupled_model(toolkit_client: ToolkitClient) -> None: + loader = ViewLoader(toolkit_client, STRONGLY_COUPLED_MODEL, None) + views = dm.ViewApplyList([dm.ViewApply.load(file.read_text(encoding="utf-8")) for file in loader.find_files()]) + + try: + created = loader.create(views) + + assert len(views) == len(created) + finally: + toolkit_client.data_modeling.views.delete(views.as_ids()) From 4a408aa3738f1681e4b26668b2fac93b8f3a34ad Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sat, 1 Mar 2025 12:45:38 +0100 Subject: [PATCH 3/6] feat: First draft tarjan --- cognite_toolkit/_cdf_tk/utils/tarjan.py | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 cognite_toolkit/_cdf_tk/utils/tarjan.py diff --git a/cognite_toolkit/_cdf_tk/utils/tarjan.py b/cognite_toolkit/_cdf_tk/utils/tarjan.py new file mode 100644 index 000000000..8bb3361d9 --- /dev/null +++ b/cognite_toolkit/_cdf_tk/utils/tarjan.py @@ -0,0 +1,45 @@ +from cognite.client.data_classes.data_modeling import ViewId + + +def tarjan(dependencies_by_id: dict[ViewId, set[ViewId]]) -> list[set[ViewId]]: + """Returns the strongly connected components of the dependency graph + in topological order. + + Args: + dependencies_by_id: A dictionary where the keys are the view ids and the values are the set of view ids + that the key view depends on. + + Returns: + A list of sets of view ids, where each set is a strongly connected component. + """ + + S = [] + S_set = set() + index: dict[ViewId, int] = {} + lowlink = {} + ret = [] + + def visit(v: ViewId) -> None: + index[v] = len(index) + lowlink[v] = index[v] + S.append(v) + S_set.add(v) + for w in dependencies_by_id.get(v, []): + if w not in index: + visit(w) + lowlink[v] = min(lowlink[w], lowlink[v]) + elif w in S_set: + lowlink[v] = min(lowlink[v], index[w]) + if lowlink[v] == index[v]: + scc = set() + dependency: ViewId | None = None + while v != dependency: + dependency = S.pop() + scc.add(dependency) + S_set.remove(dependency) + ret.append(scc) + + for view_id in dependencies_by_id.keys(): + if view_id not in index: + visit(view_id) + return ret From 52725fa57daf965287944888a581e5642183b1c0 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sat, 1 Mar 2025 13:03:40 +0100 Subject: [PATCH 4/6] fix: implemented recovery --- .../_resource_loaders/datamodel_loaders.py | 92 +++++++++++++------ 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py b/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py index 5bcf3821d..0be58094d 100644 --- a/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py +++ b/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py @@ -103,6 +103,7 @@ ) from cognite_toolkit._cdf_tk.utils.cdf import iterate_instances from cognite_toolkit._cdf_tk.utils.diff_list import diff_list_identifiable, dm_identifier +from cognite_toolkit._cdf_tk.utils.tarjan import tarjan from .auth_loaders import GroupAllScopedLoader @@ -601,38 +602,77 @@ def create(self, items: Sequence[ViewApply]) -> ViewList: if self._is_auto_retryable(e1): # Fallback to creating one by one if the error is auto-retryable. return self._fallback_create_one_by_one(items, e1) - elif self._is_deployment_order(e1, set(self.get_ids(items))): - return self._fallback_create_one_by_one(self._topological_sort(items), e1, warn=False) + elif self._is_false_not_exists(e1, {item.as_id() for item in items}): + return self._try_to_recover_coupled(items, e1) raise @staticmethod - def _is_deployment_order(e: CogniteAPIError, ids: set[ViewId]) -> bool: - if match := re.match( - r"One or more views do not exist: '([a-zA-Z0-9_-]+):([a-zA-Z0-9_]+)/([.a-zA-Z0-9_-]+)'", e.message - ): - return ViewId(*match.groups()) in ids - return False - - def _topological_sort(self, items: Sequence[ViewApply]) -> Sequence[ViewApply]: + def _is_false_not_exists(e: CogniteAPIError, request_views: set[ViewId]) -> bool: + if "not exist" not in e.message and 400 <= e.code < 500: + return False + results = re.findall(r"'([a-zA-Z0-9_-]+):([a-zA-Z0-9_]+)/([.a-zA-Z0-9_-]+)'", e.message) + if not results: + # No view references in the message + return False + error_message_views = {ViewId(*result) for result in results} + return error_message_views.issubset(request_views) + + def _try_to_recover_coupled(self, items: Sequence[ViewApply], original_error: CogniteAPIError) -> ViewList: + """The /models/views endpoint can give faulty 400 about missing views that are part of the request. + + This method tries to recover from such errors by identifying the strongly connected components in the graph + defined by the implements and through properties of the views. We then create the components in topological + order. + + Args: + items: The items that failed to create. + original_error: The original error that was raised. If the problem is not recoverable, this error is raised. + + Returns: + The views that were created. + + """ views_by_id = {self.get_id(item): item for item in items} - dependencies_by_id: dict[ViewId, set[ViewId]] = {} - for item in items: - view_id = self.get_id(item) - dependencies_by_id[view_id] = set() - for prop in (item.properties or {}).values(): - if isinstance(prop, ReverseDirectRelationApply): - if ( - isinstance(prop.through.source, ViewId) - and prop.through.source in views_by_id - and prop.through.source != view_id - ): - dependencies_by_id[view_id].add(prop.through.source) + parents_by_child: dict[ViewId, set[ViewId]] = { + view_id: {parent for parent in view.implements or [] if parent in views_by_id} + for view_id, view in views_by_id.items() + } + # Check for cycles in the implements graph try: - return [views_by_id[view_id] for view_id in TopologicalSorter(dependencies_by_id).static_order()] + TopologicalSorter(parents_by_child).static_order() except CycleError as e: - raise ToolkitCycleError( - f"Cycle detected in views: {e.args[0]}. Please fix the cycle before deploying." - ) from e + raise ToolkitCycleError(f"Failed to deploy views. This likely due to a cycle in implements. {e.args[1]}") + + dependencies_by_id: dict[ViewId, set[ViewId]] = defaultdict(set) + for view_id, view in views_by_id.items(): + dependencies_by_id[view_id].update([parent for parent in view.implements or [] if parent in views_by_id]) + for properties in (view.properties or {}).values(): + if isinstance(properties, ReverseDirectRelationApply): + if isinstance(properties.through.source, ViewId) and properties.through.source in views_by_id: + dependencies_by_id[view_id].add(properties.through.source) + + LowSeverityWarning( + f"Failed to create {len(items)} views: {escape(original_error.message)}.\nAttempting to revover..." + ).print_warning(include_timestamp=True, console=self.console) + created = ViewList([]) + for strongly_connected in tarjan(dependencies_by_id): + to_create = [views_by_id[view_id] for view_id in strongly_connected] + try: + created_set = self.client.data_modeling.views.apply(to_create) + except CogniteAPIError as error: + self.client.data_modeling.views.delete(created.as_ids()) + HighSeverityWarning( + f"Recovering attempt failed. Could not create views {self.get_ids(to_create)}: " + f"{escape(error.message)}.\n Raising original error." + ).print_warning(console=self.console) + raise original_error + created.extend(created_set) + message = f"Revory attempt succeeded. Created {len(created)} views." + if self.console: + self.console.print(message) + else: + print(message) + return created @staticmethod def _is_auto_retryable(e: CogniteAPIError) -> bool: From 7a6d1dfcbea8aad3942e681c6579fe79d933fd52 Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sat, 1 Mar 2025 13:45:10 +0100 Subject: [PATCH 5/6] tests: added testing for tarjan --- cognite_toolkit/_cdf_tk/utils/tarjan.py | 37 ++++++++--------- .../test_cdf_tk/test_utils/test_tarjan.py | 40 +++++++++++++++++++ 2 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 tests/test_unit/test_cdf_tk/test_utils/test_tarjan.py diff --git a/cognite_toolkit/_cdf_tk/utils/tarjan.py b/cognite_toolkit/_cdf_tk/utils/tarjan.py index 8bb3361d9..e3c8c93de 100644 --- a/cognite_toolkit/_cdf_tk/utils/tarjan.py +++ b/cognite_toolkit/_cdf_tk/utils/tarjan.py @@ -1,45 +1,46 @@ -from cognite.client.data_classes.data_modeling import ViewId +from typing import TypeVar +T = TypeVar("T") -def tarjan(dependencies_by_id: dict[ViewId, set[ViewId]]) -> list[set[ViewId]]: + +def tarjan(dependencies_by_id: dict[T, set[T]]) -> list[set[T]]: """Returns the strongly connected components of the dependency graph in topological order. Args: - dependencies_by_id: A dictionary where the keys are the view ids and the values are the set of view ids - that the key view depends on. + dependencies_by_id: A dictionary where the keys are ids and the values are sets of ids that the key depends on. Returns: - A list of sets of view ids, where each set is a strongly connected component. + A list of sets of ids that are strongly connected components in the dependency graph. """ - S = [] - S_set = set() - index: dict[ViewId, int] = {} + stack = [] + stack_set = set() + index: dict[T, int] = {} lowlink = {} - ret = [] + result = [] - def visit(v: ViewId) -> None: + def visit(v: T) -> None: index[v] = len(index) lowlink[v] = index[v] - S.append(v) - S_set.add(v) + stack.append(v) + stack_set.add(v) for w in dependencies_by_id.get(v, []): if w not in index: visit(w) lowlink[v] = min(lowlink[w], lowlink[v]) - elif w in S_set: + elif w in stack_set: lowlink[v] = min(lowlink[v], index[w]) if lowlink[v] == index[v]: scc = set() - dependency: ViewId | None = None + dependency: T | None = None while v != dependency: - dependency = S.pop() + dependency = stack.pop() scc.add(dependency) - S_set.remove(dependency) - ret.append(scc) + stack_set.remove(dependency) + result.append(scc) for view_id in dependencies_by_id.keys(): if view_id not in index: visit(view_id) - return ret + return result diff --git a/tests/test_unit/test_cdf_tk/test_utils/test_tarjan.py b/tests/test_unit/test_cdf_tk/test_utils/test_tarjan.py new file mode 100644 index 000000000..deedabe14 --- /dev/null +++ b/tests/test_unit/test_cdf_tk/test_utils/test_tarjan.py @@ -0,0 +1,40 @@ +from collections.abc import Iterable + +import pytest + +from cognite_toolkit._cdf_tk.utils.tarjan import tarjan + + +def tarjan_test_cases() -> Iterable: + yield pytest.param( + {}, + [], + id="Empty graph", + ) + yield pytest.param( + {"A": set()}, + [{"A"}], + id="Single node", + ) + yield pytest.param( + {"A": {"B"}, "B": set()}, + [{"B"}, {"A"}], + id="Two nodes", + ) + yield pytest.param( + {"A": {"B"}, "B": {"A"}}, + [{"A", "B"}], + id="Circular dependency", + ) + yield pytest.param( + {"A": {"B"}, "B": {"C"}, "C": {"A"}}, + [{"C", "B", "A"}], + id="Circular dependency with three nodes", + ) + + +class TestTarjan: + @pytest.mark.parametrize("graph, expected", tarjan_test_cases()) + def test_tarjan(self, graph: dict[str, set[str]], expected: list[set[str]]): + result = tarjan(graph) + assert result == expected From f11838aa2a9fabe95f235e38ceb24c604c94169c Mon Sep 17 00:00:00 2001 From: anders-albert Date: Sat, 1 Mar 2025 13:48:08 +0100 Subject: [PATCH 6/6] style: fix typos --- .../_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py b/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py index 0be58094d..af3ed682a 100644 --- a/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py +++ b/cognite_toolkit/_cdf_tk/loaders/_resource_loaders/datamodel_loaders.py @@ -652,7 +652,7 @@ def _try_to_recover_coupled(self, items: Sequence[ViewApply], original_error: Co dependencies_by_id[view_id].add(properties.through.source) LowSeverityWarning( - f"Failed to create {len(items)} views: {escape(original_error.message)}.\nAttempting to revover..." + f"Failed to create {len(items)} views: {escape(original_error.message)}.\nAttempting to recover..." ).print_warning(include_timestamp=True, console=self.console) created = ViewList([]) for strongly_connected in tarjan(dependencies_by_id): @@ -667,7 +667,7 @@ def _try_to_recover_coupled(self, items: Sequence[ViewApply], original_error: Co ).print_warning(console=self.console) raise original_error created.extend(created_set) - message = f"Revory attempt succeeded. Created {len(created)} views." + message = f"Recovery attempt succeeded. Created {len(created)} views." if self.console: self.console.print(message) else: