{ "cells": [ { "cell_type": "markdown", "id": "d882a35a", "metadata": {}, "source": [ "# Perform a BoM impacted substances query" ] }, { "cell_type": "markdown", "id": "7d6d31ac", "metadata": {}, "source": [ "Impacted substances queries can be performed on an XML BoM instead of a list\n", "of Granta MI records. The BoM must be in any valid Granta XML BoM format. This example shows how to use\n", "the ``lxml`` package with the XSD XML schema file to validate the XML format." ] }, { "cell_type": "markdown", "id": "eecd3013", "metadata": {}, "source": [ "For help on constructing an XML BoM, see [BoM examples](../6_BoMs/index.rst)." ] }, { "cell_type": "markdown", "id": "995755a8", "metadata": {}, "source": [ "If the XML file is generated by a Granta MI product and has not been modified, it is possible to skip this step before\n", "submitting the query. However, it is strongly advised to validate the XML BoM in all situations to avoid unexpected\n", "server-side failures. If an invalid XML file is used in a query, an exception is raised by the ``requests`` HTTP\n", "package, but it does not contain information about why the XML is non-compliant. A more detailed log is\n", "reported on the server in the MI Service Layer log." ] }, { "cell_type": "markdown", "id": "9145bf1f", "metadata": {}, "source": [ "The following supporting files are required for this example:\n", "\n", "* [compliance-bom.xml](../supporting-files/compliance-bom.xml)\n", "* [invalid-bom.xml](../supporting-files/invalid-bom.xml)" ] }, { "cell_type": "markdown", "id": "e8820aae", "metadata": {}, "source": [ "The XSD XML schema is included in the library in the ``schemas`` subpackage." ] }, { "cell_type": "markdown", "id": "73a7dc39", "metadata": {}, "source": [ "## Validate an XML file with an XSD schema" ] }, { "cell_type": "markdown", "id": "0b44481a", "metadata": {}, "source": [ "
\n", "\n", "**Info:**\n", "\n", "If you are planning on using a BoM that has been generated in a supported version of Granta MI BoM Analyzer or\n", "Materials Gateway, and the BoM has not been modified, you do not need to validate the XML. However, if invalid XML is\n", "used in a query, a [requests](https://requests.readthedocs.io/en/latest/) exception is raised when the query is\n", "submitted, with a more detailed report available in the MI Service Layer log. Therefore, to avoid unexpected\n", "server-side failures, you should set up validation in all situations.\n", "
" ] }, { "cell_type": "markdown", "id": "0bab346b", "metadata": {}, "source": [ "The ``lxml`` package provides a similar API to the standard library XML module, but it includes some additional\n", "functionality, including schema validation. First import the ``lxml`` package and then build a simple validator\n", "function that takes both the XML file and schema file and returns the result." ] }, { "cell_type": "code", "execution_count": null, "id": "04ead98a", "metadata": { "lines_to_end_of_cell_marker": 0, "lines_to_next_cell": 1 }, "outputs": [], "source": [ "from lxml import etree\n", "\n", "\n", "def xml_validator(xml: str, schema_file: str) -> bool:\n", " schema = etree.XMLSchema(file=schema_file)\n", " doc = etree.fromstring(xml)\n", " return schema.validate(doc)" ] }, { "cell_type": "markdown", "id": "74dca169", "metadata": {}, "source": [ "You can now use this function to test the validity of a BoM generated by BoM Analyzer." ] }, { "cell_type": "code", "execution_count": null, "id": "25dc1a0e", "metadata": {}, "outputs": [], "source": [ "from ansys.grantami.bomanalytics.schemas import bom_schema_1711\n", "\n", "valid_xml_file = \"../supporting-files/compliance-bom.xml\"\n", "with open(valid_xml_file) as f:\n", " valid_xml = f.read()\n", "result = xml_validator(valid_xml, bom_schema_1711)\n", "result" ] }, { "cell_type": "markdown", "id": "ed3e14a9", "metadata": {}, "source": [ "You can also test a BoM that is valid XML but is not compliant with the schema." ] }, { "cell_type": "code", "execution_count": null, "id": "290946e1", "metadata": {}, "outputs": [], "source": [ "invalid_xml_file = \"../supporting-files/invalid-bom.xml\"\n", "with open(invalid_xml_file) as f:\n", " invalid_xml = f.read()\n", "result = xml_validator(invalid_xml, bom_schema_1711)\n", "result" ] }, { "cell_type": "markdown", "id": "4cff7f1b", "metadata": {}, "source": [ "## Run an impacted substances XML-based query" ] }, { "cell_type": "markdown", "id": "a9a9a081", "metadata": {}, "source": [ "Now that you have validated the XML, you can build your XML BoM-based query.\n", "First, connect to Granta MI." ] }, { "cell_type": "code", "execution_count": null, "id": "94b7a52b", "metadata": {}, "outputs": [], "source": [ "from ansys.grantami.bomanalytics import Connection\n", "\n", "server_url = \"http://my_grantami_server/mi_servicelayer\"\n", "cxn = Connection(server_url).with_credentials(\"user_name\", \"password\").connect()" ] }, { "cell_type": "markdown", "id": "52901d2b", "metadata": {}, "source": [ "The impacted substances BoM query behaves similar to other impacted substances queries. However,\n", "a BoM query can only accept a single BoM at a time, and so you only ever receive a single list\n", "of substances impacted by the specified legislations." ] }, { "cell_type": "code", "execution_count": null, "id": "84c3d320", "metadata": {}, "outputs": [], "source": [ "from ansys.grantami.bomanalytics import queries\n", "\n", "SIN_LIST = \"SINList\"\n", "impacted_substances_query = (\n", " queries.BomImpactedSubstancesQuery()\n", " .with_bom(valid_xml)\n", " .with_legislation_ids([SIN_LIST])\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "5f11d7d1", "metadata": {}, "outputs": [], "source": [ "impacted_substances_result = cxn.run(impacted_substances_query)\n", "impacted_substances_result" ] }, { "cell_type": "markdown", "id": "9eeaba87", "metadata": {}, "source": [ "The ``BomImpactedSubstancesQueryResult`` object returned after running the query for impacted substances now behaves\n", "similarly to the result object for any other query for impacted substances. For example, you can print all substances\n", "impacted by the legislation using an approach from the previous example." ] }, { "cell_type": "code", "execution_count": null, "id": "f19b55d5", "metadata": {}, "outputs": [], "source": [ "from tabulate import tabulate\n", "\n", "rows = [\n", " [substance.cas_number, substance.max_percentage_amount_in_material]\n", " for substance in impacted_substances_result.impacted_substances\n", "]\n", "print(f'Substances impacted by \"{SIN_LIST}\" in a BoM (5/{len(rows)})')\n", "print(tabulate(rows[:5], headers=[\"CAS Number\", \"Amount (wt. %)\"]))" ] }, { "cell_type": "markdown", "id": "9b34ea9a", "metadata": {}, "source": [ "## Raise an invalid BoM exception" ] }, { "cell_type": "markdown", "id": "505711c6", "metadata": {}, "source": [ "If you were to try the same query with an invalid BoM, you would see a stack trace informing you that the MI Service\n", "Layer responded with a 500 HTTP response code. To raise the exception, change the following ``RUN_QUERY`` constant to\n", "``True``." ] }, { "cell_type": "code", "execution_count": null, "id": "0d4c0dfe", "metadata": {}, "outputs": [], "source": [ "broken_query = (\n", " queries.BomImpactedSubstancesQuery()\n", " .with_bom(invalid_xml)\n", " .with_legislation_ids([SIN_LIST])\n", ")\n", "\n", "RUN_QUERY = False\n", "\n", "if RUN_QUERY:\n", " cxn.run(broken_query)" ] } ], "metadata": { "jupytext": { "formats": "ipynb,py:light" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }