A XactFlow exporter plugin that serializes
ipxact.Design objects into valid IEEE 1685-2022
IP-XACT design XML documents.
ipxact-compiler reads IP-XACT XML and hands back
Python objects, it never writes XML. This package is the other direction: given a Design, it
writes the XML back out.
pip install xactflow-designFor local development, requirements-dev.txt overrides ipxact-compiler and xactflow to
local installations. It can be modified to adapt the paths or to keep either version on PyPI.
pip install -r requirements-dev.txt -e .Requires Python >= 3.9 and XactFlow >= 0.4.0, whose exporters take a Library rather than a
single object.
from pathlib import Path
from xactflow import Library
from xactflow_design import DesignExporter
library = Library()
library.add_file("top_design.xml", target=True) # or let an importer add its designs
DesignExporter().export(library, Path("out"))
# writes out/<vendor>_<library>_<name>_<version>.xmlThe exporter writes every ipxact.Design among the library's targets(); the library's other
documents are not written. Each output file is named after the design's full VLNV
(<vendor>_<library>_<name>_<version>.xml) inside output_dir, which is created if it does not
exist. Each VLNV part may only hold letters, digits, ., _ and -; anything else raises
ValueError. Exporting the same design again replaces its file, but a file of that name holding
anything else (another VLNV, or not a design), or two targets sharing a file name, raise
FileExistsError. Every file name is checked before any file is written, so a rejected target
leaves output_dir untouched.
Lower-level entry points are available for callers that want the tree or the bytes rather than a file:
from xactflow_design import design_to_bytes, write_design, write_design_file
element = write_design(design) # the lxml ipxact:design root element
data = design_to_bytes(design) # pretty-printed bytes, with an XML declaration and a generated-by comment
path = write_design_file(design, "out.xml") # writes and returns the pathOnce installed, the exporter registers itself under the xactflow.exporters entry point group as
design. From the XactFlow CLI, run it on a design file, which XactFlow links against the --lib
folders before exporting, or after an importer with --then design:
xactflow design top_design.xml --lib ip/ --output out/
xactflow archidesc design.py --lib ip/ --then design --output out/
# writes out/<vendor>_<library>_<name>_<version>.xmlexport() raises TypeError when the library has no ipxact.Design target. Writing out a
fully resolved LinkedDesign, or a matching designConfiguration alongside it, is a planned
later addition, not an oversight.
The exporter takes no options for now, so any --option / --then-option also raises TypeError.
- Element order comes from the XSD, not from the dataclasses.
design's sequence putsdisplayName/shortDescription/descriptionright after the VLNV, andcomponentInstanceputscomponentRefbeforepowerDomainLinks, while the corresponding dataclasses declare those fields in a different order. The same mismatch repeats ininterconnectionandmonitorInterconnection, whosenameGroupopens the element while the Python fields are trailing optionals. Every writer here follows the schema. - Expressions are written verbatim. Anything typed
Expressioninipxact-compiler(tiedValue,externalPowerDomainReference, aparameter'svalue, theleft/rightof apartSelect'srange, ...) has itsvaluetext emitted unchanged, never evaluated or reformatted, together with itsminimum/maximum,xml:idand foreign attributes. - Vendor extensions stay identical. Their content is not IP-XACT's to define, so each fragment is re-inserted as parsed (only a leading XML declaration is dropped).
- Defaults are omitted. Attributes whose value equals the schema default
(
resolve="immediate",type="string") are left out, which keeps the output close to hand-written IP-XACT and still round-trips exactly. - Interconnections and monitor interconnections share one XML container but two Python
lists.
design.xsd'sinterconnectionselement freely interleavesinterconnectionandmonitorInterconnectionchildren, butDesignkeeps them as two separate lists with no record of their original relative order. The writer emits everyinterconnectionfirst, then everymonitorInterconnection; the content is unaffected, only the interleaving is not preserved. - Required XSD cardinalities raise
ValueErrorwhen left unsatisfied, instead of emitting invalid XML. Aninterconnectionneeds a second active interface or a hierarchical interface, anadHocConnectionneeds at least one internal or external port reference, amonitorInterconnectionneeds at least one monitor interface, apowerDomainLinkneeds at least one internal power domain reference, achoiceneeds at least one enumeration, and apartSelectneeds indices or a range. Rather than silently writing an incomplete element for any of these, the writer raises a specific error naming the missing field. design.xsd's key, keyref and unique constraints raiseValueErrortoo. Component instance names, interconnection and monitor interconnection names (one shared namespace), ad hoc connection names, parameter ids and choice names must be unique; everyactiveInterfaceof aninterconnectionand everyinternalPortReferencemust name an existing component instance, and a parameter'schoiceRefan existing choice. Simple types (xs:Name,xs:NMTOKEN, a parameter'stype) are not checked.
pip install -r requirements-dev.txt -e .
pytestThe tests round-trip the tests/xml/top_design.xml fixture and a hand-built design through the
writer and back through the parser, validate the written XML against the design.xsd shipped with
ipxact-compiler with lxml.etree.XMLSchema.assertValid, and re-run
xactflow.SCR.run_single_doc_checks on the result.
LGPL-3.0. See LICENSE.