mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
Support JSON output for IDS results
This commit is contained in:
@@ -30,6 +30,12 @@ parser.add_argument("ifc", type=str, help="Path to an IFC")
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-r", "--reporter", type=str, help="The reporting method to view audit results", default="Console"
|
"-r", "--reporter", type=str, help="The reporting method to view audit results", default="Console"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--no-color", help="Disable colour output supported by Console reporting", action="store_true"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o", "--output", help="Output file supported by Json reporting"
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
@@ -40,4 +46,15 @@ start = time.time()
|
|||||||
specs.validate(ifc)
|
specs.validate(ifc)
|
||||||
print("Finished validating:", time.time() - start)
|
print("Finished validating:", time.time() - start)
|
||||||
start = time.time()
|
start = time.time()
|
||||||
reporter.Console(specs).report()
|
|
||||||
|
if args.reporter == "Console":
|
||||||
|
engine = reporter.Console(specs, use_colour=not args.no_color)
|
||||||
|
elif args.reporter == "Json":
|
||||||
|
engine = reporter.Json(specs)
|
||||||
|
|
||||||
|
engine.report()
|
||||||
|
|
||||||
|
if args.output:
|
||||||
|
engine.to_file(args.output)
|
||||||
|
else:
|
||||||
|
print(engine.to_string())
|
||||||
|
|||||||
@@ -19,15 +19,25 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import numpy as np
|
|
||||||
import ifcopenshell.util.placement
|
|
||||||
from bcf.v2.bcfxml import BcfXml
|
|
||||||
from bcf.v2 import data as bcf
|
|
||||||
|
|
||||||
|
|
||||||
class Console:
|
class Reporter:
|
||||||
def __init__(self, ids, use_colour=True):
|
def __init__(self, ids):
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
|
|
||||||
|
def report(self, ids):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def to_string():
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def write(filepath):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Console(Reporter):
|
||||||
|
def __init__(self, ids, use_colour=True):
|
||||||
|
super().__init__(ids)
|
||||||
self.use_colour = use_colour
|
self.use_colour = use_colour
|
||||||
self.colours = {
|
self.colours = {
|
||||||
"red": "\033[1;31m",
|
"red": "\033[1;31m",
|
||||||
@@ -77,7 +87,6 @@ class Console:
|
|||||||
for applicability in specification.applicability:
|
for applicability in specification.applicability:
|
||||||
print(" " * 8 + applicability.to_string("applicability"))
|
print(" " * 8 + applicability.to_string("applicability"))
|
||||||
|
|
||||||
|
|
||||||
if not total and specification.status is False:
|
if not total and specification.status is False:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -99,7 +108,7 @@ class Console:
|
|||||||
|
|
||||||
def report_reason(self, reason, element):
|
def report_reason(self, reason, element):
|
||||||
is_bold = False
|
is_bold = False
|
||||||
for substring in reason.split("\""):
|
for substring in reason.split('"'):
|
||||||
if is_bold:
|
if is_bold:
|
||||||
self.set_style("purple")
|
self.set_style("purple")
|
||||||
else:
|
else:
|
||||||
@@ -115,76 +124,52 @@ class Console:
|
|||||||
sys.stdout.write("".join([self.colours[c] for c in colours]))
|
sys.stdout.write("".join([self.colours[c] for c in colours]))
|
||||||
|
|
||||||
|
|
||||||
class JsonReporter:
|
class Json(Reporter):
|
||||||
def __init__(self, specifications):
|
def __init__(self, ids):
|
||||||
self.specifications = specifications
|
super().__init__(ids)
|
||||||
self.results = []
|
self.results = {}
|
||||||
|
|
||||||
def report(self):
|
def report(self):
|
||||||
for specification in self.specifications:
|
self.results["title"] = self.ids.info.get("title", "Untitled IDS")
|
||||||
self.results.append(self.report_specification(specification))
|
self.results["specifications"] = []
|
||||||
|
for specification in self.ids.specifications:
|
||||||
|
self.results["specifications"].append(self.report_specification(specification))
|
||||||
return self.results
|
return self.results
|
||||||
|
|
||||||
def report_specification(self, specification):
|
def report_specification(self, specification):
|
||||||
return {"status": specification.status}
|
requirements = []
|
||||||
|
for requirement in specification.requirements:
|
||||||
|
requirements.append(
|
||||||
|
{
|
||||||
|
"description": requirement.to_string("requirement"),
|
||||||
|
"success": not requirement.failed_entities,
|
||||||
|
"failed_entities": [
|
||||||
|
{"reason": requirement.failed_reasons[i], "element": str(e)}
|
||||||
|
for i, e in enumerate(requirement.failed_entities[0:10])
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
total = len(specification.applicable_entities)
|
||||||
|
return {
|
||||||
|
"name": specification.name,
|
||||||
|
"status": specification.status,
|
||||||
|
"total_successes": total - len(specification.failed_entities),
|
||||||
|
"total": total,
|
||||||
|
"required": specification.minOccurs != 0,
|
||||||
|
"requirements": requirements,
|
||||||
|
}
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
import json
|
||||||
|
|
||||||
class SimpleHandler(logging.StreamHandler):
|
return json.dumps(self.results)
|
||||||
"""Logging handler listing all cases in python list."""
|
|
||||||
|
|
||||||
def __init__(self, report_valid=False):
|
def to_file(self, filepath):
|
||||||
"""Logging handler listing all cases in python list.
|
import json
|
||||||
|
|
||||||
:param report_valid: True if you want to list all the compliant cases as well, defaults to False
|
with open(filepath, "w") as outfile:
|
||||||
:type report_valid: bool, optional
|
return json.dump(self.results, outfile)
|
||||||
"""
|
|
||||||
logging.StreamHandler.__init__(self)
|
|
||||||
self.statements = []
|
|
||||||
if report_valid:
|
|
||||||
self.setLevel(logging.DEBUG)
|
|
||||||
else:
|
|
||||||
self.setLevel(logging.ERROR)
|
|
||||||
|
|
||||||
def emit(self, mymsg):
|
|
||||||
"""Triggered on each use of logging with the Simple handler enabled.
|
|
||||||
|
|
||||||
:param log_content: default logger message
|
|
||||||
:type log_content: string|dict
|
|
||||||
"""
|
|
||||||
self.statements.append(mymsg.msg)
|
|
||||||
|
|
||||||
|
|
||||||
class CsvHandler(logging.StreamHandler):
|
|
||||||
"""Logging handler listing all cases in csv file."""
|
|
||||||
|
|
||||||
def __init__(self, filepath="./Report.csv", report_valid=False):
|
|
||||||
"""Logging handler listing all cases in csv file.
|
|
||||||
|
|
||||||
:param report_valid: True if you want to list all the compliant cases as well, defaults to False
|
|
||||||
:type report_valid: bool, optional
|
|
||||||
"""
|
|
||||||
import csv
|
|
||||||
|
|
||||||
logging.StreamHandler.__init__(self)
|
|
||||||
if report_valid:
|
|
||||||
self.setLevel(logging.INFO)
|
|
||||||
else:
|
|
||||||
self.setLevel(logging.ERROR)
|
|
||||||
self.file = open(filepath, "w", encoding="UTF8", newline="")
|
|
||||||
self.csvwriter = csv.writer(self.file)
|
|
||||||
self.csvwriter.writerow(["guid", "result", "sentence"]) # header
|
|
||||||
|
|
||||||
def emit(self, mymsg):
|
|
||||||
"""Triggered on each use of logging with the Simple handler enabled.
|
|
||||||
|
|
||||||
:param log_content: default logger message
|
|
||||||
:type log_content: string|dict
|
|
||||||
"""
|
|
||||||
# BUG bytes-like object is required, not 'str'
|
|
||||||
self.csvwriter.writerow(mymsg.msg)
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
self.file.close()
|
|
||||||
|
|
||||||
|
|
||||||
class BcfHandler(logging.StreamHandler):
|
class BcfHandler(logging.StreamHandler):
|
||||||
@@ -212,6 +197,10 @@ class BcfHandler(logging.StreamHandler):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, project_name="IDS Project", author="your@email.com", filepath=None, report_valid=False):
|
def __init__(self, project_name="IDS Project", author="your@email.com", filepath=None, report_valid=False):
|
||||||
|
import numpy as np
|
||||||
|
import ifcopenshell.util.placement
|
||||||
|
from bcf.v2.bcfxml import BcfXml
|
||||||
|
from bcf.v2 import data as bcf
|
||||||
|
|
||||||
logging.StreamHandler.__init__(self)
|
logging.StreamHandler.__init__(self)
|
||||||
if report_valid:
|
if report_valid:
|
||||||
|
|||||||
Reference in New Issue
Block a user