mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
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:
@@ -52,12 +52,18 @@ class facet(metaclass=meta_facet):
|
||||
self.node = node
|
||||
|
||||
def __getattr__(self, k):
|
||||
v = self.node.getElementsByTagName(k)[0]
|
||||
elems = [n for n in v.childNodes if n.nodeType == n.ELEMENT_NODE]
|
||||
if elems:
|
||||
return restriction(elems[0])
|
||||
try:
|
||||
v = self.node.getElementsByTagName(k)[0]
|
||||
except IndexError:
|
||||
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:
|
||||
return v.firstChild.nodeValue.strip()
|
||||
return None
|
||||
|
||||
def __iter__(self):
|
||||
for k in self.parameters:
|
||||
@@ -76,17 +82,18 @@ class entity(facet):
|
||||
The IDS entity facet currently *with* inheritance
|
||||
"""
|
||||
|
||||
parameters = ["name"]
|
||||
message = "an entity name '%(name)s'"
|
||||
parameters = ["name", "predefinedtype"]
|
||||
|
||||
# @todo predefinedtype
|
||||
|
||||
def __call__(self, inst, logger):
|
||||
logger.debug("Testing %s == %s", inst.is_a(), self.name)
|
||||
# @nb with inheritance
|
||||
# return inst.is_a() == self.name
|
||||
return facet_evaluation(inst.is_a(self.name), self.message % {"name": inst.is_a()})
|
||||
|
||||
if self.predefinedtype and hasattr(inst, "PredefinedType"):
|
||||
# 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):
|
||||
"""
|
||||
@@ -124,7 +131,7 @@ class property(facet):
|
||||
props = ifcopenshell.util.element.get_psets(inst)
|
||||
pset = props.get(self.propertyset)
|
||||
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 = {
|
||||
"name": self.name,
|
||||
@@ -136,7 +143,7 @@ class property(facet):
|
||||
msg = self.message % di
|
||||
else:
|
||||
if pset:
|
||||
msg = "a set '%(propertyset)s', but no property '%(name)'" % di
|
||||
msg = "a set '%(propertyset)s', but no property '%(name)s'" % di
|
||||
else:
|
||||
msg = "no set '%(propertyset)s'" % di
|
||||
|
||||
@@ -161,7 +168,6 @@ class material(facet):
|
||||
elif rel.RelatingMaterial.is_a() == "IfcMaterial":
|
||||
names.append(rel.RelatingMaterial.Name)
|
||||
|
||||
|
||||
return facet_evaluation(
|
||||
0,
|
||||
# @todo
|
||||
@@ -218,8 +224,7 @@ class restriction:
|
||||
elif n.nodeType == n.ELEMENT_NODE and n.tagName.endswith("pattern"):
|
||||
self.options.append(n.getAttribute("value"))
|
||||
self.type = "pattern"
|
||||
|
||||
# "Given an instance with %(applicabiliy)s\nWe expect %(requirements)s" % self.__dict__
|
||||
|
||||
def __eq__(self, other):
|
||||
return other in self.options
|
||||
|
||||
@@ -253,19 +258,19 @@ class specification:
|
||||
phrases[0].tagName == "applicability" or error("expected <applicability>")
|
||||
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):
|
||||
if self.applicabiliy(inst, logger):
|
||||
if self.applicability(inst, logger):
|
||||
valid = self.requirements(inst, logger)
|
||||
|
||||
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:
|
||||
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):
|
||||
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:
|
||||
@@ -286,7 +291,7 @@ class ids:
|
||||
for spec in self.specifications:
|
||||
for elem in ifc_file.by_type("IfcObject"):
|
||||
spec(elem, logger)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys, os
|
||||
import logging
|
||||
@@ -300,4 +305,7 @@ if __name__ == "__main__":
|
||||
|
||||
ids_file = ids(sys.argv[1])
|
||||
ifc_file = ifcopenshell.open(sys.argv[2])
|
||||
|
||||
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))
|
||||
Reference in New Issue
Block a user