From 59fa3a405433d015ad8d929e54df51d08894d4f2 Mon Sep 17 00:00:00 2001 From: Gabe Fierro Date: Wed, 10 Apr 2024 13:34:06 -0600 Subject: [PATCH] Add ability to use TopQuadrant SHACL implementation as engine (#308) * add shacl_validate/infer functions and use these as the entrypoint. Augment tests to check both shacl engines * fix interactions with shacl inference * tightening up the implementation and use of the shacl_* methods * support specifying shacl engine in the API * update tests; test both pyshacl and topquadrant * add brick-tq-shacl dep * add TODOs * Formatting * no more 3.8! * ignoring some imported packages without type annotations * more type annotations * add types, ignore type errors for imports * update mypy, fix some issues and ignore some others * fix union type annotation * update docker containers * 3.8.1 python for higher * add back python 3.8 * change 3.8 version * add test for finding reasons with a given severity * update brick-tq-shacl, fix type signature * remove debug serializations * bump shacl version * fixing skolemization for validation * move shacl engine config inside buildingmotif object --- .github/workflows/ci.yml | 2 +- .pre-commit-config.yaml | 4 +- buildingmotif/api/Dockerfile | 2 +- buildingmotif/api/views/model.py | 4 +- .../building_motif/building_motif.py | 13 +- buildingmotif/dataclasses/library.py | 13 +- buildingmotif/dataclasses/model.py | 84 +- buildingmotif/dataclasses/template.py | 1 + buildingmotif/dataclasses/validation.py | 48 +- buildingmotif/template_matcher.py | 4 +- buildingmotif/utils.py | 155 +- poetry.lock | 361 +- pyproject.toml | 13 +- .../fixtures/buildingmotif/Dockerfile | 4 +- tests/unit/api/test_model.py | 26 +- tests/unit/conftest.py | 4 + tests/unit/dataclasses/test_model.py | 122 +- tests/unit/fixtures/shapes/shape2.ttl | 2 + .../fixtures/smallOffice_brick_compiled.ttl | 3096 +++-------------- tests/unit/test_utils.py | 117 +- 20 files changed, 1199 insertions(+), 2876 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 123aa8054..b71529c98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: - name: lint run: poetry run flake8 buildingmotif - name: type check - run: poetry run mypy + run: poetry run mypy --ignore-missing-imports - name: unit tests run: poetry run pytest tests/unit --cov=./ --cov-report=xml - name: integration tests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a62d4522a..8483923dc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,9 +16,9 @@ repos: entry: poetry run flake8 buildingmotif # can't poetry run becuase not present in repository https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.931 + rev: v1.9.0 hooks: - id: mypy - args: ["--install-types", "--non-interactive", "--ignore-missing-imports", "--follow-imports=skip"] + args: ["--install-types", "--non-interactive", "--ignore-missing-imports", "--follow-imports=skip", "--disable-error-code=import-untyped"] additional_dependencies: [sqlalchemy2-stubs <= 0.0.2a20, SQLAlchemy <= 1.4] exclude: docs/conf.py diff --git a/buildingmotif/api/Dockerfile b/buildingmotif/api/Dockerfile index c31edc202..7d163de7d 100644 --- a/buildingmotif/api/Dockerfile +++ b/buildingmotif/api/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8 +FROM python:3.9 # Copy project ADD buildingmotif /opt/buildingmotif diff --git a/buildingmotif/api/views/model.py b/buildingmotif/api/views/model.py index 97d1772fc..41fc930dd 100644 --- a/buildingmotif/api/views/model.py +++ b/buildingmotif/api/views/model.py @@ -165,7 +165,7 @@ def validate_model(models_id: int) -> flask.Response: shape_collections = [] - # no body provided -- default to model manifest + # no body provided -- default to model manifest and default SHACL engine if request.content_length is None: shape_collections = [model.get_manifest()] else: @@ -204,7 +204,7 @@ def validate_model(models_id: int) -> flask.Response: "message": vaildation_context.report_string, "valid": vaildation_context.valid, "reasons": { - focus_node: [gd.reason() for gd in grahdiffs] + focus_node: list(set(gd.reason() for gd in grahdiffs)) for focus_node, grahdiffs in vaildation_context.diffset.items() }, }, status.HTTP_200_OK diff --git a/buildingmotif/building_motif/building_motif.py b/buildingmotif/building_motif/building_motif.py index d8805d93f..a01691a0d 100644 --- a/buildingmotif/building_motif/building_motif.py +++ b/buildingmotif/building_motif/building_motif.py @@ -1,6 +1,7 @@ import logging import os from contextlib import contextmanager +from typing import Optional from rdflib import Graph from rdflib.namespace import NamespaceManager @@ -24,16 +25,26 @@ class BuildingMOTIF(metaclass=Singleton): """Manages BuildingMOTIF data classes.""" - def __init__(self, db_uri: str, log_level=logging.WARNING) -> None: + def __init__( + self, + db_uri: str, + shacl_engine: Optional[str] = "pyshacl", + log_level=logging.WARNING, + ) -> None: """Class constructor. :param db_uri: database URI :type db_uri: str + :param shacl_engine: the name of the engine to use for validation: "pyshacl" or "topquadrant". Using topquadrant + requires Java to be installed on this machine, and the "topquadrant" feature on BuildingMOTIF, + defaults to "pyshacl" + :type shacl_engine: str, optional :param log_level: logging level of detail :type log_level: int :default log_level: INFO """ self.db_uri = db_uri + self.shacl_engine = shacl_engine self.engine = create_engine( db_uri, echo=False, diff --git a/buildingmotif/dataclasses/library.py b/buildingmotif/dataclasses/library.py index daeebe512..05858c972 100644 --- a/buildingmotif/dataclasses/library.py +++ b/buildingmotif/dataclasses/library.py @@ -5,7 +5,6 @@ from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Union import pygit2 -import pyshacl import rdflib import sqlalchemy import yaml @@ -23,6 +22,7 @@ from buildingmotif.utils import ( get_ontology_files, get_template_parts_from_shape, + shacl_inference, skip_uri, ) @@ -248,15 +248,7 @@ def _load_from_ontology( # expand the ontology graph before we insert it into the database. This will ensure # that the output of compiled models will not contain triples that really belong to # the ontology - pyshacl.validate( - data_graph=ontology, - shacl_graph=ontology, - ont_graph=ontology, - advanced=True, - inplace=True, - js=True, - allow_warnings=True, - ) + ontology = shacl_inference(ontology, engine=get_building_motif().shacl_engine) lib = cls.create(ontology_name, overwrite=overwrite) @@ -284,6 +276,7 @@ def _infer_shapes_from_graph(self, graph: rdflib.Graph): dependency_cache: Dict[int, List[Dict[Any, Any]]] = {} for candidate in candidates: assert isinstance(candidate, rdflib.URIRef) + # TODO: mincount 0 (or unspecified) should be optional args on the generated template partial_body, deps = get_template_parts_from_shape(candidate, graph) templ = self.create_template(str(candidate), partial_body) dependency_cache[templ.id] = deps diff --git a/buildingmotif/dataclasses/model.py b/buildingmotif/dataclasses/model.py index 80bc1d088..4d9dc6549 100644 --- a/buildingmotif/dataclasses/model.py +++ b/buildingmotif/dataclasses/model.py @@ -1,7 +1,6 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Dict, List, Optional -import pyshacl import rdflib import rfc3987 from rdflib import URIRef @@ -9,8 +8,15 @@ from buildingmotif import get_building_motif from buildingmotif.dataclasses.shape_collection import ShapeCollection from buildingmotif.dataclasses.validation import ValidationContext -from buildingmotif.namespaces import A -from buildingmotif.utils import Triple, copy_graph, rewrite_shape_graph +from buildingmotif.namespaces import OWL, A +from buildingmotif.utils import ( + Triple, + copy_graph, + rewrite_shape_graph, + shacl_inference, + shacl_validate, + skolemize_shapes, +) if TYPE_CHECKING: from buildingmotif import BuildingMOTIF @@ -174,20 +180,24 @@ def validate( ).graph # inline sh:node for interpretability shapeg = rewrite_shape_graph(shapeg) + + # remove imports from sg + shapeg.remove((None, OWL.imports, None)) + + # skolemize the shape graph so we have consistent identifiers across + # validation through the interpretation of the validation report + shapeg = skolemize_shapes(shapeg) + # TODO: do we want to preserve the materialized triples added to data_graph via reasoning? data_graph = copy_graph(self.graph) - valid, report_g, report_str = pyshacl.validate( - data_graph, - shacl_graph=shapeg, - ont_graph=shapeg, - advanced=True, - js=True, - allow_warnings=True, - # inplace=True, + + # validate the data graph + valid, report_g, report_str = shacl_validate( + data_graph, shapeg, engine=self._bm.shacl_engine ) - assert isinstance(report_g, rdflib.Graph) return ValidationContext( shape_collections, + shapeg, valid, report_g, report_str, @@ -208,43 +218,13 @@ def compile(self, shape_collections: List["ShapeCollection"]): for shape_collection in shape_collections: ontology_graph += shape_collection.graph - ontology_graph = ontology_graph.skolemize() + ontology_graph = skolemize_shapes(ontology_graph) model_graph = copy_graph(self.graph).skolemize() - # We use a fixed-point computation approach to 'compiling' RDF models. - # We accomlish this by keeping track of the size of the graph before and after - # the inference step. If the size of the graph changes, then we know that the - # inference has had some effect. We do this at most 3 times to avoid looping - # forever. - pre_compile_length = len(model_graph) # type: ignore - pyshacl.validate( - data_graph=model_graph, - shacl_graph=ontology_graph, - ont_graph=ontology_graph, - advanced=True, - inplace=True, - js=True, - allow_warnings=True, + return shacl_inference( + model_graph, ontology_graph, engine=self._bm.shacl_engine ) - post_compile_length = len(model_graph) # type: ignore - - attempts = 3 - while attempts > 0 and post_compile_length != pre_compile_length: - pre_compile_length = len(model_graph) # type: ignore - pyshacl.validate( - data_graph=model_graph, - shacl_graph=ontology_graph, - ont_graph=ontology_graph, - advanced=True, - inplace=True, - js=True, - allow_warnings=True, - ) - post_compile_length = len(model_graph) # type: ignore - attempts -= 1 - model_graph -= ontology_graph - return model_graph.de_skolemize() def test_model_against_shapes( self, @@ -291,15 +271,17 @@ def test_model_against_shapes( temp_model_graph += ontology_graph.cbd(shape_uri) - valid, report_g, report_str = pyshacl.validate( - data_graph=temp_model_graph, - ont_graph=ontology_graph, - allow_warnings=True, - advanced=True, - js=True, + # skolemize the shape graph so we have consistent identifiers across + # validation through the interpretation of the validation report + ontology_graph = ontology_graph.skolemize() + + valid, report_g, report_str = shacl_validate( + temp_model_graph, ontology_graph ) + results[shape_uri] = ValidationContext( shape_collections, + ontology_graph, valid, report_g, report_str, diff --git a/buildingmotif/dataclasses/template.py b/buildingmotif/dataclasses/template.py index f0a585bf2..fc6990e01 100644 --- a/buildingmotif/dataclasses/template.py +++ b/buildingmotif/dataclasses/template.py @@ -356,6 +356,7 @@ def evaluate( parameters were provided :rtype: Union[Template, rdflib.Graph] """ + # TODO: handle datatype properties templ = self.in_memory_copy() # put all of the parameter names into the PARAM namespace so they can be # directly subsituted in the template body diff --git a/buildingmotif/dataclasses/validation.py b/buildingmotif/dataclasses/validation.py index dff441dd0..d70fe9035 100644 --- a/buildingmotif/dataclasses/validation.py +++ b/buildingmotif/dataclasses/validation.py @@ -3,7 +3,7 @@ from functools import cached_property from itertools import chain from secrets import token_hex -from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple +from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Union import rdflib from rdflib import Graph, URIRef @@ -252,6 +252,9 @@ class ValidationContext: """ shape_collections: List[ShapeCollection] + # the shapes graph that was used to validate the model + # This will be skolemized! + shapes_graph: Graph valid: bool report: rdflib.Graph report_string: str @@ -264,10 +267,6 @@ def diffset(self) -> Dict[Optional[URIRef], Set[GraphDiff]]: """ return self._report_to_diffset() - @cached_property - def _context(self) -> Graph: - return sum((sc.graph for sc in self.shape_collections), start=Graph()) # type: ignore - def as_templates(self) -> List["Template"]: """Produces the set of templates that reconcile the GraphDiffs from the SHACL validation report. @@ -277,6 +276,43 @@ def as_templates(self) -> List["Template"]: """ return diffset_to_templates(self.diffset) + def get_reasons_with_severity( + self, severity: Union[URIRef, str] + ) -> Dict[Optional[URIRef], Set[GraphDiff]]: + """ + Like diffset, but only includes ValidationResults with the given severity. + Permitted values are: + - SH.Violation or "Violation" for violations + - SH.Warning or "Warning" for warnings + - SH.Info or "Info" for info + + :param severity: the severity to filter by + :type severity: Union[URIRef|str] + :return: a dictionary of focus nodes to the reasons with the given severity + :rtype: Dict[Optional[URIRef], Set[GraphDiff]] + """ + + if not isinstance(severity, URIRef): + severity = SH[severity] + + # check if the severity is a valid SHACL severity + if severity not in {SH.Violation, SH.Warning, SH.Info}: + raise ValueError( + f"Invalid severity: {severity}. Must be one of SH.Violation, SH.Warning, or SH.Info" + ) + + # for each value in the diffset, filter out the diffs that don't have the given severity + # in the diffset.graph + return { + focus: { + diff + for diff in diffs + if diff.validation_result.value(diff._result_uri, SH.resultSeverity) + == severity + } + for focus, diffs in self.diffset.items() + } + def _report_to_diffset(self) -> Dict[Optional[URIRef], Set[GraphDiff]]: """Interpret a SHACL validation report and say what is missing. @@ -288,7 +324,7 @@ def _report_to_diffset(self) -> Dict[Optional[URIRef], Set[GraphDiff]]: # TODO: for future use # proppath = SH["property"] | (SH.qualifiedValueShape / SH["property"]) # type: ignore - g = self.report + self._context + g = self.report + self.shapes_graph diffs: Dict[Optional[URIRef], Set[GraphDiff]] = defaultdict(set) for result in g.objects(predicate=SH.result): # check if the failure is due to our count constraint component diff --git a/buildingmotif/template_matcher.py b/buildingmotif/template_matcher.py index 5147a2b02..b18a91311 100644 --- a/buildingmotif/template_matcher.py +++ b/buildingmotif/template_matcher.py @@ -42,7 +42,7 @@ def parents(self, ntype: Node, ontology: Graph) -> Set[Node]: cache = self.sc_cache[id(ontology)] # populate cache if necessary if ntype not in cache: - cache[ntype] = set(ontology.transitive_objects(ntype, RDFS.subClassOf)) + cache[ntype] = set(ontology.transitive_objects(ntype, RDFS.subClassOf)) # type: ignore return cache[ntype] def superproperties(self, ntype: Node, ontology: Graph) -> Set[Node]: @@ -428,7 +428,7 @@ def building_mapping_subgraphs_iter( subgraph = self.building_subgraph_from_mapping(mapping) if not subgraph.connected(): continue - key = tuple(sorted(subgraph.all_nodes())) + key = tuple(sorted(subgraph.all_nodes())) # type: ignore if key in cache: continue cache.add(key) diff --git a/buildingmotif/utils.py b/buildingmotif/utils.py index 45b8da6e0..46fa4f161 100644 --- a/buildingmotif/utils.py +++ b/buildingmotif/utils.py @@ -7,6 +7,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple +import pyshacl # type: ignore from rdflib import BNode, Graph, Literal, URIRef from rdflib.paths import ZeroOrOne from rdflib.term import Node @@ -474,7 +475,7 @@ def _inline_sh_node(sg: Graph): sh:node ?child . }""" for row in sg.query(q): - parent, child = row + parent, child = row # type: ignore sg.remove((parent, SH.node, child)) pos = sg.predicate_objects(child) for (p, o) in pos: @@ -494,7 +495,7 @@ def _inline_sh_and(sg: Graph): ?andnode rdf:rest*/rdf:first ?child . }""" for row in sg.query(q): - parent, child, to_remove = row + parent, child, to_remove = row # type: ignore sg.remove((parent, SH["and"], to_remove)) pos = sg.predicate_objects(child) for (p, o) in pos: @@ -541,3 +542,153 @@ def skip_uri(uri: URIRef) -> bool: if uri.startswith(ns): return True return False + + +def shacl_validate( + data_graph: Graph, + shape_graph: Optional[Graph] = None, + engine: Optional[str] = "topquadrant", +) -> Tuple[bool, Graph, str]: + """ + Validate the data graph against the shape graph. + Uses the fastest validation method available. Use the 'topquadrant' feature + to use TopQuadrant's SHACL engine. Defaults to using PySHACL. + + :param data_graph: the graph to validate + :type data_graph: Graph + :param shape_graph: the shape graph to validate against + :type shape_graph: Graph, optional + :param engine: the SHACL engine to use, defaults to "topquadrant" + :type engine: str, optional + :return: a tuple containing the validation result, the validation report, and the validation report string + :rtype: Tuple[bool, Graph, str] + """ + + if engine == "topquadrant": + try: + from brick_tq_shacl.topquadrant_shacl import ( + validate as tq_validate, # type: ignore + ) + + return tq_validate(data_graph, shape_graph or Graph()) # type: ignore + except ImportError: + logging.info( + "TopQuadrant SHACL engine not available. Using PySHACL instead." + ) + pass + + return pyshacl.validate( + data_graph, + shacl_graph=shape_graph, + ont_graph=shape_graph, + advanced=True, + js=True, + allow_warnings=True, + ) # type: ignore + + +def shacl_inference( + data_graph: Graph, + shape_graph: Optional[Graph] = None, + engine: Optional[str] = "topquadrant", +) -> Graph: + """ + Infer new triples in the data graph using the shape graph. + Edits the data graph in place. Uses the fastest inference method available. + Use the 'topquadrant' feature to use TopQuadrant's SHACL engine. Defaults to + using PySHACL. + + :param data_graph: the graph to infer new triples in + :type data_graph: Graph + :param shape_graph: the shape graph to use for inference + :type shape_graph: Optional[Graph] + :param engine: the SHACL engine to use, defaults to "topquadrant" + :type engine: str, optional + :return: the data graph with inferred triples + :rtype: Graph + """ + if engine == "topquadrant": + try: + from brick_tq_shacl.topquadrant_shacl import infer as tq_infer + + return tq_infer(data_graph, shape_graph or Graph()) # type: ignore + except ImportError: + logging.info( + "TopQuadrant SHACL engine not available. Using PySHACL instead." + ) + pass + + # We use a fixed-point computation approach to 'compiling' RDF models. + # We accomlish this by keeping track of the size of the graph before and after + # the inference step. If the size of the graph changes, then we know that the + # inference has had some effect. We do this at most 3 times to avoid looping + # forever. + pre_compile_length = len(data_graph) # type: ignore + pyshacl.validate( + data_graph=data_graph, + shacl_graph=shape_graph, + ont_graph=shape_graph, + advanced=True, + inplace=True, + js=True, + allow_warnings=True, + ) + post_compile_length = len(data_graph) # type: ignore + + attempts = 3 + while attempts > 0 and post_compile_length != pre_compile_length: + pre_compile_length = len(data_graph) # type: ignore + pyshacl.validate( + data_graph=data_graph, + shacl_graph=shape_graph, + ont_graph=shape_graph, + advanced=True, + inplace=True, + js=True, + allow_warnings=True, + ) + post_compile_length = len(data_graph) # type: ignore + attempts -= 1 + return data_graph - (shape_graph or Graph()) + + +def skolemize_shapes(g: Graph) -> Graph: + """ + Skolemize the shapes in the graph. + + :param g: the graph to skolemize + :type g: Graph + :return: the skolemized graph + :rtype: Graph + """ + # write a query to update agraph by changing all PropertyShape blank nodes + # to URIRefs + g = copy_graph(g) + property_shapes = list(g.subjects(predicate=RDF.type, object=SH.PropertyShape)) + property_shapes.extend(list(g.objects(predicate=SH.property))) + replacements = {} + for ps in property_shapes: + # if not bnode, skip + if not isinstance(ps, BNode): + continue + # create a new URIRef + new_ps = URIRef(f"urn:well-known/{secrets.token_hex(4)}") + # replace the old BNode with the new URIRef + replacements[ps] = new_ps + # apply the replacements + replace_nodes(g, replacements) + + # name all objects of qualifiedValueShape + qvs = list(g.objects(predicate=SH.qualifiedValueShape)) + replacements = {} + for qv in qvs: + # if not bnode, skip + if not isinstance(qv, BNode): + continue + # create a new URIRef + new_qv = URIRef(f"urn:well-known/{secrets.token_hex(4)}") + # replace the old BNode with the new URIRef + replacements[qv] = new_qv + # apply the replacements + replace_nodes(g, replacements) + return g diff --git a/poetry.lock b/poetry.lock index 68c533cec..f9cf54136 100644 --- a/poetry.lock +++ b/poetry.lock @@ -345,6 +345,20 @@ files = [ {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, ] +[[package]] +name = "brick-tq-shacl" +version = "0.3.2a4" +description = "Wraps topquadrant's SHACL implementation in a simple Python wrapper" +optional = true +python-versions = ">=3.8.1,<4.0.0" +files = [ + {file = "brick_tq_shacl-0.3.2a4-py3-none-any.whl", hash = "sha256:5d54159d1da328daca7cf9b6abe3831865ac68f12244fcff54a682e4bf69f09d"}, + {file = "brick_tq_shacl-0.3.2a4.tar.gz", hash = "sha256:2bad45c69d008c1500b5b7f63d0c09ca7931311da6f264c55e7de81cd423d960"}, +] + +[package.dependencies] +rdflib = ">=7.0,<8.0" + [[package]] name = "certifi" version = "2024.2.2" @@ -557,13 +571,13 @@ files = [ [[package]] name = "comm" -version = "0.2.1" +version = "0.2.2" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false python-versions = ">=3.8" files = [ - {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, - {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, ] [package.dependencies] @@ -574,63 +588,63 @@ test = ["pytest"] [[package]] name = "coverage" -version = "7.4.3" +version = "7.4.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, - {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, - {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, - {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, - {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, - {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, - {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, - {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, - {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, - {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, - {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, - {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, - {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, - {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, ] [package.dependencies] @@ -1033,32 +1047,32 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.1" +version = "7.0.2" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, - {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, + {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, + {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "importlib-resources" -version = "6.1.2" +version = "6.3.1" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.2-py3-none-any.whl", hash = "sha256:9a0a862501dc38b68adebc82970140c9e4209fc99601782925178f8386339938"}, - {file = "importlib_resources-6.1.2.tar.gz", hash = "sha256:308abf8474e2dba5f867d279237cd4076482c3de7104a40b41426370e891549b"}, + {file = "importlib_resources-6.3.1-py3-none-any.whl", hash = "sha256:4811639ca7fa830abdb8e9ca0a104dc6ad13de691d9fe0d3173a71304f068159"}, + {file = "importlib_resources-6.3.1.tar.gz", hash = "sha256:29a3d16556e330c3c8fb8202118c5ff41241cc34cbfb25989bbad226d99b7995"}, ] [package.dependencies] @@ -1066,7 +1080,7 @@ zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] +testing = ["jaraco.collections", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -1263,18 +1277,15 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "json5" -version = "0.9.20" +version = "0.9.24" description = "A Python implementation of the JSON5 data format." optional = false python-versions = ">=3.8" files = [ - {file = "json5-0.9.20-py3-none-any.whl", hash = "sha256:f623485b37fad95783233bad9352d21526709cbd9a2ec41ddc3e950fca85b701"}, - {file = "json5-0.9.20.tar.gz", hash = "sha256:20a255981244081d5aaa4adc90d31cdbf05bed1863993cbf300b8e2cd2b6de88"}, + {file = "json5-0.9.24-py3-none-any.whl", hash = "sha256:4ca101fd5c7cb47960c055ef8f4d0e31e15a7c6c48c3b6f1473fc83b6c462a13"}, + {file = "json5-0.9.24.tar.gz", hash = "sha256:0c638399421da959a20952782800e5c1a78c14e08e1dc9738fa10d8ec14d58c8"}, ] -[package.extras] -dev = ["hypothesis"] - [[package]] name = "jsonpointer" version = "2.4" @@ -1418,13 +1429,13 @@ testing = ["coverage", "ipykernel", "jupytext", "matplotlib", "nbdime", "nbforma [[package]] name = "jupyter-client" -version = "8.6.0" +version = "8.6.1" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.6.0-py3-none-any.whl", hash = "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99"}, - {file = "jupyter_client-8.6.0.tar.gz", hash = "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7"}, + {file = "jupyter_client-8.6.1-py3-none-any.whl", hash = "sha256:3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f"}, + {file = "jupyter_client-8.6.1.tar.gz", hash = "sha256:e842515e2bab8e19186d89fdfea7abd15e39dd581f94e399f00e2af5a1652d3f"}, ] [package.dependencies] @@ -1465,13 +1476,13 @@ test = ["flaky", "pexpect", "pytest"] [[package]] name = "jupyter-core" -version = "5.7.1" +version = "5.7.2" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, - {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, ] [package.dependencies] @@ -1481,17 +1492,17 @@ traitlets = ">=5.3" [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyter-events" -version = "0.9.0" +version = "0.10.0" description = "Jupyter Event System library" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_events-0.9.0-py3-none-any.whl", hash = "sha256:d853b3c10273ff9bc8bb8b30076d65e2c9685579db736873de6c2232dde148bf"}, - {file = "jupyter_events-0.9.0.tar.gz", hash = "sha256:81ad2e4bc710881ec274d31c6c50669d71bbaa5dd9d01e600b56faa85700d399"}, + {file = "jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960"}, + {file = "jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22"}, ] [package.dependencies] @@ -1561,13 +1572,13 @@ test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-sc [[package]] name = "jupyter-server-terminals" -version = "0.5.2" +version = "0.5.3" description = "A Jupyter Server Extension Providing Terminals." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_server_terminals-0.5.2-py3-none-any.whl", hash = "sha256:1b80c12765da979513c42c90215481bbc39bd8ae7c0350b4f85bc3eb58d0fa80"}, - {file = "jupyter_server_terminals-0.5.2.tar.gz", hash = "sha256:396b5ccc0881e550bf0ee7012c6ef1b53edbde69e67cab1d56e89711b46052e8"}, + {file = "jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa"}, + {file = "jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269"}, ] [package.dependencies] @@ -1580,13 +1591,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.1.3" +version = "4.1.5" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.1.3-py3-none-any.whl", hash = "sha256:67dbec7057c6ad46f08a3667a80bdb890df9453822c93b5ddfd5e8313a718ef9"}, - {file = "jupyterlab-4.1.3.tar.gz", hash = "sha256:b85bd8766f995d23461e1f68a0cbc688d23e0af2b6f42a7768fc7b1826b2ec39"}, + {file = "jupyterlab-4.1.5-py3-none-any.whl", hash = "sha256:3bc843382a25e1ab7bc31d9e39295a9f0463626692b7995597709c0ab236ab2c"}, + {file = "jupyterlab-4.1.5.tar.gz", hash = "sha256:c9ad75290cb10bfaff3624bf3fbb852319b4cce4c456613f8ebbaa98d03524db"}, ] [package.dependencies] @@ -1625,13 +1636,13 @@ files = [ [[package]] name = "jupyterlab-server" -version = "2.25.3" +version = "2.25.4" description = "A set of server components for JupyterLab and JupyterLab like applications." optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab_server-2.25.3-py3-none-any.whl", hash = "sha256:c48862519fded9b418c71645d85a49b2f0ec50d032ba8316738e9276046088c1"}, - {file = "jupyterlab_server-2.25.3.tar.gz", hash = "sha256:846f125a8a19656611df5b03e5912c8393cea6900859baa64fa515eb64a8dc40"}, + {file = "jupyterlab_server-2.25.4-py3-none-any.whl", hash = "sha256:eb645ecc8f9b24bac5decc7803b6d5363250e16ec5af814e516bc2c54dd88081"}, + {file = "jupyterlab_server-2.25.4.tar.gz", hash = "sha256:2098198e1e82e0db982440f9b5136175d73bea2cd42a6480aa6fd502cb23c4f9"}, ] [package.dependencies] @@ -1647,7 +1658,7 @@ requests = ">=2.31" [package.extras] docs = ["autodoc-traits", "jinja2 (<3.2.0)", "mistune (<4)", "myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-copybutton", "sphinxcontrib-openapi (>0.8)"] openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"] -test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] +test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0,<8)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] [[package]] name = "jupyterlab-widgets" @@ -1900,41 +1911,50 @@ files = [ [[package]] name = "mypy" -version = "0.931" +version = "1.9.0" description = "Optional static typing for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"}, - {file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"}, - {file = "mypy-0.931-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714"}, - {file = "mypy-0.931-cp310-cp310-win_amd64.whl", hash = "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc"}, - {file = "mypy-0.931-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d"}, - {file = "mypy-0.931-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d"}, - {file = "mypy-0.931-cp36-cp36m-win_amd64.whl", hash = "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c"}, - {file = "mypy-0.931-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0"}, - {file = "mypy-0.931-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05"}, - {file = "mypy-0.931-cp37-cp37m-win_amd64.whl", hash = "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7"}, - {file = "mypy-0.931-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0"}, - {file = "mypy-0.931-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069"}, - {file = "mypy-0.931-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799"}, - {file = "mypy-0.931-cp38-cp38-win_amd64.whl", hash = "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a"}, - {file = "mypy-0.931-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"}, - {file = "mypy-0.931-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266"}, - {file = "mypy-0.931-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd"}, - {file = "mypy-0.931-cp39-cp39-win_amd64.whl", hash = "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697"}, - {file = "mypy-0.931-py3-none-any.whl", hash = "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d"}, - {file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, + {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, + {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, + {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, + {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, + {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, + {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, + {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, + {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, + {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, + {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, + {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, + {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, + {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, + {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, + {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, + {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, + {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, + {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, + {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, + {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, + {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, + {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, ] [package.dependencies] -mypy-extensions = ">=0.4.3" -tomli = ">=1.1.0" -typing-extensions = ">=3.10" +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] [[package]] name = "mypy-extensions" @@ -2062,13 +2082,13 @@ webpdf = ["playwright"] [[package]] name = "nbformat" -version = "5.9.2" +version = "5.10.3" description = "The Jupyter Notebook format" optional = false python-versions = ">=3.8" files = [ - {file = "nbformat-5.9.2-py3-none-any.whl", hash = "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9"}, - {file = "nbformat-5.9.2.tar.gz", hash = "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192"}, + {file = "nbformat-5.10.3-py3-none-any.whl", hash = "sha256:d9476ca28676799af85385f409b49d95e199951477a159a576ef2a675151e5e8"}, + {file = "nbformat-5.10.3.tar.gz", hash = "sha256:60ed5e910ef7c6264b87d644f276b1b49e24011930deef54605188ddeb211685"}, ] [package.dependencies] @@ -2083,13 +2103,13 @@ test = ["pep440", "pre-commit", "pytest", "testpath"] [[package]] name = "nbmake" -version = "1.5.2" +version = "1.5.3" description = "Pytest plugin for testing notebooks" optional = false python-versions = ">=3.8.0,<4.0.0" files = [ - {file = "nbmake-1.5.2-py3-none-any.whl", hash = "sha256:b8669c248177e2bc61139b7ce1bcbeb2ef2435e59e2308927737d6c84c53fc40"}, - {file = "nbmake-1.5.2.tar.gz", hash = "sha256:fc423b1f0d5e964a3928c77ff7b18fe50067444ee3479fdc1f82fc77504f0a30"}, + {file = "nbmake-1.5.3-py3-none-any.whl", hash = "sha256:6cfa2b926d335e9c6dce7e8543d01b2398b0a56c03131c5c0bce2b1722116212"}, + {file = "nbmake-1.5.3.tar.gz", hash = "sha256:0b76b829e8b128eb1895539bacf515a1ee85e5b7b492cdfe76e3a12f804e069e"}, ] [package.dependencies] @@ -2183,13 +2203,13 @@ setuptools = "*" [[package]] name = "notebook" -version = "7.1.1" +version = "7.1.2" description = "Jupyter Notebook - A web-based notebook environment for interactive computing" optional = false python-versions = ">=3.8" files = [ - {file = "notebook-7.1.1-py3-none-any.whl", hash = "sha256:197d8e0595acabf4005851c8716e952a81b405f7aefb648067a761fbde267ce7"}, - {file = "notebook-7.1.1.tar.gz", hash = "sha256:818e7420fa21f402e726afb9f02df7f3c10f294c02e383ed19852866c316108b"}, + {file = "notebook-7.1.2-py3-none-any.whl", hash = "sha256:fc6c24b9aef18d0cd57157c9c47e95833b9b0bdc599652639acf0bdb61dc7d5f"}, + {file = "notebook-7.1.2.tar.gz", hash = "sha256:efc2c80043909e0faa17fce9e9b37c059c03af0ec99a4d4db84cb21d9d2e936a"}, ] [package.dependencies] @@ -2262,13 +2282,13 @@ rdflib = ">=6.0.2" [[package]] name = "packaging" -version = "23.2" +version = "24.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] [[package]] @@ -2801,13 +2821,13 @@ js = ["pyduktape2 (>=0.4.6,<0.5.0)"] [[package]] name = "pytest" -version = "8.0.2" +version = "8.1.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"}, - {file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"}, + {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, + {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, ] [package.dependencies] @@ -2815,11 +2835,11 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.3.0,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" @@ -3122,13 +3142,13 @@ test = ["pytest (>=6,!=7.0.0,!=7.0.1)", "pytest-cov (>=3.0.0)", "pytest-qt"] [[package]] name = "rdflib" -version = "6.3.2" +version = "7.0.0" description = "RDFLib is a Python library for working with RDF, a simple yet powerful language for representing information." optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.8.1,<4.0.0" files = [ - {file = "rdflib-6.3.2-py3-none-any.whl", hash = "sha256:36b4e74a32aa1e4fa7b8719876fb192f19ecd45ff932ea5ebbd2e417a0247e63"}, - {file = "rdflib-6.3.2.tar.gz", hash = "sha256:72af591ff704f4caacea7ecc0c5a9056b8553e0489dd4f35a9bc52dbd41522e0"}, + {file = "rdflib-7.0.0-py3-none-any.whl", hash = "sha256:0438920912a642c866a513de6fe8a0001bd86ef975057d6962c79ce4771687cd"}, + {file = "rdflib-7.0.0.tar.gz", hash = "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae"}, ] [package.dependencies] @@ -3160,13 +3180,13 @@ SQLAlchemy = ">=1.1.4,<2.0.0" [[package]] name = "referencing" -version = "0.33.0" +version = "0.34.0" description = "JSON Referencing + Python" optional = false python-versions = ">=3.8" files = [ - {file = "referencing-0.33.0-py3-none-any.whl", hash = "sha256:39240f2ecc770258f28b642dd47fd74bc8b02484de54e1882b74b35ebd779bd5"}, - {file = "referencing-0.33.0.tar.gz", hash = "sha256:c775fedf74bc0f9189c2a3be1c12fd03e8c23f4d371dce795df44e06c5b412f7"}, + {file = "referencing-0.34.0-py3-none-any.whl", hash = "sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4"}, + {file = "referencing-0.34.0.tar.gz", hash = "sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844"}, ] [package.dependencies] @@ -3806,6 +3826,8 @@ files = [ [package.dependencies] greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +mypy = {version = ">=0.910", optional = true, markers = "python_version >= \"3\" and extra == \"mypy\""} +sqlalchemy2-stubs = {version = "*", optional = true, markers = "extra == \"mypy\""} [package.extras] aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] @@ -3877,13 +3899,13 @@ widechars = ["wcwidth"] [[package]] name = "terminado" -version = "0.18.0" +version = "0.18.1" description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." optional = false python-versions = ">=3.8" files = [ - {file = "terminado-0.18.0-py3-none-any.whl", hash = "sha256:87b0d96642d0fe5f5abd7783857b9cab167f221a39ff98e3b9619a788a3c0f2e"}, - {file = "terminado-0.18.0.tar.gz", hash = "sha256:1ea08a89b835dd1b8c0c900d92848147cef2537243361b2e3f4dc15df9b6fded"}, + {file = "terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0"}, + {file = "terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e"}, ] [package.dependencies] @@ -3958,28 +3980,28 @@ files = [ [[package]] name = "traitlets" -version = "5.14.1" +version = "5.14.2" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" files = [ - {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, - {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, + {file = "traitlets-5.14.2-py3-none-any.whl", hash = "sha256:fcdf85684a772ddeba87db2f398ce00b40ff550d1528c03c14dbf6a02003cd80"}, + {file = "traitlets-5.14.2.tar.gz", hash = "sha256:8cdd83c040dab7d1dee822678e5f5d100b514f7b72b01615b26fc5718916fdf9"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.1)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "types-jsonschema" -version = "4.21.0.20240118" +version = "4.21.0.20240311" description = "Typing stubs for jsonschema" optional = false python-versions = ">=3.8" files = [ - {file = "types-jsonschema-4.21.0.20240118.tar.gz", hash = "sha256:31aae1b5adc0176c1155c2d4f58348b22d92ae64315e9cc83bd6902168839232"}, - {file = "types_jsonschema-4.21.0.20240118-py3-none-any.whl", hash = "sha256:77a4ac36b0be4f24274d5b9bf0b66208ee771c05f80e34c4641de7d63e8a872d"}, + {file = "types-jsonschema-4.21.0.20240311.tar.gz", hash = "sha256:f7165ce70abd91df490c73b089873afd2899c5e56430ee495b64f851ad01f287"}, + {file = "types_jsonschema-4.21.0.20240311-py3-none-any.whl", hash = "sha256:e872f5661513824edf9698f73a66c9c114713d93eab58699bd0532e7e6db5750"}, ] [package.dependencies] @@ -3987,24 +4009,24 @@ referencing = "*" [[package]] name = "types-python-dateutil" -version = "2.8.19.20240106" +version = "2.9.0.20240316" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.8.19.20240106.tar.gz", hash = "sha256:1f8db221c3b98e6ca02ea83a58371b22c374f42ae5bbdf186db9c9a76581459f"}, - {file = "types_python_dateutil-2.8.19.20240106-py3-none-any.whl", hash = "sha256:efbbdc54590d0f16152fa103c9879c7d4a00e82078f6e2cf01769042165acaa2"}, + {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, + {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, ] [[package]] name = "types-pyyaml" -version = "6.0.12.12" +version = "6.0.12.20240311" description = "Typing stubs for PyYAML" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-PyYAML-6.0.12.12.tar.gz", hash = "sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062"}, - {file = "types_PyYAML-6.0.12.12-py3-none-any.whl", hash = "sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24"}, + {file = "types-PyYAML-6.0.12.20240311.tar.gz", hash = "sha256:a9e0f0f88dc835739b0c1ca51ee90d04ca2a897a71af79de9aec5f38cb0a5342"}, + {file = "types_PyYAML-6.0.12.20240311-py3-none-any.whl", hash = "sha256:b845b06a1c7e54b8e5b4c683043de0d9caf205e7434b3edc678ff2411979b8f6"}, ] [[package]] @@ -4155,13 +4177,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "wheel" -version = "0.42.0" +version = "0.43.0" description = "A built-package format for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "wheel-0.42.0-py3-none-any.whl", hash = "sha256:177f9c9b0d45c47873b619f5b650346d632cdc35fb5e4d25058e09c9e581433d"}, - {file = "wheel-0.42.0.tar.gz", hash = "sha256:c45be39f7882c9d34243236f2d63cbd58039e360f85d0913425fbd7ceea617a8"}, + {file = "wheel-0.43.0-py3-none-any.whl", hash = "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"}, + {file = "wheel-0.43.0.tar.gz", hash = "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85"}, ] [package.extras] @@ -4180,27 +4202,28 @@ files = [ [[package]] name = "zipp" -version = "3.17.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, - {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy", "pytest-ruff (>=0.2.1)"] [extras] all = ["psycopg2"] all-ingresses = [] bacnet-ingress = [] postgres = ["psycopg2"] +topquadrant = ["brick-tq-shacl"] xlsx-ingress = [] [metadata] lock-version = "2.0" python-versions = ">=3.8.1, <3.12" -content-hash = "67cd841a2191127f13d7cf4b4344b5eb1066c899730839c6f224df994871b5dc" +content-hash = "e9bd5f48cee921f5e9a11268cb0d9aca4cc673eea5db0275b83a53645395bc46" diff --git a/pyproject.toml b/pyproject.toml index b6e0669dc..565dcda98 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,8 +20,8 @@ buildingmotif = 'buildingmotif.bin.cli:app' [tool.poetry.dependencies] python = ">=3.8.1, <3.12" -rdflib = "^6.3.2" -SQLAlchemy = "^1.4" +rdflib = ">=7.0" +SQLAlchemy = {extras = ["mypy"], version = "^1.4.44"} pyaml = "^21.10.1" networkx = "^2.7.1" types-PyYAML = "^6.0.4" @@ -36,17 +36,17 @@ setuptools = "^65.6.3" psycopg2 = {version="^2.9.5", optional=true} pygit2 = "~1.11.1" jsonschema = "^4.21.1" - +brick-tq-shacl = {optional = true, version="0.3.2a4"} werkzeug="^2.3.7" -types-jsonschema = "^4.21.0.20240118" +types-jsonschema = "^4.21.0.20240311" [tool.poetry.group.dev.dependencies] black = "^22.3.0" isort = "^5.10.1" pre-commit = "^2.17.0" pytest-cov = "^3.0.0" -mypy = "^0.931" -sqlalchemy2-stubs = "^0.0.2-alpha.20" +mypy = "v1.9.0" +sqlalchemy2-stubs = "^0.0.2a38" psycopg2-binary = "^2.9.5" jupytext = "^1.13.8" jupyter = "^1.0.0" @@ -63,6 +63,7 @@ pytest = "^8.0.2" [tool.poetry.extras] all = ["BAC0", "openpyxl", "netifaces", "pytz", "psycopg2"] postgres = ["psycopg2"] +topquadrant = ["brick-tq-shacl"] # dependencies for ingresses (e.g. BAC0, openpyxl) should be included in dev dependencies bacnet-ingress = ["BAC0", "netifaces", "pytz"] xlsx-ingress = ["openpyxl"] diff --git a/tests/integration/fixtures/buildingmotif/Dockerfile b/tests/integration/fixtures/buildingmotif/Dockerfile index fccfae549..84a49ac66 100644 --- a/tests/integration/fixtures/buildingmotif/Dockerfile +++ b/tests/integration/fixtures/buildingmotif/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8 +FROM python:3.9 WORKDIR /home/buildingmotif @@ -15,4 +15,4 @@ COPY notebooks notebooks COPY migrations migrations COPY docs docs -RUN poetry install \ No newline at end of file +RUN poetry install diff --git a/tests/unit/api/test_model.py b/tests/unit/api/test_model.py index ca7df7e26..e165f88b6 100644 --- a/tests/unit/api/test_model.py +++ b/tests/unit/api/test_model.py @@ -253,14 +253,15 @@ def test_create_model_bad_name(client, building_motif): assert len(building_motif.table_connection.get_all_db_models()) == 0 -def test_validate_model(client, building_motif): +def test_validate_model(client, building_motif, shacl_engine): + building_motif.shacl_engine = shacl_engine # Set up + brick = Library.load(ontology_graph="tests/unit/fixtures/Brick.ttl") + assert brick is not None library_1 = Library.load(ontology_graph="tests/unit/fixtures/shapes/shape1.ttl") assert library_1 is not None library_2 = Library.load(directory="tests/unit/fixtures/templates") assert library_2 is not None - brick = Library.load(ontology_graph="tests/unit/fixtures/Brick.ttl") - assert brick is not None BLDG = Namespace("urn:building/") model = Model.create(name=BLDG) @@ -270,7 +271,10 @@ def test_validate_model(client, building_motif): results = client.post( f"/models/{model.id}/validate", headers={"Content-Type": "application/json"}, - json={"library_ids": [library_1.id, library_2.id, brick.id]}, + json={ + "library_ids": [library_1.id, library_2.id, brick.id], + "shacl_engine": shacl_engine, + }, ) # Assert @@ -297,7 +301,7 @@ def test_validate_model(client, building_motif): results = client.post( f"/models/{model.id}/validate", headers={"Content-Type": "application/json"}, - json={"library_ids": [library_1.id, library_2.id]}, + json={"library_ids": [library_1.id, library_2.id, brick.id]}, ) # Assert @@ -309,7 +313,8 @@ def test_validate_model(client, building_motif): assert results.get_json()["reasons"] == {} -def test_validate_model_bad_model_id(client, building_motif): +def test_validate_model_bad_model_id(client, building_motif, shacl_engine): + building_motif.shacl_engine = shacl_engine # Set up library = Library.load(ontology_graph="tests/unit/fixtures/shapes/shape1.ttl") assert library is not None @@ -325,7 +330,8 @@ def test_validate_model_bad_model_id(client, building_motif): assert results.status_code == 404 -def test_validate_model_no_args(client, building_motif): +def test_validate_model_no_args(client, building_motif, shacl_engine): + building_motif.shacl_engine = shacl_engine # Set up BLDG = Namespace("urn:building/") model = Model.create(name=BLDG) @@ -344,7 +350,8 @@ def test_validate_model_no_args(client, building_motif): assert results.get_json()["reasons"] == {} -def test_validate_model_no_library_ids(client, building_motif): +def test_validate_model_no_library_ids(client, building_motif, shacl_engine): + building_motif.shacl_engine = shacl_engine # Set up BLDG = Namespace("urn:building/") model = Model.create(name=BLDG) @@ -413,7 +420,8 @@ def test_validate_model_bad_args(client, building_motif): assert results.status_code == 400 -def test_test_model_against_shapes(client, building_motif): +def test_test_model_against_shapes(client, building_motif, shacl_engine): + building_motif.shacl_engine = shacl_engine # Load libraries Library.load(ontology_graph=str(PROJECT_DIR / "libraries/brick/Brick-subset.ttl")) ashrae_g36 = Library.load( diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 0797c83f8..1d02638c2 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -100,3 +100,7 @@ def pytest_generate_tests(metafunc): if "builtin_ontology" in metafunc.fixturenames: builtin_ontology = {"brick/Brick.ttl", "constraints/constraints.ttl"} metafunc.parametrize("builtin_ontology", builtin_ontology) + + if "shacl_engine" in metafunc.fixturenames: + shacl_engine = {"pyshacl", "topquadrant"} + metafunc.parametrize("shacl_engine", shacl_engine) diff --git a/tests/unit/dataclasses/test_model.py b/tests/unit/dataclasses/test_model.py index 433069e01..7bd5b89ce 100644 --- a/tests/unit/dataclasses/test_model.py +++ b/tests/unit/dataclasses/test_model.py @@ -1,6 +1,6 @@ import pytest -from rdflib import BNode, Graph, Literal, Namespace, URIRef -from rdflib.compare import isomorphic +from rdflib import Graph, Literal, Namespace, URIRef +from rdflib.compare import graph_diff, isomorphic, to_isomorphic from rdflib.namespace import FOAF from buildingmotif import BuildingMOTIF @@ -53,7 +53,8 @@ def test_update_model_manifest(clean_building_motif): assert len(list(m.get_manifest().graph.subjects(RDF.type, SH.NodeShape))) == 2 -def test_validate_model_manifest(clean_building_motif): +def test_validate_model_manifest(clean_building_motif, shacl_engine): + clean_building_motif.shacl_engine = shacl_engine m = Model.create(name="https://example.com", description="a very good model") m.graph.add((URIRef("https://example.com/vav1"), A, BRICK.VAV)) @@ -90,7 +91,8 @@ def test_validate_model_manifest(clean_building_motif): assert result.valid -def test_validate_model_manifest_with_imports(clean_building_motif): +def test_validate_model_manifest_with_imports(clean_building_motif, shacl_engine): + clean_building_motif.shacl_engine = shacl_engine m = Model.create(name="https://example.com", description="a very good model") m.graph.add((URIRef("https://example.com/vav1"), A, BRICK.VAV)) @@ -125,11 +127,12 @@ def test_validate_model_manifest_with_imports(clean_building_motif): ) # validate against manifest -- should pass now - result = m.validate(error_on_missing_imports=False) + result = m.validate() assert result.valid, result.report_string -def test_validate_model_explicit_shapes(clean_building_motif): +def test_validate_model_explicit_shapes(clean_building_motif, shacl_engine): + clean_building_motif.shacl_engine = shacl_engine # load library Library.load(ontology_graph="tests/unit/fixtures/Brick1.3rc1-equip-only.ttl") lib = Library.load(ontology_graph="tests/unit/fixtures/shapes/shape1.ttl") @@ -154,10 +157,11 @@ def test_validate_model_explicit_shapes(clean_building_motif): assert len(ctx.diffset) == 0 -def test_validate_model_with_failure(bm: BuildingMOTIF): +def test_validate_model_with_failure(bm: BuildingMOTIF, shacl_engine): """ Test that a model correctly validates """ + bm.shacl_engine = shacl_engine shape_graph_data = """ @prefix sh: . @prefix rdfs: . @@ -191,10 +195,6 @@ def test_validate_model_with_failure(bm: BuildingMOTIF): assert not ctx.valid assert len(ctx.diffset) == 1 diff = next(iter(ctx.diffset.values())).pop() - 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"))) @@ -204,8 +204,9 @@ def test_validate_model_with_failure(bm: BuildingMOTIF): assert ctx.valid -def test_model_compile(bm: BuildingMOTIF): +def test_model_compile(bm: BuildingMOTIF, shacl_engine): """Test that model compilation gives expected results""" + bm.shacl_engine = shacl_engine small_office_model = Model.create("http://example.org/building/") small_office_model.graph.parse( "tests/unit/fixtures/smallOffice_brick.ttl", format="ttl" @@ -219,7 +220,12 @@ def test_model_compile(bm: BuildingMOTIF): "tests/unit/fixtures/smallOffice_brick_compiled.ttl", format="ttl" ) - assert isomorphic(compiled_model, precompiled_model) + # returns in_both, in_first, in_second + _, in_first, _ = graph_diff( + to_isomorphic(precompiled_model), to_isomorphic(compiled_model) + ) + # passes if everything from precompiled_model is in compiled_model + assert len(in_first) == 0 def test_get_manifest(clean_building_motif): @@ -232,7 +238,8 @@ def test_get_manifest(clean_building_motif): assert isomorphic(manifest.load(manifest.id).graph, manifest.graph) -def test_validate_with_manifest(clean_building_motif): +def test_validate_with_manifest(clean_building_motif, shacl_engine): + clean_building_motif.shacl_engine = shacl_engine g = Graph() g.parse( data=""" @@ -269,5 +276,90 @@ def test_validate_with_manifest(clean_building_motif): manifest = model.get_manifest() manifest.add_graph(manifest_g) - ctx = model.validate(None) + ctx = model.validate() assert not ctx.valid, "Model validated but it should throw an error" + + +def test_get_validation_severity(clean_building_motif, shacl_engine): + NS = Namespace("urn:ex/") + clean_building_motif.shacl_engine = shacl_engine + g = Graph() + g.parse( + data=""" + @prefix rdf: . + @prefix rdfs: . + @prefix skos: . + @prefix brick: . + @prefix sh: . + @prefix : . + :a a :Class . # will fail all shapes + """ + ) + + manifest_g = Graph() + manifest_g.parse( + data=""" + @prefix rdf: . + @prefix rdfs: . + @prefix skos: . + @prefix brick: . + @prefix sh: . + @prefix : . + :shape_warning a sh:NodeShape ; + sh:targetClass :Class ; + sh:property [ + sh:path rdfs:label ; + sh:minCount 1 ; + sh:severity sh:Warning ; + ] . + :shape_violation1 a sh:NodeShape ; + sh:targetClass :Class ; + sh:property [ + sh:path brick:hasPoint ; + sh:minCount 1 ; + sh:severity sh:Violation ; + ] . + :shape_violation2 a sh:NodeShape ; + sh:targetClass :Class ; + sh:property [ + sh:path brick:feeds ; + sh:minCount 1 ; + sh:severity sh:Violation ; + ] . + :shape_info a sh:NodeShape ; + sh:targetClass :Class ; + sh:property [ + sh:path brick:hasPart ; + sh:minCount 1 ; + sh:severity sh:Info ; + ] . + + """ + ) + + model = Model.create(name=NS) + model.add_graph(g) + manifest = model.get_manifest() + manifest.add_graph(manifest_g) + + ctx = model.validate() + assert not ctx.valid, "Model validated but it should throw an error" + + # check that only valid severity values are accepted + with pytest.raises(ValueError): + reasons = ctx.get_reasons_with_severity("Nonexist") + + for severity in ["Violation", SH.Violation]: + reasons = ctx.get_reasons_with_severity(severity) + assert set(reasons.keys()) == {NS["a"]} + assert len(reasons[NS["a"]]) == 2, f"Expected 2 violations, got {reasons}" + + for severity in ["Info", SH.Info]: + reasons = ctx.get_reasons_with_severity(severity) + assert set(reasons.keys()) == {NS["a"]} + assert len(reasons[NS["a"]]) == 1, f"Expected 1 info, got {reasons}" + + for severity in ["Warning", SH.Warning]: + reasons = ctx.get_reasons_with_severity(severity) + assert set(reasons.keys()) == {NS["a"]} + assert len(reasons[NS["a"]]) == 1, f"Expected 1 warning, got {reasons}" diff --git a/tests/unit/fixtures/shapes/shape2.ttl b/tests/unit/fixtures/shapes/shape2.ttl index 8c08d0864..b14cc9dd1 100644 --- a/tests/unit/fixtures/shapes/shape2.ttl +++ b/tests/unit/fixtures/shapes/shape2.ttl @@ -14,6 +14,7 @@ sh:path brick:hasPoint ; sh:qualifiedValueShape [ sh:class brick:Air_Flow_Sensor ] ; sh:qualifiedMinCount 1 ; + sh:message "VAV must have at least one air flow sensor" ; sh:minCount 1; ] ; . @@ -24,6 +25,7 @@ sh:path brick:hasPoint ; sh:qualifiedValueShape [ sh:class brick:Temperature_Sensor ] ; sh:qualifiedMinCount 1 ; + sh:message "Terminal Unit must have at least one temperature sensor" ; sh:minCount 1; ] ; . diff --git a/tests/unit/fixtures/smallOffice_brick_compiled.ttl b/tests/unit/fixtures/smallOffice_brick_compiled.ttl index 4f466adf6..1463e98f1 100644 --- a/tests/unit/fixtures/smallOffice_brick_compiled.ttl +++ b/tests/unit/fixtures/smallOffice_brick_compiled.ttl @@ -4,6 +4,11 @@ a owl:Ontology . + a brick:Thermal_Power_Sensor ; + rdfs:label "Core_ZN-ZN-HP-Htg-Coil-27-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Electrical_Power_Sensor ; rdfs:label "Core_ZN-ZN-HP-Htg-Coil-27-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; brick:hasUnit ; @@ -14,2884 +19,861 @@ brick:hasUnit ; brick:isPointOf . - a brick:Electrical_Power_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Fan_Fan_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Fan_Fan_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-HP-Htg-Coil-29-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-1spd-DX-HP-Clg-Coil-29kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Fan_Fan_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-HP-Htg-Coil-30-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-1spd-DX-HP-Clg-Coil-30kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Fan_Fan_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Electrical_Power_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Fan_Fan_Electricity_Rate" ; - brick:hasUnit ; - brick:isPointOf . - - brick:isTagOf . - - a brick:Energy_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; - brick:hasTag , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Energy_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; - brick:hasTag , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Energy_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; - brick:hasTag , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Energy_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; - brick:hasTag , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Energy_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; - brick:hasTag , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Core_ZN-ZN-HP-Htg-Coil-27-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - a brick:Thermal_Power_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-1spd-DX-HP-Clg-Coil-27kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; - brick:hasTag , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Min_Position_Setpoint_Limit ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Diffuser-Zone-Air-Terminal-Minimum-Air-Flow-Fraction" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Damper_Position_Command ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; - brick:hasTag , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Electrical_Power_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Fan_Fan_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Thermal_Power_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Energy_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; brick:hasUnit ; brick:isPointOf . a brick:Air_Flow_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Damper_Position_Command ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-HP-Htg-Coil-29-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-1spd-DX-HP-Clg-Coil-29kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Damper_Position_Command ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-HP-Htg-Coil-30-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-1spd-DX-HP-Clg-Coil-30kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Damper_Position_Command ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Damper_Position_Command ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Thermal_Power_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . - - brick:isTagOf , - , - , - , - . + a brick:Mixed_Air_Humidity_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Mixed-Air-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . a brick:Mixed_Air_Temperature_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Mixed-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Outside_Air_Dewpoint_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Outside_Air_Flow_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Outside_Air_Humidity_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Outdoor-Air-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Outside_Air_Temperature_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Outdoor-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Exhaust_Air_Flow_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Exhaust_Air_Humidity_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Relief-Air-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Exhaust_Air_Temperature_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Relief-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Return_Air_Flow_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Return_Air_Humidity_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Inlet-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Return_Air_Temperature_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Inlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Zone_Air_Temperature_Sensor ; - rdfs:label "Core_ZN-ZN-Zone-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Mixed_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Mixed-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Dewpoint_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Relief-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Inlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-Zone-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Mixed_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Mixed-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Dewpoint_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Relief-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Inlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-Zone-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Mixed_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Mixed-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Dewpoint_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Relief-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Inlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-Zone-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Mixed_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Mixed-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Dewpoint_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Relief-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Flow_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - ; + a brick:Discharge_Air_Flow_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Outlet-Node_System_Node_Mass_Flow_Rate" ; brick:hasUnit ; - brick:isPointOf . - - a brick:Return_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Inlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Temperature_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-Zone-Air-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - brick:isTagOf , - , - , - , - , - . - - a brick:Min_Position_Setpoint_Limit ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Diffuser-Zone-Air-Terminal-Minimum-Air-Flow-Fraction" ; - brick:hasTag , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Discharge_Fan, - brick:Supply_Fan ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Fan" ; - brick:hasPoint ; - brick:hasTag , - , - , - , - ; - brick:isPartOf . - - a brick:Mixed_Air_Humidity_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Mixed-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Outside_Air_Humidity_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Outdoor-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Exhaust_Air_Humidity_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Relief-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; - brick:hasUnit ; brick:isPointOf . - a brick:Return_Air_Humidity_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Inlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; + a brick:Discharge_Air_Humidity_Sensor ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Outlet-Node_System_Node_Relative_Humidity" ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Flow_Sensor, - brick:Supply_Air_Flow_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Outlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Discharge_Air_Temperature_Sensor, - brick:Supply_Air_Temperature_Sensor ; + a brick:Discharge_Air_Temperature_Sensor ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Outlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Cooling_Temperature_Setpoint ; rdfs:label "Core_ZN-ZN-Zone-Air-Node-Cooling-Setpoint" ; - brick:hasTag , - , - , - , - , - ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Zone_Air_Heating_Temperature_Setpoint ; + rdfs:label "Core_ZN-ZN-Zone-Air-Node-Heating-Setpoint" ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Humidity_Sensor ; rdfs:label "Core_ZN-ZN-Zone-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Zone_Air_Temperature_Sensor ; + rdfs:label "Core_ZN-ZN-Zone-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Min_Position_Setpoint_Limit ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Diffuser-Zone-Air-Terminal-Minimum-Air-Flow-Fraction" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Fan, - brick:Supply_Fan ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Fan" ; - brick:hasPoint ; - brick:hasTag , - , - , - , - ; - brick:isPartOf . + a brick:Damper_Position_Command ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Fan_Fan_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Energy_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . a brick:Mixed_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Mixed-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Mixed_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Mixed-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Dewpoint_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Outside_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Outside_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Outdoor-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Exhaust_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Exhaust_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Relief-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Exhaust_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Relief-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Return_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Return_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Inlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Flow_Sensor, - brick:Supply_Air_Flow_Sensor ; + a brick:Return_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Inlet-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Flow_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Outlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Temperature_Sensor, - brick:Supply_Air_Temperature_Sensor ; + a brick:Discharge_Air_Humidity_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Outlet-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Temperature_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Outlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Cooling_Temperature_Setpoint ; rdfs:label "Perimeter_ZN_1-ZN-Zone-Air-Node-Cooling-Setpoint" ; - brick:hasTag , - , - , - , - , - ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Zone_Air_Heating_Temperature_Setpoint ; + rdfs:label "Perimeter_ZN_1-ZN-Zone-Air-Node-Heating-Setpoint" ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_1-ZN-Zone-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Zone_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_1-ZN-Zone-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-HP-Htg-Coil-29-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-HP-Htg-Coil-29-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-1spd-DX-HP-Clg-Coil-29kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-1spd-DX-HP-Clg-Coil-29kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Min_Position_Setpoint_Limit ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Diffuser-Zone-Air-Terminal-Minimum-Air-Flow-Fraction" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Fan, - brick:Supply_Fan ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Fan" ; - brick:hasPoint ; - brick:hasTag , - , - , - , - ; - brick:isPartOf . + a brick:Damper_Position_Command ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Fan_Fan_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Energy_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . a brick:Mixed_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Mixed-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Mixed_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Mixed-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Dewpoint_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Outside_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Outside_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Outdoor-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Exhaust_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Exhaust_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Relief-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Exhaust_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Relief-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Return_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Return_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Inlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Flow_Sensor, - brick:Supply_Air_Flow_Sensor ; + a brick:Return_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Inlet-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Flow_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Outlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Temperature_Sensor, - brick:Supply_Air_Temperature_Sensor ; + a brick:Discharge_Air_Humidity_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Outlet-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Temperature_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Outlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Cooling_Temperature_Setpoint ; rdfs:label "Perimeter_ZN_2-ZN-Zone-Air-Node-Cooling-Setpoint" ; - brick:hasTag , - , - , - , - , - ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Zone_Air_Heating_Temperature_Setpoint ; + rdfs:label "Perimeter_ZN_2-ZN-Zone-Air-Node-Heating-Setpoint" ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_2-ZN-Zone-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Zone_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_2-ZN-Zone-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-HP-Htg-Coil-30-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-HP-Htg-Coil-30-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-1spd-DX-HP-Clg-Coil-30kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-1spd-DX-HP-Clg-Coil-30kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Min_Position_Setpoint_Limit ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Diffuser-Zone-Air-Terminal-Minimum-Air-Flow-Fraction" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Fan, - brick:Supply_Fan ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Fan" ; - brick:hasPoint ; - brick:hasTag , - , - , - , - ; - brick:isPartOf . + a brick:Damper_Position_Command ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Fan_Fan_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Energy_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . a brick:Mixed_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Mixed-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Mixed_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Mixed-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Dewpoint_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Outside_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Outside_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Outdoor-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Exhaust_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Exhaust_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Relief-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Exhaust_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Relief-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Return_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Return_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Inlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Flow_Sensor, - brick:Supply_Air_Flow_Sensor ; + a brick:Return_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Inlet-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Flow_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Outlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Temperature_Sensor, - brick:Supply_Air_Temperature_Sensor ; + a brick:Discharge_Air_Humidity_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Outlet-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Temperature_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Outlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Cooling_Temperature_Setpoint ; rdfs:label "Perimeter_ZN_3-ZN-Zone-Air-Node-Cooling-Setpoint" ; - brick:hasTag , - , - , - , - , - ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Zone_Air_Heating_Temperature_Setpoint ; + rdfs:label "Perimeter_ZN_3-ZN-Zone-Air-Node-Heating-Setpoint" ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_3-ZN-Zone-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Zone_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_3-ZN-Zone-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF_Heating_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER_Cooling_Coil_Total_Cooling_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Min_Position_Setpoint_Limit ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Diffuser-Zone-Air-Terminal-Minimum-Air-Flow-Fraction" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Fan, - brick:Supply_Fan ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Fan" ; - brick:hasPoint ; - brick:hasTag , - , - , - , - ; - brick:isPartOf . + a brick:Damper_Position_Command ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Diffuser-Zone-Air-Terminal-VAV-Damper-Position" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Electrical_Power_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Fan_Fan_Electricity_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Thermal_Power_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Gas-Backup-Htg-Coil_Heating_Coil_Air_Heating_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Energy_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Gas-Backup-Htg-Coil_Heating_Coil_NaturalGas_Rate" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Mixed-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . a brick:Mixed_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Mixed-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Mixed_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Mixed-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Dewpoint_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Dewpoint_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Outside_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Outside_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Outside_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Outdoor-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Exhaust_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Relief-Air-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Exhaust_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Relief-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . + a brick:Exhaust_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Relief-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Return_Air_Flow_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Inlet-Node_System_Node_Mass_Flow_Rate" ; + brick:hasUnit ; + brick:isPointOf . + a brick:Return_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Inlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Flow_Sensor, - brick:Supply_Air_Flow_Sensor ; + a brick:Return_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Inlet-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Flow_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Outlet-Node_System_Node_Mass_Flow_Rate" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Discharge_Air_Temperature_Sensor, - brick:Supply_Air_Temperature_Sensor ; + a brick:Discharge_Air_Humidity_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Outlet-Node_System_Node_Relative_Humidity" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Air_Temperature_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Outlet-Node_System_Node_Temperature" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Cooling_Temperature_Setpoint ; rdfs:label "Perimeter_ZN_4-ZN-Zone-Air-Node-Cooling-Setpoint" ; - brick:hasTag , - , - , - , - , - ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Zone_Air_Heating_Temperature_Setpoint ; + rdfs:label "Perimeter_ZN_4-ZN-Zone-Air-Node-Heating-Setpoint" ; brick:hasUnit ; brick:isPointOf . a brick:Zone_Air_Humidity_Sensor ; rdfs:label "Perimeter_ZN_4-ZN-Zone-Air-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - ; brick:hasUnit ; brick:isPointOf . - a brick:Building ; - rdfs:label "smallOffice" ; - brick:hasTag , - ; - brick:isLocationOf , - , - , - , - . + a brick:Zone_Air_Temperature_Sensor ; + rdfs:label "Perimeter_ZN_4-ZN-Zone-Air-Node_System_Node_Temperature" ; + brick:hasUnit ; + brick:isPointOf . + + a brick:Discharge_Fan ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-Fan" ; + brick:isPartOf . + + a brick:Discharge_Fan ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Fan" ; + brick:isPartOf . + + a brick:Discharge_Fan ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Fan" ; + brick:isPartOf . + + a brick:Discharge_Fan ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Fan" ; + brick:isPartOf . + + a brick:Discharge_Fan ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Fan" ; + brick:isPartOf . a brick:Heating_Coil ; rdfs:label "Core_ZN-ZN-HP-Htg-Coil-27-Clg-kBtu/hr-7.7HSPF" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; + brick:isPartOf . + + a brick:Cooling_Coil ; + rdfs:label "Core_ZN-ZN-PSZ-AC-1-1spd-DX-HP-Clg-Coil-27kBtu/hr-13.0SEER" ; brick:isPartOf . a brick:Heating_Coil ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Gas-Backup-Htg-Coil" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; brick:isPartOf . - a brick:Discharge_Air_Humidity_Sensor, - brick:Supply_Air_Humidity_Sensor ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-Supply-Outlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Heating_Temperature_Setpoint ; - rdfs:label "Core_ZN-ZN-Zone-Air-Node-Heating-Setpoint" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_1-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; + brick:isPartOf . + + a brick:Cooling_Coil ; + rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER" ; brick:isPartOf . a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Gas-Backup-Htg-Coil" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; brick:isPartOf . - a brick:Discharge_Air_Humidity_Sensor, - brick:Supply_Air_Humidity_Sensor ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Supply-Outlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Heating_Temperature_Setpoint ; - rdfs:label "Perimeter_ZN_1-ZN-Zone-Air-Node-Heating-Setpoint" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_2-ZN-HP-Htg-Coil-29-Clg-kBtu/hr-7.7HSPF" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; + brick:isPartOf . + + a brick:Cooling_Coil ; + rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-1spd-DX-HP-Clg-Coil-29kBtu/hr-13.0SEER" ; brick:isPartOf . a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Gas-Backup-Htg-Coil" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; brick:isPartOf . - a brick:Discharge_Air_Humidity_Sensor, - brick:Supply_Air_Humidity_Sensor ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Supply-Outlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Heating_Temperature_Setpoint ; - rdfs:label "Perimeter_ZN_2-ZN-Zone-Air-Node-Heating-Setpoint" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_3-ZN-HP-Htg-Coil-30-Clg-kBtu/hr-7.7HSPF" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; + brick:isPartOf . + + a brick:Cooling_Coil ; + rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-1spd-DX-HP-Clg-Coil-30kBtu/hr-13.0SEER" ; brick:isPartOf . a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Gas-Backup-Htg-Coil" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; brick:isPartOf . - a brick:Discharge_Air_Humidity_Sensor, - brick:Supply_Air_Humidity_Sensor ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Supply-Outlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Heating_Temperature_Setpoint ; - rdfs:label "Perimeter_ZN_3-ZN-Zone-Air-Node-Heating-Setpoint" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - a brick:Heating_Coil ; rdfs:label "Perimeter_ZN_4-ZN-HP-Htg-Coil-31-Clg-kBtu/hr-7.7HSPF" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; - brick:isPartOf . - - a brick:Heating_Coil ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Gas-Backup-Htg-Coil" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - ; brick:isPartOf . - a brick:Discharge_Air_Humidity_Sensor, - brick:Supply_Air_Humidity_Sensor ; - rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Supply-Outlet-Node_System_Node_Relative_Humidity" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:Zone_Air_Heating_Temperature_Setpoint ; - rdfs:label "Perimeter_ZN_4-ZN-Zone-Air-Node-Heating-Setpoint" ; - brick:hasTag , - , - , - , - , - , - ; - brick:hasUnit ; - brick:isPointOf . - - a brick:HVAC_Zone ; - rdfs:label "Core_ZN-ZN" ; - brick:hasPoint , - , - , - ; - brick:hasTag , - , - ; - brick:isFedBy ; - brick:isLocationOf . - - a brick:Cooling_Coil ; - rdfs:label "Core_ZN-ZN-PSZ-AC-1-1spd-DX-HP-Clg-Coil-27kBtu/hr-13.0SEER" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - ; - brick:isPartOf . - - a brick:HVAC_Zone ; - rdfs:label "Perimeter_ZN_1-ZN" ; - brick:hasPoint , - , - , - ; - brick:hasTag , - , - ; - brick:isFedBy ; - brick:isLocationOf . - - a brick:Cooling_Coil ; - rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - ; - brick:isPartOf . - - a brick:HVAC_Zone ; - rdfs:label "Perimeter_ZN_2-ZN" ; - brick:hasPoint , - , - , - ; - brick:hasTag , - , - ; - brick:isFedBy ; - brick:isLocationOf . - - a brick:Cooling_Coil ; - rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-1spd-DX-HP-Clg-Coil-29kBtu/hr-13.0SEER" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - ; - brick:isPartOf . - - a brick:HVAC_Zone ; - rdfs:label "Perimeter_ZN_3-ZN" ; - brick:hasPoint , - , - , - ; - brick:hasTag , - , - ; - brick:isFedBy ; - brick:isLocationOf . - - a brick:Cooling_Coil ; - rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-1spd-DX-HP-Clg-Coil-30kBtu/hr-13.0SEER" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - ; - brick:isPartOf . - - a brick:HVAC_Zone ; - rdfs:label "Perimeter_ZN_4-ZN" ; - brick:hasPoint , - , - , - ; - brick:hasTag , - , - ; - brick:isFedBy ; - brick:isLocationOf . - a brick:Cooling_Coil ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-1spd-DX-HP-Clg-Coil-31kBtu/hr-13.0SEER" ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - ; brick:isPartOf . - brick:isTagOf , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - . - - a brick:CAV, - brick:Constant_Air_Volume_Box ; + a brick:Heating_Coil ; + rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Gas-Backup-Htg-Coil" ; + brick:isPartOf . + + a brick:CAV ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Diffuser" ; - brick:feeds ; brick:hasLocation ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - , - , - ; brick:isFedBy . - a brick:CAV, - brick:Constant_Air_Volume_Box ; + a brick:CAV ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Diffuser" ; - brick:feeds ; brick:hasLocation ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - , - , - ; brick:isFedBy . - a brick:CAV, - brick:Constant_Air_Volume_Box ; + a brick:CAV ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Diffuser" ; - brick:feeds ; brick:hasLocation ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - , - , - ; brick:isFedBy . - a brick:CAV, - brick:Constant_Air_Volume_Box ; + a brick:CAV ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Diffuser" ; - brick:feeds ; brick:hasLocation ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - , - , - ; brick:isFedBy . - a brick:CAV, - brick:Constant_Air_Volume_Box ; + a brick:CAV ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Diffuser" ; - brick:feeds ; brick:hasLocation ; - brick:hasPoint , - ; - brick:hasTag , - , - , - , - , - , - , - ; brick:isFedBy . - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - a brick:AHU, - brick:Air_Handler_Unit, - brick:Air_Handling_Unit ; + a brick:HVAC_Zone ; + rdfs:label "Core_ZN-ZN" ; + brick:isFedBy . + + a brick:HVAC_Zone ; + rdfs:label "Perimeter_ZN_1-ZN" ; + brick:isFedBy . + + a brick:HVAC_Zone ; + rdfs:label "Perimeter_ZN_2-ZN" ; + brick:isFedBy . + + a brick:HVAC_Zone ; + rdfs:label "Perimeter_ZN_3-ZN" ; + brick:isFedBy . + + a brick:HVAC_Zone ; + rdfs:label "Perimeter_ZN_4-ZN" ; + brick:isFedBy . + + a brick:Building ; + rdfs:label "smallOffice" . + + a brick:AHU ; rdfs:label "Core_ZN-ZN-PSZ-AC-1-Unitary-HP" ; - brick:feeds ; - brick:hasLocation ; - brick:hasPart , - , - , - ; - brick:hasPoint , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - brick:hasTag , - , - , - , - , - , - . - - a brick:AHU, - brick:Air_Handler_Unit, - brick:Air_Handling_Unit ; + brick:hasLocation . + + a brick:AHU ; rdfs:label "Perimeter_ZN_1-ZN-PSZ-AC-2-Unitary-HP" ; - brick:feeds ; - brick:hasLocation ; - brick:hasPart , - , - , - ; - brick:hasPoint , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - brick:hasTag , - , - , - , - , - , - . - - a brick:AHU, - brick:Air_Handler_Unit, - brick:Air_Handling_Unit ; + brick:hasLocation . + + a brick:AHU ; rdfs:label "Perimeter_ZN_2-ZN-PSZ-AC-3-Unitary-HP" ; - brick:feeds ; - brick:hasLocation ; - brick:hasPart , - , - , - ; - brick:hasPoint , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - brick:hasTag , - , - , - , - , - , - . - - a brick:AHU, - brick:Air_Handler_Unit, - brick:Air_Handling_Unit ; + brick:hasLocation . + + a brick:AHU ; rdfs:label "Perimeter_ZN_3-ZN-PSZ-AC-4-Unitary-HP" ; - brick:feeds ; - brick:hasLocation ; - brick:hasPart , - , - , - ; - brick:hasPoint , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - brick:hasTag , - , - , - , - , - , - . - - a brick:AHU, - brick:Air_Handler_Unit, - brick:Air_Handling_Unit ; + brick:hasLocation . + + a brick:AHU ; rdfs:label "Perimeter_ZN_4-ZN-PSZ-AC-5-Unitary-HP" ; - brick:feeds ; - brick:hasLocation ; - brick:hasPart , - , - , - ; - brick:hasPoint , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - ; - brick:hasTag , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . - - brick:isTagOf , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - , - . + brick:hasLocation . diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index b735f81bb..62a566c51 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -1,6 +1,5 @@ -import pyshacl # type: ignore import pytest -from rdflib import Graph, Namespace, URIRef +from rdflib import Graph, Literal, Namespace, URIRef from buildingmotif import BuildingMOTIF from buildingmotif.dataclasses import Model, ShapeCollection @@ -12,6 +11,7 @@ get_template_parts_from_shape, replace_nodes, rewrite_shape_graph, + shacl_validate, skip_uri, ) @@ -129,7 +129,7 @@ def test_get_parameters(): assert get_parameters(body) == {"name", "1", "2", "3", "4"} -def test_inline_sh_nodes(): +def test_inline_sh_nodes(shacl_engine): shape_g = Graph() shape_g.parse( data="""@prefix sh: . @@ -160,21 +160,24 @@ def test_inline_sh_nodes(): . """ ) - # should not raise an exception - pyshacl.validate(shape_g) + # should pass + valid, _, report = shacl_validate(shape_g) + assert valid, report shape1_cbd = shape_g.cbd(URIRef("urn:ex/shape1")) assert len(shape1_cbd) == 3 shape_g = rewrite_shape_graph(shape_g) - # should not raise an exception - pyshacl.validate(shape_g) + # should pass + valid, _, report = shacl_validate(shape_g) + assert valid, report shape1_cbd = shape_g.cbd(URIRef("urn:ex/shape1")) assert len(shape1_cbd) == 8 -def test_inline_sh_and(bm: BuildingMOTIF): +def test_inline_sh_and(bm: BuildingMOTIF, shacl_engine): + bm.shacl_engine = shacl_engine sg = Graph() sg.parse( data=PREAMBLE @@ -211,24 +214,42 @@ def test_inline_sh_and(bm: BuildingMOTIF): ctx = model.validate([sc]) assert not ctx.valid - assert ( - "Value class is not in classes (brick:Class2, brick:Class3)" - in ctx.report_string - or "Value class is not in classes (brick:Class3, brick:Class2)" - in ctx.report_string - or "Value class is not in classes (, )" - in ctx.report_string - or "Value class is not in classes (, )" - in ctx.report_string - ), ctx.report_string - assert ( - "Less than 1 values on ->brick:relationship" in ctx.report_string - or "Less than 1 values on ->" - in ctx.report_string - ) - -def test_inline_sh_node(bm: BuildingMOTIF): + if shacl_engine == "pyshacl": + assert ( + "Value class is not in classes (brick:Class2, brick:Class3)" + in ctx.report_string + or "Value class is not in classes (brick:Class3, brick:Class2)" + in ctx.report_string + or "Value class is not in classes (, )" + in ctx.report_string + or "Value class is not in classes (, )" + in ctx.report_string + ), ctx.report_string + assert ( + "Less than 1 values on ->brick:relationship" + in ctx.report_string + or "Less than 1 values on ->" + in ctx.report_string + ) + elif shacl_engine == "topquadrant": + assert (None, SH.resultPath, BRICK.relationship) in ctx.report + assert ( + None, + SH.resultMessage, + Literal("Property needs to have at least 1 value"), + ) in ctx.report + + assert ( + None, + SH.resultMessage, + Literal("Value must be an instance of brick:Class3"), + ) in ctx.report + assert (None, SH.sourceShape, URIRef("urn:model#shape1")) in ctx.report + + +def test_inline_sh_node(bm: BuildingMOTIF, shacl_engine): + bm.shacl_engine = shacl_engine sg = Graph() sg.parse( data=PREAMBLE @@ -265,21 +286,37 @@ def test_inline_sh_node(bm: BuildingMOTIF): ctx = model.validate([sc]) assert not ctx.valid, ctx.report_string - assert ( - "Value class is not in classes (brick:Class2, brick:Class3)" - in ctx.report_string - or "Value class is not in classes (brick:Class3, brick:Class2)" - in ctx.report_string - or "Value class is not in classes (, )" - in ctx.report_string - or "Value class is not in classes (, )" - in ctx.report_string - ) - assert ( - "Less than 1 values on ->brick:relationship" in ctx.report_string - or "Less than 1 values on ->" - in ctx.report_string - ) + if shacl_engine == "pyshacl": + assert ( + "Value class is not in classes (brick:Class2, brick:Class3)" + in ctx.report_string + or "Value class is not in classes (brick:Class3, brick:Class2)" + in ctx.report_string + or "Value class is not in classes (, )" + in ctx.report_string + or "Value class is not in classes (, )" + in ctx.report_string + ) + assert ( + "Less than 1 values on ->brick:relationship" + in ctx.report_string + or "Less than 1 values on ->" + in ctx.report_string + ) + elif shacl_engine == "topquadrant": + assert (None, SH.resultPath, BRICK.relationship) in ctx.report + assert ( + None, + SH.resultMessage, + Literal("Property needs to have at least 1 value"), + ) in ctx.report + + assert ( + None, + SH.resultMessage, + Literal("Value must be an instance of brick:Class3"), + ) in ctx.report + assert (None, SH.sourceShape, URIRef("urn:model#shape1")) in ctx.report def test_param_name():