Skip to content

Update/metamodel v3.1.2#484

Open
s-heppner wants to merge 23 commits intoeclipse-basyx:developfrom
rwth-iat:update/Metamodel_V3.1.2
Open

Update/metamodel v3.1.2#484
s-heppner wants to merge 23 commits intoeclipse-basyx:developfrom
rwth-iat:update/Metamodel_V3.1.2

Conversation

@s-heppner
Copy link
Copy Markdown
Member

@s-heppner s-heppner commented Apr 28, 2026

This implements the changes of the metamodel for version 3.1.2 of the spec.

Fixes #437

s-heppner and others added 21 commits December 5, 2025 09:08
Prepare Release v2.0.0

# Release Notes

Version 2.0.0 of the BaSyx-Python SDK comes with a major refactoring of the server and a renewed concept for data persistence.

Previously, the server code was split between the `sdk` and `server` packages (due to historic development of the code). 
Now all the code relevant just for the server is located in `server`, where it belongs. Since this means, some code that was previously in `sdk` is not there anymore, this is a breaking change and warranted the new major release.

> [!note]
> This release does not have any changes in implemented AAS specification versions. It is the preparotory release in order to get ready for the new versions of the specifications, as well as new features for the SDK, such as Registry and Discovery server.

> [!warning]
> Due to these major refactorings, there were some backward incompatible changes. Please check the documentation, if you encounter any issues.

# Changelog

**Notable:**
- Backward Incompatible: Refactor server functionality from `sdk` to `server` (See: eclipse-basyx#388)
- Backward Incompatible: Refactor `backend` concept for data persistence (See: eclipse-basyx#370)
- Backward Incompatible: Refactor server `start-up` options (See: eclipse-basyx#418)
- Remove support for Python 3.9 (as it is EoL) (See eclipse-basyx#433)

**Improvements:**
- Clarify documentation of running the server with Docker (See: eclipse-basyx#398)
- Document running the server without Docker (See: eclipse-basyx#403)
- Improve XML serialization (See: eclipse-basyx#406)
- Improve server reading of JSON and XML files (See: eclipse-basyx#408)
- Add more utility methods for `Referable` and `Key` handling (See: eclipse-basyx#410)

**Bugfixes:**
- Fix type issues found with a new version of `mypy` (See: eclipse-basyx#399)
- Fix parsing of `ConceptDescription`s in the server (See: eclipse-basyx#420)
- Update `pyecma376-2` and `lxml` dependencies (See: eclipse-basyx#419)
* update constraint AASd-002

* adapt regex

* fix docs
Previously, Python 3.9 reached its EOL.

This replace all references to Python 3.9 within the SDK with references
to Python 3.10.

Fixes eclipse-basyx#432
Syncing with develop (copyright mismatch).
AASd-090 is removed, since category is deprecated ([Changelog/AASd-090](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=REMOVED:%20remove%20AASd%2D090:%20category%20is%20deprecated%20(#514))).

This means, we do not check that `DataElement.category` is one of `["CONSTANT", "PARAMETER", "VARIABLE"]` anymore.

Co-authored-by: Leon Huang <hleon@157-023.eduroam.rwth-aachen.de>
With version 3.1.2, the `base.AssetKind` enumeration now has an 
additional `Role` value. 

See the [Spec-Changelog](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AssetKind/Role,-New%20value%20in)).  

---------

Co-authored-by: Leon Huang <hleon@088-095.eduroam.rwth-aachen.de>
This updates the constraint documentation for version 3.1.2.

Replace "needs to" with "shall" ([AASd-006](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AASd%2D006,-Update), [AASd-007](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AASd%2D007,-Update), [AASd-021](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AASd%2D021,-Update), [AASd-077](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AASd%2D077,-Update)) in Docstrings. 

Update documentation for [AASd-116](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AASd%2D116,-Update). 

---------

Co-authored-by: Leon Huang <hleon@151-020.eduroam.rwth-aachen.de>
Co-authored-by: Leon Huang <hleon@157-023.eduroam.rwth-aachen.de>
Co-authored-by: Leon Huang <hleon@174-165.eduroam.rwth-aachen.de>
Previously, we had some weird bugs with the CI pipeline sometimes
failing (eclipse-basyx#400), but not always reproducible. Namely, sometimes the CI
failed, due to `mypy` not finding the `sdk` types when running from the
`compliance_tool` environment. Since currently, we are at a point where
it is impossible to reproduce the failing CI (at least for me), I
decided to clean up the job definitions a little bit and make some
things more explicit.

Namely, instead of calling scripts like `pip` or `mypy` from their PATH,
we now explicitly call them via `python -m pip` and `python -m mypy`.
This theoretically ensures, that it always uses the script we just
installed with the dependencies and not something the VM already had
in its path via `actions/setup-python@v5`.
This should ensure that a script like `mypy` actually has all the
necessary dependencies installed.

Secondly, we had a `pip install -e ../sdk[dev]`, therefore installing
the development dependencies of the `sdk` in the `compliance_tool` CI
check. This is technically incorrect, since we use the `sdk` as external
dependency and therefore shouldn't depend on the development
dependencies. I therefore removed this.

Lastly, the `sdk-readme-codeblocks` check uses `bash` syntax. In theory,
the Ubuntu environment should use `bash` by default, but now it is made
explicit.

Fixes eclipse-basyx#400 (hopefully)
Update to version 3.1 of the metamodel made the `content_type` attribute
of classes `Blob` and `File` optional. 

See the link to [the spec] for details.

[the spec]: https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#_metamodel_changes_v3_1_vs_v3_0_2
Update to version 3.1 of the spec removed constraint AASd-120.

See [the spec] for more details.

[the spec]: https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=AASd%2D120,-Removed

Co-authored-by: Leon Huang <hleon@088-095.eduroam.rwth-aachen.de>
…clipse-basyx#375)

This adds a `server-publish` configuration that publishes
the server Docker image on DockerHub. The logic is 
in line with the basyx-java-server. 

---------

Co-authored-by: s-heppner <iat@s-heppner.com>
…se-basyx#481)

Remove multiplatform support from DockerHub publishing for now

---------

Co-authored-by: Sercan Sahin <s.sahin@iat.rwth-aachen.de>
Until we implement eclipse-basyx#485 and update the `compliance-tool` properly, we should exclude it from the CI tests.
@s-heppner s-heppner added this to the Release 2.1.0 milestone Apr 29, 2026
@s-heppner s-heppner marked this pull request as ready for review May 5, 2026 11:38
Copy link
Copy Markdown
Contributor

@zrgt zrgt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to add tests for new optional fields:

  • AssetKind.ROLE round-trip (JSON + XML)
  • Blob/File with content_type=None round-trip
  • RelationshipElement with first=None/second=None
  • Entity with entity_type=None

Comment on lines +640 to 645
if obj.entity_type:
data['entityType'] = _generic.ENTITY_TYPES[obj.entity_type]
if obj.global_asset_id:
data['globalAssetId'] = obj.global_asset_id
if obj.specific_asset_id:
data['specificAssetIds'] = list(obj.specific_asset_id)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if obj.entity_type is not None:
data['entityType'] = _generic.ENTITY_TYPES[obj.entity_type]
if obj.global_asset_id is not None:
data['globalAssetId'] = obj.global_asset_id
if obj.specific_asset_id is not None:
data['specificAssetIds'] = list(obj.specific_asset_id)

We should use here the same pattern as in other methods.
Explicit is Better Than Implicit.

Comment thread README.md
| Specification | Version |
|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Part 1: Metamodel | [v3.0.1 (01001)](https://industrialdigitaltwin.org/wp-content/uploads/2024/06/IDTA-01001-3-0-1_SpecificationAssetAdministrationShell_Part1_Metamodel.pdf) |
| Part 1: Metamodel | [v3.1.2 (01001-3-0-1)](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/index.html) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Part 1: Metamodel | [v3.1.2 (01001-3-0-1)](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/index.html) |
| Part 1: Metamodel | [v3.1.2 (01001-3-1-2)](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/index.html) |

Must be 3-1-2 acc. to DOI: https://doi.org/10.62628/IDTA.01001-3-1-2

Comment on lines 638 to 639
first=cls._construct_reference(_get_ts(dct, 'first', dict)),
second=cls._construct_reference(_get_ts(dct, 'second', dict)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first/second are now optional acc. to the spec., so these can be absent in the JSON.
The deserialiser will fail if first/second are not present in the JSON, even though it is now valid.

Would be nice to have a UnitTest for such a case.

:return: dict with the serialized attributes of this object
"""
data = cls._abstract_classes_to_json(obj)
data.update({'first': obj.first, 'second': obj.second})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first/second are now optional acc. to the spec., so these should be absent in the JSON if not given.

Suggested change
if obj.first is not None:
data['first'] = obj.first
if obj.second is not None:
data['second'] = obj.second

:return: dict with the serialized attributes of this object
"""
data = cls._abstract_classes_to_json(obj)
data.update({'first': obj.first, 'second': obj.second})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first/second are now optional acc. to the spec., so these should be absent in the JSON if not given.

Comment on lines 649 to 650
first=cls._construct_reference(_get_ts(dct, 'first', dict)),
second=cls._construct_reference(_get_ts(dct, 'second', dict)))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first/second are now optional acc. to the spec., so these can be absent in the JSON.
The deserialiser will fail if first/second are not present in the JSON, even though it is now valid.

Comment on lines 515 to 516
_child_construct_mandatory(element, NS_AAS + "first", cls.construct_reference),
_child_construct_mandatory(element, NS_AAS + "second", cls.construct_reference)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first/second are now optional acc. to the spec., so these can be absent in the JSON.
The deserialiser will fail if first/second are not present in the JSON, even though it is now valid.

Comment on lines 581 to 582
data = cls._abstract_classes_to_json(obj)
data.update({'first': obj.first, 'second': obj.second})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
data = cls._relationship_element_to_json(obj)

# Generate a unique id_short when a SubmodelElement is added, because children of a SubmodelElementList may not
# have an id_short. The alternative would be making SubmodelElementList a special kind of base.Namespace without
# a unique attribute for child-elements (which contradicts the definition of a Namespace).
new.id_short = "generated_submodel_list_hack_" + uuid.uuid1(clock_seq=self._uuid_seq).hex
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still replace idShorts of SubmodelElements in a list. It shoudn't be the case if a SubmodelElement already has an idShort

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants