diff --git a/mlx/reqif_export.py b/mlx/reqif_export.py new file mode 100644 index 00000000..ae44d642 --- /dev/null +++ b/mlx/reqif_export.py @@ -0,0 +1,90 @@ +from reqif_pyxb.ReqIF import * +import pyxb.binding.datatypes as datatypes +import hashlib + +requirement_object_type = None + +def reqif_document_setup(): + global requirement_object_type + # Construct the header + reqif_doc = REQ_IF( + THE_HEADER=pyxb.BIND(), + CORE_CONTENT=pyxb.BIND(), + TOOL_EXTENSIONS=pyxb.BIND(), + ) + reqif_doc.THE_HEADER.REQ_IF_HEADER=REQ_IF_HEADER() + + content = REQ_IF_CONTENT() + + datatype_string = DATATYPE_DEFINITION_STRING(LONG_NAME="string") + datatype_int = DATATYPE_DEFINITION_INTEGER(LONG_NAME="integer", MIN=0, MAX=65535) + content.add_datatype(datatype_string) + + # The specification types + text_attribute = ATTRIBUTE_DEFINITION_STRING(LONG_NAME="Text", datatype=datatype_string) + caption_attribute = ATTRIBUTE_DEFINITION_STRING(LONG_NAME="Caption", datatype=datatype_string) + content_hash_attribute = ATTRIBUTE_DEFINITION_STRING(LONG_NAME="Content hash", datatype=datatype_string) + document_name_attribute = ATTRIBUTE_DEFINITION_STRING(LONG_NAME="Document", datatype=datatype_string) + line_number_attribute = ATTRIBUTE_DEFINITION_INTEGER(LONG_NAME="Line number", datatype=datatype_int) + requirement_object_type = SPEC_OBJECT_TYPE(LONG_NAME= "Requirement") + requirement_object_type.add_attribute(text_attribute) + requirement_object_type.add_attribute(caption_attribute) + requirement_object_type.add_attribute(content_hash_attribute) + requirement_object_type.add_attribute(document_name_attribute) + requirement_object_type.add_attribute(line_number_attribute) + + specification_type = SPECIFICATION_TYPE(LONG_NAME="doc_type") + + # reqif_doc.CORE_CONTENT.REQ_IF_CONTENT.SPEC_TYPES = pyxb.BIND() + + content.add_spectype(requirement_object_type) + content.add_spectype(specification_type) + + + spec = SPECIFICATION(spectype=specification_type, LONG_NAME="SW specification") + content.add_specification(spec) + + reqif_doc.CORE_CONTENT.REQ_IF_CONTENT = content + + # print(reqif_doc.CORE_CONTENT.REQ_IF_CONTENT.SPEC_TYPES) + reqif_doc.TOOL_EXTENSIONS.REQ_IF_TOOL_EXTENSION.append(REQ_IF_TOOL_EXTENSION()) + return reqif_doc + + +def add_relation(reqif_doc, relation): + content = reqif_doc.CORE_CONTENT.REQ_IF_CONTENT + content.add_spectype(SPEC_RELATION_TYPE(LONG_NAME=relation)) + print(relation) + +def add_requirement(reqif_doc, item): + content = reqif_doc.CORE_CONTENT.REQ_IF_CONTENT + specification = content.SPECIFICATIONS + + if item.content: + content_hash = hashlib.md5(item.content.encode('utf-8')).hexdigest() + else: + content_hash = "0" + + # The actual requirements + requirement = SPEC_OBJECT(IDENTIFIER=item.id, LONG_NAME=item.get_name(), spectype=requirement_object_type) + requirement.set_value("Text", item.content if item.content else '-') + requirement.set_value("Caption", item.caption if item.caption else '-') + requirement.set_value("Content hash", content_hash) + requirement.set_value("Line number", item.lineno if item.lineno else 0) + requirement.set_value("Document", item.docname if item.docname else '-') + content.add_specobject(requirement) + specification.SPECIFICATION[0].add_spec_hierarchy(SPEC_HIERARCHY(spec_object=requirement)) + + for relation in item.iter_relations(): + tgts = item.iter_targets(relation) + for target in tgts: + content.add_spec_relation_by_ID(item.id, target, relation) + +def export_xml(reqif_doc, outfile): + print(outfile) + with open(outfile, 'w') as out: + try: + xml_content = reqif_doc.toxml() + print(xml_content, file=out) + except Exception as e: + print(e.details()) diff --git a/mlx/traceability.py b/mlx/traceability.py index 56815d93..4741752e 100644 --- a/mlx/traceability.py +++ b/mlx/traceability.py @@ -196,6 +196,7 @@ def perform_consistency_check(app, doctree): if app.config.traceability_json_export_path: fname = app.config.traceability_json_export_path env.traceability_collection.export(fname) + env.traceability_collection.export_reqif(fname + ".reqif") if app.config.traceability_hyperlink_colors: app.add_stylesheet('hyperlink_colors.css') diff --git a/mlx/traceable_collection.py b/mlx/traceable_collection.py index 26b1ea3b..2c1302b8 100644 --- a/mlx/traceable_collection.py +++ b/mlx/traceable_collection.py @@ -8,6 +8,7 @@ from mlx.traceability_exception import MultipleTraceabilityExceptions, TraceabilityException from mlx.traceable_item import TraceableItem +from mlx.reqif_export import * class TraceableCollection: @@ -180,6 +181,22 @@ def export(self, fname): data.append(item.to_dict()) json.dump(data, outfile, indent=4, sort_keys=True) + def export_reqif(self, fname): + ''' + Exports collection content. The target location of the json file gets created if it doesn't exist yet. + + Args: + fname (str): Path to the json file to export + ''' + Path(fname).parent.mkdir(parents=True, exist_ok=True) + reqif_doc = reqif_document_setup() + for relation in self.relations: + add_relation(reqif_doc, relation) + for itemid in self.iter_items(): + item = self.get_item(itemid) + add_requirement(reqif_doc, item) + export_xml(reqif_doc, fname) + def self_test(self, notification_item_id, docname=None): ''' Perform self test on collection content