Skip to main content

aas-submodel-to-py - AAS Submodel Python Code Generator

aas-submodel-to-py is a code generator tool built on top of the BaSyx-Python-SDK. It is designed to generate Submodel-specific classes and classes for its submodel elements with filled meta-information derived from submodel templates. These generated classes act as child classes of the BaSyx-Python-SDK classes and represent classes of the Asset Administration Shell Metamodel. The hierarchical structure of the generated submodel-specific class includes all the required submodel element-specific classes. Input files can be .aasx, .json, or .xml format (see Supported Input).

Examples

Example of generated classes

Here's a snippet of the classes generated from the Digital Nameplate 3.0.1 submodel template (... marks omitted lines). Each submodel element gets a class nested in the class of its submodel or collection. Its init takes the values of the element (e.g. value) and its submodel elements; metadata like semantic_id or description are keyword arguments, typed by a TypedDict per BaSyx class (e.g. PropertyMetadata), and default to the template's values, which template_defaults() returns. The classes build instances (kind=Instance), so template qualifiers like SMT/Cardinality, which are only allowed in templates, aren't taken over. Each module starts with a few helpers its classes share:

from typing import Any, Iterable, Optional, Tuple, TypedDict, Union, Unpack, cast
from basyx.aas import model as aas
from basyx.aas.model import datatypes as xsd


def global_ref(value: str) -> aas.ExternalReference:
    """External reference to the global identifier `value`, e.g. a semantic ID"""
    return aas.ExternalReference((aas.Key(aas.KeyTypes.GLOBAL_REFERENCE, value),))


def collect_submodel_elements(*elements: Any, number_repeated: bool = True) -> list[aas.SubmodelElement]:
    """Collect the submodel elements passed to an init in one list: single elements, unless None,
    and the elements of iterables, whose idShorts get an index if `number_repeated` (e.g. Keyword00)"""
    ...


class GeneratedSubmodelElementList(aas.SubmodelElementList):
    """SubmodelElementList, whose items may be instances of subclasses of type_value_list_element,
    such as the generated classes of its items"""
    ...


class MultiLanguagePropertyMetadata(TypedDict, total=False):
    """Metadata of aas.MultiLanguageProperty, passed as keyword arguments to its generated classes"""

    id_short: Optional[str]
    ...
    semantic_id: Optional[aas.Reference]
    ...


class Nameplate(aas.Submodel):

    class URIOfTheProduct(aas.Property):
        ...

    class ManufacturerName(aas.MultiLanguageProperty):

        @staticmethod
        def template_defaults() -> MultiLanguagePropertyMetadata:
            return {
                "id_short": r"ManufacturerName",
                "semantic_id": global_ref(r"0112/2///61987#ABA565#009"),
                "supplemental_semantic_id": (global_ref(r"0173-1#02-AAO677#004"),),
            }

        def __init__(self, value: aas.MultiLanguageTextType, **kwargs: Unpack[MultiLanguagePropertyMetadata]):

            super().__init__(value=value, **(self.template_defaults() | kwargs))

    ...

    class Markings(GeneratedSubmodelElementList):
        ...

    ...

    @staticmethod
    def template_defaults() -> SubmodelMetadata:
        return {
            "id_short": r"Nameplate",
            "description": aas.MultiLanguageTextType(
                dict_={r"en": r"Contains the nameplate information attached to the product"}
            ),
            "administration": aas.AdministrativeInformation(
                version=r"3",
                revision=r"0",
                ...
                template_id=r"https://admin-shell.io/idta-02006-3-0",
                ...
            ),
            "semantic_id": global_ref(r"https://admin-shell.io/idta/nameplate/3/0/Nameplate"),
        }

    def __init__(
        self,
        id_: str,
        uRIOfTheProduct: Union[xsd.AnyURI, URIOfTheProduct],
        manufacturerName: Union[aas.MultiLanguageTextType, ManufacturerName],
        ...
        yearOfConstruction: Optional[Union[str, YearOfConstruction]] = None,
        ...
        markings: Optional[Union[Iterable[Markings.Markings_item], Markings]] = None,
        ...
        **kwargs: Unpack[SubmodelMetadata],
    ):
        ...

Usage Example of the generated class

Here's an example of instantiating the generated Nameplate submodel. The classes generated from Digital Nameplate 3.0.1 are part of py-aas-submodels:

from basyx.aas.model import MultiLanguageTextType
from py_aas_submodels.digital_nameplate_3_0_1 import Nameplate

nameplate = Nameplate(
    id_="https://example.com/ids/sm/nameplate-001",
    uRIOfTheProduct="https://www.domain-abc.com/Model-Nr-1234",
    manufacturerName=MultiLanguageTextType({"de": "Muster AG"}),
    manufacturerProductDesignation=MultiLanguageTextType({"en": "ABC-123"}),
    addressInformation=Nameplate.AddressInformation(),
    orderCodeOfManufacturer="ABC-123-XYZ",
    yearOfConstruction="2022",
    serialNumber=Nameplate.SerialNumber("12345678"),
)

All required submodel elements are positional arguments; optional elements default to None. Metadata is passed as keyword arguments, e.g. Nameplate(..., id_short="Nameplate01"), and replaces the template's value (None removes it); type checkers like mypy report unknown or wrongly typed metadata. Instead of submodel elements (e.g. Nameplate.SerialNumber("12345678")), raw values can be passed (e.g. yearOfConstruction="2022"); multi-language values are passed as MultiLanguageTextType. Properties with a default value in the template (SMT/DefaultValue, else SMT/InitialValue) can be created without value, e.g. PAMSpecificationSheet.GeneralInformation.SafetyMeasure(). Of elements marked as alternatives (SMT/EitherOr), only one may be given; passing more raises a ValueError. Values restricted by the template (SMT/AllowedValue, SMT/AllowedRange, FormChoices, enumeration) are checked as well and available as class attributes, e.g. SafetyMeasure.ALLOWED_VALUES == ("True", "False"). Lists (SubmodelElementList) take an iterable of their items or raw values, e.g. phases=["A1", "B2"]. List items have no idShort by default, as it is optional since AAS metamodel 3.1. The output is auto-formatted with Black and passes the type checker mypy.

Installation

Using PyPI:

pip install aas-submodel-to-py

Or from the repository root:

pip install -e ./aas-submodel-to-py

Supported Input

Format AAS metamodel 3.1 AAS metamodel 3.0
.json ✅ ✅
.aasx ✅ ❌
.xml ✅ ❌

Files are read with the BaSyx Python SDK (≥ 2.1.0), which implements AAS metamodel 3.1 and can't read AASX and XML files of metamodel 3.0. Many templates on the IDTA website are still such files. For those, use the JSON version of the template, or its _forAASMetamodelV3.1 variant; both are published in admin-shell-io/submodel-templates.

For such files, as for any file without a submodel, the generator raises a NoSubmodelError (submodel_to_code exits with an error message) instead of writing a module.

Usage

Command Line

# Minimal: output .py is generated next to the input file
# e.g. IDTA-02006-2-0_Submodel_Digital Nameplate.aasx → IDTA_02006_2_0_Submodel_Digital_Nameplate.py
submodel_to_code -i /some/path/DigitalNameplate.aasx

# Write to a specific output directory (filename still auto-derived)
submodel_to_code -i /some/path/DigitalNameplate.aasx -d /some/other/path/

# Write to an explicit output file path
submodel_to_code -i /some/path/DigitalNameplate.aasx -o /some/path/output.py

# Overwrite an existing output file
submodel_to_code -i /some/path/DigitalNameplate.aasx --force
Flag Long form Description Required
-i --aas_path Input AAS file (.aasx, .json, or .xml) Yes
-o --outpath Output .py file path (mutually exclusive with -d) No
-d --outdir Output directory; filename is derived from the input filename (mutually exclusive with -o) No
-f --force Overwrite the output file if it already exists No

If neither -o nor -d is given, the output file is written next to the input file with hyphens and spaces in the name replaced by underscores.

If the entry-point is not on PATH, use the module invocation:

python -m aas_submodel_to_py.submodel_to_code \
    -i /some/path/DigitalNameplate.aasx \
    -o /some/path/output.py

Python API

from aas_submodel_to_py import SubmodelCodegen

codegen = SubmodelCodegen()

# Generate from an AAS file (.aasx, .json, or .xml)
codegen.generate_from(
    input_file="/some/path/DigitalNameplate.aasx",
    output_file="nameplate.py"
)

# If you already have an AAS object store loaded in memory
codegen.generate_from_obj_store(
    obj_store=my_existing_store,
    output_file="output.py"
)

Running Tests

From the repository root:

pip install -e "./aas-submodel-to-py[test]"
python -m pytest aas-submodel-to-py/tests

The Tests workflow runs these tests, and the import checks of all modules in py-aas-submodels, on Python 3.11 and 3.14 for every push to master/develop and every pull request.

Support and Contribution

If you encounter any issues, or want to contribute to the project, feel free to open an issue or a pull request. Your contributions are always welcome!

License

This project is licensed under the MIT License. See the LICENSE file for details.

Metadata

Release files for aas-submodel-to-py 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aas-submodel-to-py 0.2.0
File Size Uploaded Provenance Actions
aas_submodel_to_py-0.2.0.tar.gz 52.0 kB With provenance Details for aas_submodel_to_py-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for aas-submodel-to-py 0.2.0
File Interpreter ABI Platform Actions
aas_submodel_to_py-0.2.0-py3-none-any.whl Python 3 none any Details for aas_submodel_to_py-0.2.0-py3-none-any.whl

Total release size: 79.0 kB

Release files / aas_submodel_to_py-0.2.0.tar.gz

Download URL aas_submodel_to_py-0.2.0.tar.gz
Size 52.0 kB
Tags Source
SHA-256 checksum
How to use checksums
e0720ae04376fb4e5d7941fc48e8c7a05e7e0c7618c48bbb89a5d3c436cc74ab
BLAKE2b-256 checksum
How to use checksums
b8f62a16a2207431898c0589091332ca4ccbebb86432af22a6d8c534fb6bf1c1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Release files / aas_submodel_to_py-0.2.0-py3-none-any.whl

Download URL aas_submodel_to_py-0.2.0-py3-none-any.whl
Size 27.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
16a739ebd51007c75eaed3717361e9e6b6e45d44202c90618f933746357baa34
BLAKE2b-256 checksum
How to use checksums
ddaed7e5d632aa8d2724fd7a29f273cc5114222d0d3afc0f877d6cd2af03024a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

Security for aas-submodel-to-py 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for aas_submodel_to_py-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page