From 9d0f48462b17d1f6609700d7775f8e5cf4ff821f Mon Sep 17 00:00:00 2001 From: Gabe Fierro Date: Wed, 24 May 2023 09:49:14 +1000 Subject: [PATCH 1/2] Fix nondeterministic test failure by correctly calculating the root node of validation graphs --- buildingmotif/dataclasses/validation.py | 13 +++++++++++-- tests/unit/dataclasses/test_model.py | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/buildingmotif/dataclasses/validation.py b/buildingmotif/dataclasses/validation.py index f51514839..5f9547f6e 100644 --- a/buildingmotif/dataclasses/validation.py +++ b/buildingmotif/dataclasses/validation.py @@ -51,8 +51,17 @@ def reason(self) -> str: @cached_property def _result_uri(self) -> Node: """Return the 'name' of the ValidationReport to make failed_shape/failed_component - easier to express""" - return next(self.validation_result.subjects()) + easier to express. We compute this by taking advantage of the fact that the validation + result graph is actually a tree with a single root. We can find the root by finding + all URIs which appear as subjects in the validation_result graph that do *not* appear + as objects; this should be exactly one URI which is the 'root' of the validation result + graph + """ + possible_uris: Set[Node] = set(self.validation_result.subjects()) + objects: Set[Node] = set(self.validation_result.objects()) + sub_not_obj = possible_uris - objects + assert len(sub_not_obj) == 1 + return sub_not_obj.pop() @cached_property def failed_shape(self) -> Optional[URIRef]: diff --git a/tests/unit/dataclasses/test_model.py b/tests/unit/dataclasses/test_model.py index 721b97920..ac1509aa4 100644 --- a/tests/unit/dataclasses/test_model.py +++ b/tests/unit/dataclasses/test_model.py @@ -105,7 +105,10 @@ def test_validate_model_with_failure(bm: BuildingMOTIF): assert not ctx.valid assert len(ctx.diffset) == 1 diff = ctx.diffset.pop() - assert isinstance(diff.failed_shape, BNode) + assert isinstance(diff.failed_shape, BNode), ( + diff.failed_shape, + type(diff.failed_shape), + ) assert diff.failed_component == SH.MinCountConstraintComponent model.add_triples((bindings["name"], RDFS.label, Literal("hvac zone 1"))) From fc9e6fecbda6524dc8ddbd8aeb0ffa8b8c1535f6 Mon Sep 17 00:00:00 2001 From: Gabe Fierro Date: Thu, 25 May 2023 08:24:31 +1000 Subject: [PATCH 2/2] assert -> exception --- buildingmotif/dataclasses/validation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/buildingmotif/dataclasses/validation.py b/buildingmotif/dataclasses/validation.py index 5f9547f6e..e34aa8e21 100644 --- a/buildingmotif/dataclasses/validation.py +++ b/buildingmotif/dataclasses/validation.py @@ -60,7 +60,10 @@ def _result_uri(self) -> Node: possible_uris: Set[Node] = set(self.validation_result.subjects()) objects: Set[Node] = set(self.validation_result.objects()) sub_not_obj = possible_uris - objects - assert len(sub_not_obj) == 1 + if len(sub_not_obj) != 1: + raise Exception( + "Validation result has more than one 'root' node, which should not happen. Please raise an issue on https://github.com/NREL/BuildingMOTIF" + ) return sub_not_obj.pop() @cached_property