Download this example as a Jupyter notebook or a Python script.


Perform a BoM compliance query#

Compliance queries can be performed on an XML BoM instead of a list of Granta MI records. The BoM must be in any valid Granta XML BoM format. This example shows how to use the lxml package with the XSD XML schema file to validate the XML format.

For help on constructing an XML BoM, see BoM examples.

If the XML file is generated by a Granta MI product and has not been modified, it is possible to skip this step before submitting the query. However, it is strongly advised to validate the XML BoM in all situations to avoid unexpected server-side failures. If an invalid XML file is used in a query, an exception is raised by the requests HTTP package, but it does not contain information about why the XML is non-compliant. A more detailed log is reported on the server in the MI Service Layer log.

The following supporting files are required for this example:

The XSD XML schema is included in the library in the schemas subpackage.

Validate an XML file with an XSD schema#

The lxml package provides a similar API to the standard library XML module, but it includes some additional functionality, including schema validation. First import the lxml package and then build a simple validator function that takes both the XML file and schema file and returns the result.

[1]:
from lxml import etree


def xml_validator(xml: str, schema_file: str) -> bool:
    schema = etree.XMLSchema(file=schema_file)
    doc = etree.fromstring(xml)
    return schema.validate(doc)

You can now use this function to test the validity of a BoM generated by BoM Analyzer.

[2]:
from ansys.grantami.bomanalytics.schemas import bom_schema_1711

valid_xml_file = "../supporting-files/compliance-bom.xml"
with open(valid_xml_file) as f:
    valid_xml = f.read()
result = xml_validator(valid_xml, bom_schema_1711)
result
[2]:
True

You can also test a BoM that is valid XML but is not compliant with the schema.

[3]:
invalid_xml_file = "../supporting-files/invalid-bom.xml"
with open(invalid_xml_file) as f:
    invalid_xml = f.read()
result = xml_validator(invalid_xml, bom_schema_1711)
result
[3]:
False

Run a compliance XML-based query#

Now that you have validated the XML, you can build your XML BoM-based query. First, connect to Granta MI.

[4]:
from ansys.grantami.bomanalytics import Connection

server_url = "http://my_grantami_server/mi_servicelayer"
cxn = Connection(server_url).with_credentials("user_name", "password").connect()

Running a BoM compliance query produces the same result as if you had stored the BoM structure as linked Products and Parts records in Granta MI.

[5]:
from ansys.grantami.bomanalytics import indicators, queries

CANDIDATE_LIST = "Candidate_AnnexXV"
svhc = indicators.WatchListIndicator(
    name="SVHC",
    legislation_ids=[CANDIDATE_LIST],
    default_threshold_percentage=0.1,
)
compliance_query = (
    queries.BomComplianceQuery()
    .with_bom(valid_xml)
    .with_indicators([svhc])
)
[6]:
compliance_result = cxn.run(compliance_query)
compliance_result
[6]:
<BomComplianceQueryResult: 1 PartWithCompliance results>

The BomComplianceQueryResult object returned after running the compliance query contains a list of PartWithComplianceResult objects, the behavior of which is covered in a previous example. The following cell prints the compliance status of the BoM.

[7]:
root_part = compliance_result.compliance_by_part_and_indicator[0]
print(f"BoM Compliance Status: {root_part.indicators['SVHC'].flag.name}")
BoM Compliance Status: WatchListHasSubstanceAboveThreshold

Raise an invalid BoM exception#

If you were to try the same query with an invalid BoM, you would see a stack trace informing you that the MI Service Layer responded with a 500 HTTP response code. To raise the exception, change the following RUN_QUERY constant to True.

[8]:
broken_query = (
    queries.BomImpactedSubstancesQuery()
    .with_bom(invalid_xml)
    .with_legislation_ids([CANDIDATE_LIST])
)

RUN_QUERY = False

if RUN_QUERY:
    cxn.run(broken_query)