Skip to content

Commit

Permalink
move count formatting function to graphdiff and fix test
Browse files Browse the repository at this point in the history
  • Loading branch information
gtfierro committed Nov 19, 2024
1 parent 3be123c commit ad14e4c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 34 deletions.
63 changes: 31 additions & 32 deletions buildingmotif/dataclasses/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,6 @@
from buildingmotif.dataclasses import Library, Model, Template


def format_count_error(
max_count, min_count, path, object_type: Optional[str] = None
) -> str:
"""Format a count error message for a given object type and path.
:param max_count: the maximum number of objects expected
:type max_count: int
:param min_count: the minimum number of objects expected
:type min_count: int
:param object_type: the type of object expected
:type object_type: str
:param path: the path to the object
:type path: str
:return: the formatted error message
:rtype: str
"""
instances = f"instance(s) of {object_type} on" if object_type else "uses of"
if min_count == max_count:
return f"Expected {min_count} {instances} path {path}"
elif min_count is not None and max_count is not None:
return f"Expected between {min_count} and {max_count} {instances} path {path}"
elif min_count is not None:
return f"Expected at least {min_count} {instances} path {path}"
elif max_count is not None:
return f"Expected at most {max_count} {instances} path {path}"
else:
return f"Expected {instances} path {path}"


@dataclass(frozen=True)
class GraphDiff:
"""An abstraction of a SHACL Validation Result that can produce a template
Expand Down Expand Up @@ -114,6 +85,34 @@ def failed_component(self) -> Optional[URIRef]:
def __hash__(self):
return hash(self.reason())

def format_count_error(
self, max_count, min_count, path, object_type: Optional[str] = None
) -> str:
"""Format a count error message for a given object type and path.
:param max_count: the maximum number of objects expected
:type max_count: int
:param min_count: the minimum number of objects expected
:type min_count: int
:param object_type: the type of object expected
:type object_type: str
:param path: the path to the object
:type path: str
:return: the formatted error message
:rtype: str
"""
instances = f"instance(s) of {object_type} on" if object_type else "uses of"
if min_count == max_count:
return f"{self.focus} expected {min_count} {instances} path {path}"
elif min_count is not None and max_count is not None:
return f"{self.focus} expected between {min_count} and {max_count} {instances} path {path}"
elif min_count is not None:
return f"{self.focus} expected at least {min_count} {instances} path {path}"
elif max_count is not None:
return f"{self.focus} expected at most {max_count} {instances} path {path}"
else:
return f"{self.focus} expected {instances} path {path}"


@dataclass(frozen=True)
class OrShape(GraphDiff):
Expand Down Expand Up @@ -221,7 +220,7 @@ def reason(self) -> str:
)

classname = self.graph.qname(self.classname)
return format_count_error(self.maxc, self.minc, path, classname)
return self.format_count_error(self.maxc, self.minc, path, classname)

def resolve(self, lib: "Library") -> List["Template"]:
"""Produces a list of templates to resolve this GraphDiff.
Expand Down Expand Up @@ -309,7 +308,7 @@ def from_validation_report(
def reason(self) -> str:
"""Human-readable explanation of this GraphDiff."""
shapename = self.graph.qname(self.shapename)
return format_count_error(self.maxc, self.minc, self.path, shapename)
return self.format_count_error(self.maxc, self.minc, self.path, shapename)

def resolve(self, lib: "Library") -> List["Template"]:
"""Produces a list of templates to resolve this GraphDiff."""
Expand Down Expand Up @@ -397,7 +396,7 @@ def reason(self) -> str:
path = shacl_path_to_sparql_path(
self.graph, self.path, prefixes=dict(self.graph.namespaces())
)
return format_count_error(self.maxc, self.minc, path)
return self.format_count_error(self.maxc, self.minc, path)

def resolve(self, lib: "Library") -> List["Template"]:
"""Produces a list of templates to resolve this GraphDiff.
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/api/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ def test_validate_model(client, building_motif, shacl_engine):
response = results.get_json()
assert "urn:building/vav1" in response["reasons"], "vav1 should be in the response"
assert set(response["reasons"]["urn:building/vav1"]) == {
"urn:building/vav1 needs at least 1 instances of brick:Air_Flow_Sensor on path brick:hasPoint",
"urn:building/vav1 needs at least 1 instances of brick:Temperature_Sensor on path brick:hasPoint",
"urn:building/vav1 expected at least 1 instance(s) of brick:Temperature_Sensor on path brick:hasPoint",
"urn:building/vav1 expected at least 1 instance(s) of brick:Air_Flow_Sensor on path brick:hasPoint",
}
assert not results.get_json()["valid"]

Expand Down

0 comments on commit ad14e4c

Please sign in to comment.