#1349 result formatting

This commit is contained in:
Thomas Krijnen
2021-02-28 09:31:21 +01:00
parent 23ad1a8005
commit b5f58dc113
+82 -11
View File
@@ -10,6 +10,22 @@ def error(msg):
raise exception(msg) raise exception(msg)
class facet_evaluation:
"""
The evaluation of a facet with data from IFC. Converts to bool and has a human readable string format.
"""
def __init__(self, success, str):
self.success = success
self.str = str
def __bool__(self):
return self.success
def __str__(self):
return self.str
class meta_facet(type): class meta_facet(type):
""" """
A metaclass for automatically registering facets in a map to be instantiated based on XML tagnames. A metaclass for automatically registering facets in a map to be instantiated based on XML tagnames.
@@ -41,17 +57,30 @@ class facet(metaclass=meta_facet):
else: else:
return v.firstChild.nodeValue.strip() return v.firstChild.nodeValue.strip()
def __iter__(self):
for k in self.parameters:
yield k, getattr(self, k)
def __str__(self):
return self.message % dict(list(self))
class entity(facet): class entity(facet):
""" """
The IDS entity facet currently *with* inheritance The IDS entity facet currently *with* inheritance
""" """
parameters = ["name"]
message = "an entity name '%(name)s'"
def __call__(self, inst, logger): def __call__(self, inst, logger):
logger.debug("Testing %s == %s", inst.is_a(), self.name) logger.debug("Testing %s == %s", inst.is_a(), self.name)
# @nb with inheritance # @nb with inheritance
# return inst.is_a() == self.name # return inst.is_a() == self.name
return inst.is_a(self.name) return facet_evaluation(
inst.is_a(self.name),
self.message % {'name':inst.is_a()}
)
class classification(facet): class classification(facet):
@@ -59,6 +88,9 @@ class classification(facet):
The IDS classification facet by traversing the HasAssociations inverse attribute The IDS classification facet by traversing the HasAssociations inverse attribute
""" """
parameters = ["system", "value"]
message = "a classification reference to '%(value)s' from '%(system)s'"
def __call__(self, inst, logger): def __call__(self, inst, logger):
refs = [] refs = []
for association in inst.HasAssociations: for association in inst.HasAssociations:
@@ -66,7 +98,12 @@ class classification(facet):
cref = association.RelatingClassification cref = association.RelatingClassification
refs.append((cref.ReferencedSource, cref.Name)) refs.append((cref.ReferencedSource, cref.Name))
return (self.system, self.value) in refs return facet_evaluation(
(self.system, self.value) in refs,
# @todo
''
)
class property(facet): class property(facet):
@@ -74,11 +111,33 @@ class property(facet):
The IDS property facet implenented using `ifcopenshell.util.element` The IDS property facet implenented using `ifcopenshell.util.element`
""" """
parameters = ["property", "propertyset", "value"]
message = "a property '%(property)s' in '%(propertyset)s' with value '%(value)s'"
def __call__(self, inst, logger): def __call__(self, inst, logger):
props = ifcopenshell.util.element.get_psets(inst) props = ifcopenshell.util.element.get_psets(inst)
val = props.get(self.propertyset, {}).get(self.property) pset = props.get(self.propertyset)
val = pset.get(self.property) if pset else None
logger.debug("Testing %s == %s", val, self.value) logger.debug("Testing %s == %s", val, self.value)
return val == self.value
di = {
'property': self.property,
'propertyset': self.propertyset,
'value': val
}
if val is not None:
msg = self.message % di
else:
if pset:
msg = "a set '%(propertyset)s', but no property '%(property)'" % di
else:
msg = "no set '%(propertyset)s'" % di
return facet_evaluation(
val == self.value,
msg
)
class boolean_logic: class boolean_logic:
@@ -90,7 +149,15 @@ class boolean_logic:
self.terms = terms self.terms = terms
def __call__(self, *args): def __call__(self, *args):
return self.fold(t(*args) for t in self.terms) eval = [t(*args) for t in self.terms]
join = [" and ", " or "][self.fold == any]
return facet_evaluation(
self.fold(eval),
join.join(map(str, eval))
)
def __str__(self):
return [" and ", " or "][self.fold == any].join(map(str, self.terms))
class boolean_and(boolean_logic): class boolean_and(boolean_logic):
@@ -117,7 +184,7 @@ class restriction:
return other in self.options return other in self.options
def __repr__(self): def __repr__(self):
return "|".join(self.options) return " or ".join(self.options)
class specification: class specification:
@@ -144,10 +211,14 @@ class specification:
def __call__(self, inst, logger): def __call__(self, inst, logger):
if self.applicabiliy(inst, logger): if self.applicabiliy(inst, logger):
if self.requirements(inst, logger): valid = self.requirements(inst, logger)
logger.info("%s is compliant", inst) if valid:
logger.info(str(self) + "\n%s has" % inst + " " + str(valid) + " so is compliant")
else: else:
logger.error("%s not compliant", inst) logger.error(str(self) + "\n%s has" % inst + " " + str(valid) + " so is not compliant")
def __str__(self):
return "Given an instance with %(applicabiliy)s\nWe expect %(requirements)s" % self.__dict__
class ids: class ids:
@@ -167,8 +238,8 @@ class ids:
] ]
def validate(self, ifc_file, logger): def validate(self, ifc_file, logger):
for elem in ifc_file.by_type("IfcObject"): for spec in self.specifications:
for spec in self.specifications: for elem in ifc_file.by_type("IfcObject"):
spec(elem, logger) spec(elem, logger)