IDS Add PredefinedType support (#1447)

* fixed typos

changed all 'applicabiliy' to 'applicability'

* added boolean restriction

* Add PredefinedType support

* replace f-string with %

* skip PredefinedType if not IFC4

* code formatting

* check PredefinedType if exists not based on schema

* narrow try-except

* remove debug data
This commit is contained in:
ArturTomczak
2021-05-01 09:09:35 +02:00
committed by GitHub
parent be87b17909
commit 037261afb9
+29 -21
View File
@@ -52,12 +52,18 @@ class facet(metaclass=meta_facet):
self.node = node self.node = node
def __getattr__(self, k): def __getattr__(self, k):
v = self.node.getElementsByTagName(k)[0] try:
elems = [n for n in v.childNodes if n.nodeType == n.ELEMENT_NODE] v = self.node.getElementsByTagName(k)[0]
if elems: except IndexError:
return restriction(elems[0]) v = None
if v:
elems = [n for n in v.childNodes if n.nodeType == n.ELEMENT_NODE]
if elems:
return restriction(elems[0])
else:
return v.firstChild.nodeValue.strip()
else: else:
return v.firstChild.nodeValue.strip() return None
def __iter__(self): def __iter__(self):
for k in self.parameters: for k in self.parameters:
@@ -76,16 +82,17 @@ class entity(facet):
The IDS entity facet currently *with* inheritance The IDS entity facet currently *with* inheritance
""" """
parameters = ["name"] parameters = ["name", "predefinedtype"]
message = "an entity name '%(name)s'"
# @todo predefinedtype
def __call__(self, inst, logger): def __call__(self, inst, logger):
logger.debug("Testing %s == %s", inst.is_a(), self.name)
# @nb with inheritance # @nb with inheritance
# return inst.is_a() == self.name if self.predefinedtype and hasattr(inst, "PredefinedType"):
return facet_evaluation(inst.is_a(self.name), self.message % {"name": inst.is_a()}) # logger.debug("Testing if entity predefinedtype '%s' == '%s'", inst.PredefinedType, self.predefinedtype)
self.message = "an entity name '%(name)s' of predefined type '%(predefinedtype)s'"
return facet_evaluation(inst.is_a(self.name) and inst.PredefinedType == self.predefinedtype, self.message % {"name": inst.is_a(), "predefinedtype": inst.PredefinedType})
else:
self.message = "an entity name '%(name)s'"
return facet_evaluation(inst.is_a(self.name), self.message % {"name": inst.is_a()})
class classification(facet): class classification(facet):
@@ -124,7 +131,7 @@ class property(facet):
props = ifcopenshell.util.element.get_psets(inst) props = ifcopenshell.util.element.get_psets(inst)
pset = props.get(self.propertyset) pset = props.get(self.propertyset)
val = pset.get(self.name) if pset else None val = pset.get(self.name) if pset else None
logger.debug("Testing %s == %s", val, self.value) logger.debug("Testing if property %s == %s", val, self.value)
di = { di = {
"name": self.name, "name": self.name,
@@ -136,7 +143,7 @@ class property(facet):
msg = self.message % di msg = self.message % di
else: else:
if pset: if pset:
msg = "a set '%(propertyset)s', but no property '%(name)'" % di msg = "a set '%(propertyset)s', but no property '%(name)s'" % di
else: else:
msg = "no set '%(propertyset)s'" % di msg = "no set '%(propertyset)s'" % di
@@ -161,7 +168,6 @@ class material(facet):
elif rel.RelatingMaterial.is_a() == "IfcMaterial": elif rel.RelatingMaterial.is_a() == "IfcMaterial":
names.append(rel.RelatingMaterial.Name) names.append(rel.RelatingMaterial.Name)
return facet_evaluation( return facet_evaluation(
0, 0,
# @todo # @todo
@@ -219,7 +225,6 @@ class restriction:
self.options.append(n.getAttribute("value")) self.options.append(n.getAttribute("value"))
self.type = "pattern" self.type = "pattern"
# "Given an instance with %(applicabiliy)s\nWe expect %(requirements)s" % self.__dict__
def __eq__(self, other): def __eq__(self, other):
return other in self.options return other in self.options
@@ -253,19 +258,19 @@ class specification:
phrases[0].tagName == "applicability" or error("expected <applicability>") phrases[0].tagName == "applicability" or error("expected <applicability>")
phrases[1].tagName == "requirements" or error("expected <requirements>") phrases[1].tagName == "requirements" or error("expected <requirements>")
self.applicabiliy, self.requirements = (boolean_and(parse_rules(phrase)) for phrase in phrases) self.applicability, self.requirements = (boolean_and(parse_rules(phrase)) for phrase in phrases)
def __call__(self, inst, logger): def __call__(self, inst, logger):
if self.applicabiliy(inst, logger): if self.applicability(inst, logger):
valid = self.requirements(inst, logger) valid = self.requirements(inst, logger)
if valid: if valid:
logger.info({'guid':inst.GlobalId, 'result':valid.success,'sentence':str(self) + "\n%s has" % inst + " " + str(valid) + " so is compliant"}) logger.info({'guid':inst.GlobalId, 'result':valid.success,'sentence':str(self) + "\n'" + inst.Name + "' (id:" + inst.GlobalId + ") has " + str(valid) + " so is compliant"})
else: else:
logger.error({'guid':inst.GlobalId, 'result':valid.success, 'sentence':str(self) + "\n%s has" % inst + " " + str(valid) + " so is not compliant"}) logger.error({'guid':inst.GlobalId, 'result':valid.success, 'sentence':str(self) + "\n'" + inst.Name + "' (id:" + inst.GlobalId + ") has " + str(valid) + " so is not compliant"})
def __str__(self): def __str__(self):
return "Given an instance with %(applicabiliy)s\nWe expect %(requirements)s" % self.__dict__ return "Given an instance with %(applicability)s\nWe expect %(requirements)s" % self.__dict__
class ids: class ids:
@@ -300,4 +305,7 @@ if __name__ == "__main__":
ids_file = ids(sys.argv[1]) ids_file = ids(sys.argv[1])
ifc_file = ifcopenshell.open(sys.argv[2]) ifc_file = ifcopenshell.open(sys.argv[2])
ids_file.validate(ifc_file, logger) ids_file.validate(ifc_file, logger)
print("Validated %s IDS requirements on %s IFC elements. Results saved to %s" % (len(ids_file.specifications[0].requirements.terms), len(ifc_file.by_type('IfcProduct')), filename))