From 51d2e1ef2a02dad823d142f2143c6832657ba7a5 Mon Sep 17 00:00:00 2001 From: sbilge Date: Tue, 27 Aug 2024 12:22:00 +0000 Subject: [PATCH] passive path support is added --- .../count_references/assumptions.py | 68 +++++++++++++------ .../count_references/data_transform.py | 10 +-- .../count_references/multiple/config.yaml | 30 ++++---- 3 files changed, 65 insertions(+), 43 deletions(-) diff --git a/src/metldata/builtin_transformations/count_references/assumptions.py b/src/metldata/builtin_transformations/count_references/assumptions.py index ed06c57..d8171ec 100644 --- a/src/metldata/builtin_transformations/count_references/assumptions.py +++ b/src/metldata/builtin_transformations/count_references/assumptions.py @@ -30,15 +30,50 @@ from metldata.transform.base import ModelAssumptionError, MultiplicityError -def assert_class_is_source(instruction: AddReferenceCountPropertyInstruction): - """Make sure that the source class is the one being modified with the count property""" - if instruction.class_name != instruction.source_relation_path.source: +def validate_modification_class(path_element, expected_class_name): + """Check whether the class specified to be modified with the reference count + matches the source or target class in the provided `path_element`, depending on the + type of the relation path (i.e., active or passive). If the class does not match, + an exception is raised. + """ + modification_class_name = ( + path_element.source + if path_element.type_ == RelationPathElementType.ACTIVE + else path_element.target + ) + if expected_class_name != modification_class_name: + raise ModelAssumptionError( + f"Class { + expected_class_name} does not correspond to the relation source " + f"{modification_class_name}." + ) + + +def check_class_exists(model: SchemaPack, class_name: str) -> None: + """Check if a class exists in the model and raise an error if not""" + if class_name not in model.classes: + raise ModelAssumptionError(f"Class {class_name} not found in model.") + + +def check_relation_exists(model: SchemaPack, class_name: str, relation: str): + """Check if a relation exists in a class and raise an error if not""" + if relation not in model.classes[class_name].relations: raise ModelAssumptionError( - f"Class {instruction.class_name} does not correspond to the relation source { - instruction.source_relation_path.source}." + f"Relation property { + relation} not found in class {class_name}." ) +def assert_class_is_source(instruction: AddReferenceCountPropertyInstruction): + """Ensure that the class being modified with the reference count property is the expected class. + This function iterates over the elements of the relation path in the given instruction + and validates that the class being modified with the reference count property matches + the class specified in the relation path. + """ + for path_element in instruction.source_relation_path.elements: + validate_modification_class(path_element, instruction.class_name) + + def assert_path_classes_and_relations_exist(model: SchemaPack, path: RelationPath): """Make sure that all classes and relations defined in the provided path exist in the provided model. @@ -48,27 +83,18 @@ def assert_path_classes_and_relations_exist(model: SchemaPack, path: RelationPat if the model does not fulfill the assumptions. """ for path_element in path.elements: - if path_element.source not in model.classes: - raise ModelAssumptionError( - f"Class {path_element.source} not found in model." - ) + check_class_exists(model, path_element.source) + check_class_exists(model, path_element.target) - if path_element.target not in model.classes: - raise ModelAssumptionError( - f"Class {path_element.target} not found in model." - ) + if path_element.type_ == RelationPathElementType.ACTIVE: + check_relation_exists(model, path_element.source, path_element.property) - if path_element.type_ == RelationPathElementType.ACTIVE and ( - path_element.property not in model.classes[path_element.source].relations - ): - raise ModelAssumptionError( - f"Relation property {path_element.property} not found in class" - f" {path_element.source}." - ) + if path_element.type_ == RelationPathElementType.PASSIVE: + check_relation_exists(model, path_element.target, path_element.property) def assert_multiplicity(model: SchemaPack, path: RelationPath): - """Make sure the target of the relation conributes multiple instances to the relation.""" + """Make sure the target of the relation contributes multiple instances to the relation.""" for path_element in path.elements: if path_element.type_ == RelationPathElementType.ACTIVE: relation = model.classes[path_element.source].relations[ diff --git a/src/metldata/builtin_transformations/count_references/data_transform.py b/src/metldata/builtin_transformations/count_references/data_transform.py index 61091e6..e0c67e5 100644 --- a/src/metldata/builtin_transformations/count_references/data_transform.py +++ b/src/metldata/builtin_transformations/count_references/data_transform.py @@ -17,9 +17,6 @@ from schemapack.spec.datapack import DataPack -from metldata.builtin_transformations.common.path.path_elements import ( - RelationPathElementType, -) from metldata.builtin_transformations.count_references.instruction import ( AddReferenceCountPropertyInstruction, ) @@ -52,13 +49,12 @@ def count_references( for instruction in instructions: for path_element in instruction.source_relation_path.elements: - if path_element.type_ == RelationPathElementType.ACTIVE: - relation_slot = path_element.property - else: - raise EvitableTransformationError() + relation_slot = path_element.property for resource in resources.values(): related_to = resource.relations.get(relation_slot) + if not related_to: + raise EvitableTransformationError() count = len(related_to) if related_to else 0 diff --git a/tests/fixtures/example_transformations/count_references/multiple/config.yaml b/tests/fixtures/example_transformations/count_references/multiple/config.yaml index bfdf28f..628aab9 100644 --- a/tests/fixtures/example_transformations/count_references/multiple/config.yaml +++ b/tests/fixtures/example_transformations/count_references/multiple/config.yaml @@ -14,18 +14,18 @@ # limitations under the License. count_references: -- class_name: Dataset - target_content: - object_path: "file_summary" - property_name: "count" - source_relation_path: "Dataset(files)>File" -- class_name: Sample - target_content: - object_path: "file_summary" - property_name: "count" - source_relation_path: "Sample(files)>File" -- class_name: Experiment - target_content: - object_path: "sample_summary" - property_name: "count" - source_relation_path: "Experiment(samples)>Sample" + - class_name: Dataset + target_content: + object_path: "file_summary" + property_name: "count" + source_relation_path: "Dataset(files)>File" + - class_name: Sample + target_content: + object_path: "file_summary" + property_name: "count" + source_relation_path: "File<(files)Sample" + - class_name: Experiment + target_content: + object_path: "sample_summary" + property_name: "count" + source_relation_path: "Experiment(samples)>Sample"