From 7ad6a01bd101db263c07700dfd700aed0b35ce82 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 5 Dec 2025 09:54:59 +0100 Subject: [PATCH 01/17] update constraint AASd-002 (#62) * update constraint AASd-002 * adapt regex * fix docs --- sdk/basyx/aas/model/base.py | 24 ++++++++++++++++-------- sdk/docs/source/constraints.rst | 2 +- sdk/test/model/test_base.py | 13 +++++++++---- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 35ccad5a1..6f8cb79a3 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -596,8 +596,9 @@ class Referable(HasExtension, metaclass=abc.ABCMeta): **Constraint AASd-001:** In case of a referable element not being an identifiable element the idShort is mandatory and used for referring to the element in its name space. - **Constraint AASd-002:** idShort shall only feature letters, digits, underscore (``_``); starting - mandatory with a letter. + **Constraint AASd-002:** idShort shall only feature letters, digits, underscore (``_``), hyphen (``-``); + starting mandatory with a letter and not ending with a hyphen. + I.e. ``^[a-zA-Z]|[a-zA-Z][a-zA-Z0-9_-]*[a-zA-Z0-9_]$`` **Constraint AASd-004:** Add parent in case of non-identifiable elements. @@ -758,8 +759,9 @@ def validate_id_short(cls, id_short: NameType) -> None: """ Validates an id_short against Constraint AASd-002 and :class:`NameType` restrictions. - **Constraint AASd-002:** idShort of Referables shall only feature letters, digits, underscore (``_``); starting - mandatory with a letter. I.e. ``[a-zA-Z][a-zA-Z0-9_]+`` + **Constraint AASd-002:** idShort shall only feature letters, digits, underscore (``_``), hyphen (``-``); + starting mandatory with a letter and not ending with a hyphen. + I.e. ``^[a-zA-Z]|[a-zA-Z][a-zA-Z0-9_-]*[a-zA-Z0-9_]$`` :param id_short: The id_short to validate :raises ValueError: If the id_short doesn't comply to the constraints imposed by :class:`NameType` @@ -768,16 +770,21 @@ def validate_id_short(cls, id_short: NameType) -> None: """ _string_constraints.check_name_type(id_short) test_id_short: NameType = str(id_short) - if not re.fullmatch("[a-zA-Z0-9_]*", test_id_short): + if not re.fullmatch("[A-Za-z0-9_-]*", test_id_short): raise AASConstraintViolation( 2, - "The id_short must contain only letters, digits and underscore" + "The id_short must contain only letters, digits underscore and hyphen" ) if not test_id_short[0].isalpha(): raise AASConstraintViolation( 2, "The id_short must start with a letter" ) + if test_id_short.endswith("-"): + raise AASConstraintViolation( + 2, + "The id_short must not end with a hyphen" + ) category = property(_get_category, _set_category) @@ -785,8 +792,9 @@ def _set_id_short(self, id_short: Optional[NameType]): """ Check the input string - **Constraint AASd-002:** idShort of Referables shall only feature letters, digits, underscore (``_``); starting - mandatory with a letter. I.e. ``[a-zA-Z][a-zA-Z0-9_]+`` + **Constraint AASd-002:** idShort shall only feature letters, digits, underscore (``_``), hyphen (``-``); + starting mandatory with a letter and not ending with a hyphen. + I.e. ``^[a-zA-Z]|[a-zA-Z][a-zA-Z0-9_-]*[a-zA-Z0-9_]$`` **Constraint AASd-022:** idShort of non-identifiable referables shall be unique in its namespace (case-sensitive) diff --git a/sdk/docs/source/constraints.rst b/sdk/docs/source/constraints.rst index f51ea0ed5..18f8aa947 100644 --- a/sdk/docs/source/constraints.rst +++ b/sdk/docs/source/constraints.rst @@ -14,7 +14,7 @@ The status information means the following: In most cases, if a constraint violation is detected, an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised -.. |aasd002| replace:: ``idShort`` of ``Referable`` s shall only feature letters, digits, underscore (``_``); starting mandatory with a letter, i.e. ``[a-zA-Z][a-zA-Z0-9_]*``. +.. |aasd002| replace:: ``idShort`` of ``Referable`` s shall only feature letters, digits, underscore (``_``), hyphen (``-``); starting mandatory with a letter and not ending with a hyphen. I.e. ``^[a-zA-Z]|[a-zA-Z][a-zA-Z0-9_-]*[a-zA-Z0-9_]$``. .. |aasd005| replace:: If ``AdministrativeInformation/version`` is not specified, ``AdministrativeInformation/revision`` shall also be unspecified. This means that a revision requires a version. If there is no version, there is no revision. Revision is optional. .. |aasd006| replace:: If both, the ``value`` and the ``valueId`` of a ``Qualifier`` are present, the value needs to be identical to the value of the referenced coded value in ``Qualifier/valueId``. .. |aasd007| replace:: If both the ``Property/value`` and the ``Property/valueId`` are present, the value of ``Property/value`` needs to be identical to the value of the referenced coded value in ``Property/valueId``. diff --git a/sdk/test/model/test_base.py b/sdk/test/model/test_base.py index 460bce563..578fcbcd0 100644 --- a/sdk/test/model/test_base.py +++ b/sdk/test/model/test_base.py @@ -100,10 +100,15 @@ def test_id_short_constraint_aasd_002(self): test_object = ExampleReferable() test_object.id_short = "Test" self.assertEqual("Test", test_object.id_short) - test_object.id_short = "asdASd123_" - self.assertEqual("asdASd123_", test_object.id_short) + test_object.id_short = "asdASd-123_" + self.assertEqual("asdASd-123_", test_object.id_short) test_object.id_short = "AAs12_" self.assertEqual("AAs12_", test_object.id_short) + test_object.id_short = "A" + self.assertEqual("A", test_object.id_short) + with self.assertRaises(model.AASConstraintViolation) as cm: + test_object.id_short = "Test-" + self.assertEqual("The id_short must not end with a hyphen (Constraint AASd-002)", str(cm.exception)) with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "98sdsfdAS" self.assertEqual("The id_short must start with a letter (Constraint AASd-002)", str(cm.exception)) @@ -113,12 +118,12 @@ def test_id_short_constraint_aasd_002(self): with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "asdlujSAD8348@S" self.assertEqual( - "The id_short must contain only letters, digits and underscore (Constraint AASd-002)", + "The id_short must contain only letters, digits underscore and hyphen (Constraint AASd-002)", str(cm.exception)) with self.assertRaises(model.AASConstraintViolation) as cm: test_object.id_short = "abc\n" self.assertEqual( - "The id_short must contain only letters, digits and underscore (Constraint AASd-002)", + "The id_short must contain only letters, digits underscore and hyphen (Constraint AASd-002)", str(cm.exception)) def test_representation(self): From e0fc000d6635c1dccca40da43095858e0576ac82 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 5 Dec 2025 09:59:17 +0100 Subject: [PATCH 02/17] update RelationshipElemet first and second to be optional (#64) --- sdk/basyx/aas/adapter/xml/xml_serialization.py | 6 ++++-- sdk/basyx/aas/model/submodel.py | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sdk/basyx/aas/adapter/xml/xml_serialization.py b/sdk/basyx/aas/adapter/xml/xml_serialization.py index 2dc578ca0..3966d71d1 100644 --- a/sdk/basyx/aas/adapter/xml/xml_serialization.py +++ b/sdk/basyx/aas/adapter/xml/xml_serialization.py @@ -733,8 +733,10 @@ def relationship_element_to_xml(obj: model.RelationshipElement, :return: Serialized :class:`~lxml.etree._Element` object """ et_relationship_element = abstract_classes_to_xml(tag, obj) - et_relationship_element.append(reference_to_xml(obj.first, NS_AAS+"first")) - et_relationship_element.append(reference_to_xml(obj.second, NS_AAS+"second")) + if obj.first is not None: + et_relationship_element.append(reference_to_xml(obj.first, NS_AAS+"first")) + if obj.second is not None: + et_relationship_element.append(reference_to_xml(obj.second, NS_AAS+"second")) return et_relationship_element diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index 9e7321c41..419727ceb 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -860,8 +860,8 @@ class RelationshipElement(SubmodelElement): def __init__(self, id_short: Optional[base.NameType], - first: base.Reference, - second: base.Reference, + first: Optional[base.Reference] = None, + second: Optional[base.Reference] = None, display_name: Optional[base.MultiLanguageNameType] = None, category: Optional[base.NameType] = None, description: Optional[base.MultiLanguageTextType] = None, @@ -877,8 +877,8 @@ def __init__(self, super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, supplemental_semantic_id, embedded_data_specifications) - self.first: base.Reference = first - self.second: base.Reference = second + self.first: Optional[base.Reference] = first + self.second: Optional[base.Reference] = second class AnnotatedRelationshipElement(RelationshipElement, base.UniqueIdShortNamespace): From eb1b877122026436f77f8213cbb9a979351e0fa0 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 5 Dec 2025 09:59:52 +0100 Subject: [PATCH 03/17] update data type lengths (#65) --- sdk/basyx/aas/model/_string_constraints.py | 8 ++++---- sdk/test/model/test_string_constraints.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sdk/basyx/aas/model/_string_constraints.py b/sdk/basyx/aas/model/_string_constraints.py index 376f76b0e..0bd454c88 100644 --- a/sdk/basyx/aas/model/_string_constraints.py +++ b/sdk/basyx/aas/model/_string_constraints.py @@ -64,11 +64,11 @@ def check(value: str, type_name: str, min_length: int = 0, max_length: Optional[ def check_content_type(value: str, type_name: str = "ContentType") -> None: - return check(value, type_name, 1, 100) + return check(value, type_name, 1, 128) def check_identifier(value: str, type_name: str = "Identifier") -> None: - return check(value, type_name, 1, 2000) + return check(value, type_name, 1, 2048) def check_label_type(value: str, type_name: str = "LabelType") -> None: @@ -84,7 +84,7 @@ def check_name_type(value: str, type_name: str = "NameType") -> None: def check_path_type(value: str, type_name: str = "PathType") -> None: - return check(value, type_name, 1, 2000) + return check(value, type_name, 1, 2048) def check_qualifier_type(value: str, type_name: str = "QualifierType") -> None: @@ -100,7 +100,7 @@ def check_short_name_type(value: str, type_name: str = "ShortNameType") -> None: def check_value_type_iec61360(value: str, type_name: str = "ValueTypeIEC61360") -> None: - return check(value, type_name, 1, 2000) + return check(value, type_name, 1, 2048) def check_version_type(value: str, type_name: str = "VersionType") -> None: diff --git a/sdk/test/model/test_string_constraints.py b/sdk/test/model/test_string_constraints.py index 55d5789f5..88214e774 100644 --- a/sdk/test/model/test_string_constraints.py +++ b/sdk/test/model/test_string_constraints.py @@ -17,11 +17,11 @@ def test_identifier(self) -> None: with self.assertRaises(ValueError) as cm: _string_constraints.check_identifier(identifier) self.assertEqual("Identifier has a minimum length of 1! (length: 0)", cm.exception.args[0]) - identifier = "a" * 2001 + identifier = "a" * 2049 with self.assertRaises(ValueError) as cm: _string_constraints.check_identifier(identifier) - self.assertEqual("Identifier has a maximum length of 2000! (length: 2001)", cm.exception.args[0]) - identifier = "a" * 2000 + self.assertEqual("Identifier has a maximum length of 2048! (length: 2049)", cm.exception.args[0]) + identifier = "a" * 2048 _string_constraints.check_identifier(identifier) def test_version_type(self) -> None: @@ -73,8 +73,8 @@ def test_path_type_decoration(self) -> None: self.assertEqual("PathType has a minimum length of 1! (length: 0)", cm.exception.args[0]) dc = self.DummyClass("a") with self.assertRaises(ValueError) as cm: - dc.some_attr = "a" * 2001 - self.assertEqual("PathType has a maximum length of 2000! (length: 2001)", cm.exception.args[0]) + dc.some_attr = "a" * 2049 + self.assertEqual("PathType has a maximum length of 2048! (length: 2049)", cm.exception.args[0]) self.assertEqual(dc.some_attr, "a") def test_ignore_none_values(self) -> None: From 368a6b7a6cbf9ed640dd1d3e2e1803ec475bef4b Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:01:13 +0100 Subject: [PATCH 04/17] update entityType to be optional (#67) --- sdk/basyx/aas/adapter/json/json_serialization.py | 3 ++- sdk/basyx/aas/adapter/xml/xml_serialization.py | 3 ++- sdk/basyx/aas/model/submodel.py | 12 +++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sdk/basyx/aas/adapter/json/json_serialization.py b/sdk/basyx/aas/adapter/json/json_serialization.py index 0b0df0164..8f21fe912 100644 --- a/sdk/basyx/aas/adapter/json/json_serialization.py +++ b/sdk/basyx/aas/adapter/json/json_serialization.py @@ -635,7 +635,8 @@ def _entity_to_json(cls, obj: model.Entity) -> Dict[str, object]: data = cls._abstract_classes_to_json(obj) if not cls.stripped and obj.statement: data['statements'] = list(obj.statement) - data['entityType'] = _generic.ENTITY_TYPES[obj.entity_type] + 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: diff --git a/sdk/basyx/aas/adapter/xml/xml_serialization.py b/sdk/basyx/aas/adapter/xml/xml_serialization.py index 3966d71d1..0607a064a 100644 --- a/sdk/basyx/aas/adapter/xml/xml_serialization.py +++ b/sdk/basyx/aas/adapter/xml/xml_serialization.py @@ -824,7 +824,8 @@ def entity_to_xml(obj: model.Entity, for statement in obj.statement: et_statements.append(submodel_element_to_xml(statement)) et_entity.append(et_statements) - et_entity.append(_generate_element(NS_AAS + "entityType", text=_generic.ENTITY_TYPES[obj.entity_type])) + if obj.entity_type: + et_entity.append(_generate_element(NS_AAS + "entityType", text=_generic.ENTITY_TYPES[obj.entity_type])) if obj.global_asset_id: et_entity.append(_generate_element(NS_AAS + "globalAssetId", text=obj.global_asset_id)) if obj.specific_asset_id: diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index 419727ceb..7297136e1 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -1088,7 +1088,7 @@ class Entity(SubmodelElement, base.UniqueIdShortNamespace): def __init__(self, id_short: Optional[base.NameType], - entity_type: base.EntityType, + entity_type: Optional[base.EntityType], statement: Iterable[SubmodelElement] = (), global_asset_id: Optional[base.Identifier] = None, specific_asset_id: Iterable[base.SpecificAssetId] = (), @@ -1108,7 +1108,7 @@ def __init__(self, supplemental_semantic_id, embedded_data_specifications) self.statement = base.NamespaceSet(self, [("id_short", True)], statement) # assign private attributes, bypassing setters, as constraints will be checked below - self._entity_type: base.EntityType = entity_type + self._entity_type: Optional[base.EntityType] = entity_type self._global_asset_id: Optional[base.Identifier] = global_asset_id self._specific_asset_id: base.ConstrainedList[base.SpecificAssetId] = base.ConstrainedList( specific_asset_id, @@ -1120,11 +1120,11 @@ def __init__(self, self._validate_aasd_014(entity_type, global_asset_id, bool(specific_asset_id)) @property - def entity_type(self) -> base.EntityType: + def entity_type(self) -> Optional[base.EntityType]: return self._entity_type @entity_type.setter - def entity_type(self, entity_type: base.EntityType) -> None: + def entity_type(self, entity_type: Optional[base.EntityType]) -> None: self._validate_aasd_014(entity_type, self.global_asset_id, bool(self.specific_asset_id)) self._entity_type = entity_type @@ -1167,9 +1167,11 @@ def _validate_global_asset_id(global_asset_id: Optional[base.Identifier]) -> Non _string_constraints.check_identifier(global_asset_id) @staticmethod - def _validate_aasd_014(entity_type: base.EntityType, + def _validate_aasd_014(entity_type: Optional[base.EntityType], global_asset_id: Optional[base.Identifier], specific_asset_id_nonempty: bool) -> None: + if entity_type is None: + return if entity_type == base.EntityType.SELF_MANAGED_ENTITY and global_asset_id is None \ and not specific_asset_id_nonempty: raise base.AASConstraintViolation( From e85a0edd689c8916f8be5881aaa22967ac925d3a Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 5 Dec 2025 10:07:35 +0100 Subject: [PATCH 05/17] add Role asset (#69) --- sdk/basyx/aas/model/base.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 6f8cb79a3..850e2bbe5 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -223,7 +223,7 @@ class ModellingKind(Enum): @unique class AssetKind(Enum): """ - Enumeration for denoting whether an asset is a type asset or an instance asset or whether this kind of + Enumeration for denoting whether an asset is a type asset or an instance asset or role asset or whether this kind of classification is not applicable. .. note:: @@ -235,12 +235,14 @@ class AssetKind(Enum): :cvar TYPE: Type asset :cvar INSTANCE: Instance asset - :cvar NOT_APPLICABLE: Neither a type asset nor an instance asset + :cvar ROLE: Role asset + :cvar NOT_APPLICABLE: Neither a type asset nor an instance asset nor a role asset """ TYPE = 0 INSTANCE = 1 - NOT_APPLICABLE = 2 + ROLE = 2 + NOT_APPLICABLE = 3 class QualifierKind(Enum): From 0fb526d21a6e9e3968de7e42c45b8a4456ae769c Mon Sep 17 00:00:00 2001 From: Moritz Sommer Date: Tue, 2 Dec 2025 11:08:41 +0100 Subject: [PATCH 06/17] Fix Python 3.9 EOL (#433) 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 #432 --- .github/workflows/ci.yml | 6 +++--- compliance_tool/pyproject.toml | 2 +- sdk/.readthedocs.yaml | 2 +- sdk/pyproject.toml | 2 +- server/app/pyproject.toml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f45ee611f..da22ee48f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ name: ci on: [push, pull_request] env: - X_PYTHON_MIN_VERSION: "3.9" + X_PYTHON_MIN_VERSION: "3.10" X_PYTHON_MAX_VERSION: "3.12" jobs: @@ -45,7 +45,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.12"] + python-version: ["3.10", "3.12"] env: COUCHDB_ADMIN_PASSWORD: "yo0Quai3" # (2024-10-11, s-heppner) @@ -208,7 +208,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.12"] + python-version: ["3.10", "3.12"] defaults: run: working-directory: ./compliance_tool diff --git a/compliance_tool/pyproject.toml b/compliance_tool/pyproject.toml index c907f90df..e235bdc9b 100644 --- a/compliance_tool/pyproject.toml +++ b/compliance_tool/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ "Operating System :: OS Independent", "Development Status :: 5 - Production/Stable" ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "pyecma376-2>=0.2.4", "jsonschema>=4.21.1", diff --git a/sdk/.readthedocs.yaml b/sdk/.readthedocs.yaml index 1085208ac..7fd098a4c 100644 --- a/sdk/.readthedocs.yaml +++ b/sdk/.readthedocs.yaml @@ -6,7 +6,7 @@ version: 2 build: os: ubuntu-20.04 tools: - python: "3.9" + python: "3.10" sphinx: configuration: docs/source/conf.py diff --git a/sdk/pyproject.toml b/sdk/pyproject.toml index 588d18407..b2a7a6b7e 100644 --- a/sdk/pyproject.toml +++ b/sdk/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ "Operating System :: OS Independent", "Development Status :: 5 - Production/Stable" ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "lxml>=6.0.2", "python-dateutil>=2.8,<3", diff --git a/server/app/pyproject.toml b/server/app/pyproject.toml index abaae73d6..030be7397 100644 --- a/server/app/pyproject.toml +++ b/server/app/pyproject.toml @@ -34,7 +34,7 @@ classifiers = [ "Operating System :: OS Independent", "Development Status :: 5 - Production/Stable" ] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "urllib3>=1.26,<3", "Werkzeug>=3.0.3,<4", From 97072fc4a271c72ee8ffd98da6c7b64dd3f77ce8 Mon Sep 17 00:00:00 2001 From: Leon Huang Date: Tue, 27 Jan 2026 09:51:53 +0100 Subject: [PATCH 07/17] Remove AASd-090 (#71) 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 --- sdk/basyx/aas/model/submodel.py | 22 ---------------------- sdk/docs/source/constraints.rst | 2 -- 2 files changed, 24 deletions(-) diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index 6ce0d22ea..7837b397e 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -150,13 +150,6 @@ def __init__(self, self.embedded_data_specifications: List[base.EmbeddedDataSpecification] = list(embedded_data_specifications) -ALLOWED_DATA_ELEMENT_CATEGORIES: Set[str] = { - "CONSTANT", - "PARAMETER", - "VARIABLE" -} - - class DataElement(SubmodelElement, metaclass=abc.ABCMeta): """ A data element is a :class:`~.SubmodelElement` that is not further composed out of other @@ -203,21 +196,6 @@ def __init__(self, super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, supplemental_semantic_id, embedded_data_specifications) - def _set_category(self, category: Optional[str]): - if category == "": - raise base.AASConstraintViolation(100, - "category is not allowed to be an empty string") - if category is None: - self._category = None - else: - if category not in ALLOWED_DATA_ELEMENT_CATEGORIES: - if not (isinstance(self, File) or isinstance(self, Blob)): - raise base.AASConstraintViolation( - 90, - "DataElement.category must be one of the following: " + - ", ".join(ALLOWED_DATA_ELEMENT_CATEGORIES)) - self._category = category - class Property(DataElement): """ diff --git a/sdk/docs/source/constraints.rst b/sdk/docs/source/constraints.rst index 18f8aa947..612f8fb41 100644 --- a/sdk/docs/source/constraints.rst +++ b/sdk/docs/source/constraints.rst @@ -26,7 +26,6 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised .. |aasd077| replace:: The name of an extension (``Extension/name``) within ``HasExtensions`` needs to be unique. .. |aasd080| replace:: In case ``Key/type`` == ``GlobalReference`` ``idType`` shall not be any LocalKeyType (``IdShort, FragmentId``). .. |aasd081| replace:: In case ``Key/type`` == ``AssetAdministrationShell`` ``Key/idType`` shall not be any LocalKeyType (``IdShort``, ``FragmentId``). -.. |aasd090| replace:: for data elements, ``category`` (inherited by ``Referable``) shall be one of the following values: CONSTANT, PARAMETER or VARIABLE. Default: VARIABLE .. |aasd107| replace:: If a first level child element in a ``SubmodelElementList`` has a semanticId, it shall be identical to ``SubmodelElementList/semanticIdListElement``. .. |aasd108| replace:: All first level child elements in a ``SubmodelElementList`` shall have the same submodel element type as specified in ``SubmodelElementList/typeValueListElement``. .. |aasd109| replace:: If ``SubmodelElementList/typeValueListElement`` is equal to ``Property`` or ``Range,`` ``SubmodelElementList/valueTypeListElement`` shall be set and all first level child elements in the ``SubmodelElementList`` shall have the value type as specified in ``SubmodelElementList/valueTypeListElement``. @@ -76,7 +75,6 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised AASd-077, |aasd077|, ✅, AASd-080, |aasd080|, ✅, AASd-081, |aasd081|, ✅, - AASd-090, |aasd090|, ✅, AASd-107, |aasd107|, ✅, AASd-108, |aasd108|, ✅, AASd-109, |aasd109|, ✅, From f6bc2ba9287ee2f1d95bce16c2e9ab0b7c819804 Mon Sep 17 00:00:00 2001 From: Leon Huang Date: Tue, 27 Jan 2026 10:00:06 +0100 Subject: [PATCH 08/17] Add Role to AssetKind (#73) 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 --- sdk/basyx/aas/adapter/_generic.py | 5 +++-- sdk/basyx/aas/model/base.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sdk/basyx/aas/adapter/_generic.py b/sdk/basyx/aas/adapter/_generic.py index 65d14d8d3..f09b69add 100644 --- a/sdk/basyx/aas/adapter/_generic.py +++ b/sdk/basyx/aas/adapter/_generic.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -37,7 +37,8 @@ ASSET_KIND: Dict[model.AssetKind, str] = { model.AssetKind.TYPE: 'Type', model.AssetKind.INSTANCE: 'Instance', - model.AssetKind.NOT_APPLICABLE: 'NotApplicable'} + model.AssetKind.NOT_APPLICABLE: 'NotApplicable', + model.AssetKind.ROLE: 'Role'} QUALIFIER_KIND: Dict[model.QualifierKind, str] = { model.QualifierKind.CONCEPT_QUALIFIER: 'ConceptQualifier', diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 4113d1616..6b7c18aac 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -241,8 +241,8 @@ class AssetKind(Enum): TYPE = 0 INSTANCE = 1 - ROLE = 2 - NOT_APPLICABLE = 3 + NOT_APPLICABLE = 2 + ROLE = 3 class QualifierKind(Enum): From 56e4fe7f00a45f30576d8472b90cf33e6283c8f4 Mon Sep 17 00:00:00 2001 From: Leon Huang Date: Tue, 27 Jan 2026 10:02:57 +0100 Subject: [PATCH 09/17] Update constraint documentation (#74) 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 Co-authored-by: Leon Huang Co-authored-by: Leon Huang --- sdk/basyx/aas/model/base.py | 6 +++--- sdk/basyx/aas/model/submodel.py | 2 +- sdk/docs/source/constraints.rst | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 6b7c18aac..7f8b0403d 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -551,7 +551,7 @@ class HasExtension(Namespace, metaclass=abc.ABCMeta): <> - **Constraint AASd-077:** The name of an Extension within HasExtensions needs to be unique. + **Constraint AASd-077:** The name of an Extension within HasExtensions shall be unique. :ivar namespace_element_sets: List of :class:`NamespaceSets ` :ivar extension: A :class:`~.NamespaceSet` of :class:`Extensions <.Extension>` of the element. @@ -1640,8 +1640,8 @@ class Qualifier(HasSemantics): """ A qualifier is a type-value pair that makes additional statements w.r.t. the value of the element. - **Constraint AASd-006:** If both, the value and the valueId of a Qualifier are present, the value needs - to be identical to the value of the referenced coded value in Qualifier/valueId. + **Constraint AASd-006:** If both, the value and the valueId of a Qualifier are present, the value shall + be identical to the value of the referenced coded value in Qualifier/valueId. **Constraint AASd-020:** The value of Qualifier/value shall be consistent with the data type as defined in Qualifier/valueType. diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index 7837b397e..f60d80b2d 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -202,7 +202,7 @@ class Property(DataElement): A property is a :class:`DataElement` that has a single value. **Constraint AASd-007:** If both, the value and the valueId of a Qualifier are present, - the value needs to be identical to the value of the referenced coded value in Qualifier/valueId. + the value shall be identical to the value of the referenced coded value in Qualifier/valueId. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) diff --git a/sdk/docs/source/constraints.rst b/sdk/docs/source/constraints.rst index 612f8fb41..de937d0d3 100644 --- a/sdk/docs/source/constraints.rst +++ b/sdk/docs/source/constraints.rst @@ -16,14 +16,14 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised .. |aasd002| replace:: ``idShort`` of ``Referable`` s shall only feature letters, digits, underscore (``_``), hyphen (``-``); starting mandatory with a letter and not ending with a hyphen. I.e. ``^[a-zA-Z]|[a-zA-Z][a-zA-Z0-9_-]*[a-zA-Z0-9_]$``. .. |aasd005| replace:: If ``AdministrativeInformation/version`` is not specified, ``AdministrativeInformation/revision`` shall also be unspecified. This means that a revision requires a version. If there is no version, there is no revision. Revision is optional. -.. |aasd006| replace:: If both, the ``value`` and the ``valueId`` of a ``Qualifier`` are present, the value needs to be identical to the value of the referenced coded value in ``Qualifier/valueId``. -.. |aasd007| replace:: If both the ``Property/value`` and the ``Property/valueId`` are present, the value of ``Property/value`` needs to be identical to the value of the referenced coded value in ``Property/valueId``. +.. |aasd006| replace:: If both, the ``value`` and the ``valueId`` of a ``Qualifier`` are present, the value shall be identical to the value of the referenced coded value in ``Qualifier/valueId``. +.. |aasd007| replace:: If both the ``Property/value`` and the ``Property/valueId`` are present, the value of ``Property/value`` shall be identical to the value of the referenced coded value in ``Property/valueId``. .. |aasd012| replace:: if both the ``MultiLanguageProperty/value`` and the ``MultiLanguageProperty/valueId`` are present, the meaning must be the same for each string in a specific language, as specified in ``MultiLanguageProperty/valueId``. .. |aasd014| replace:: Either the attribute ``globalAssetId`` or ``specificAssetId`` of an ``Entity`` must be set if ``Entity/entityType`` is set to ``SelfManagedEntity``. Otherwise, they do not exist. .. |aasd020| replace:: The value of ``Qualifier/value`` shall be consistent with the data type as defined in ``Qualifier/valueType``. -.. |aasd021| replace:: Every qualifiable can only have one qualifier with the same ``Qualifier/type``. +.. |aasd021| replace:: Every qualifiable shall only have one qualifier with the same ``Qualifier/type``. .. |aasd022| replace:: ``idShort`` of non-identifiable referables within the same name space shall be unique (case-sensitive). -.. |aasd077| replace:: The name of an extension (``Extension/name``) within ``HasExtensions`` needs to be unique. +.. |aasd077| replace:: The name of an extension (``Extension/name``) within ``HasExtensions`` shall be unique. .. |aasd080| replace:: In case ``Key/type`` == ``GlobalReference`` ``idType`` shall not be any LocalKeyType (``IdShort, FragmentId``). .. |aasd081| replace:: In case ``Key/type`` == ``AssetAdministrationShell`` ``Key/idType`` shall not be any LocalKeyType (``IdShort``, ``FragmentId``). .. |aasd107| replace:: If a first level child element in a ``SubmodelElementList`` has a semanticId, it shall be identical to ``SubmodelElementList/semanticIdListElement``. @@ -31,7 +31,7 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised .. |aasd109| replace:: If ``SubmodelElementList/typeValueListElement`` is equal to ``Property`` or ``Range,`` ``SubmodelElementList/valueTypeListElement`` shall be set and all first level child elements in the ``SubmodelElementList`` shall have the value type as specified in ``SubmodelElementList/valueTypeListElement``. .. |aasd114| replace:: If two first level child elements in a ``SubmodelElementList`` have a ``semanticId``, they shall be identical. .. |aasd115| replace:: If a first level child element in a ``SubmodelElementList`` does not specify a ``semanticId``, the value is assumed to be identical to ``SubmodelElementList/semanticIdListElement``. -.. |aasd116| replace:: ``globalAssetId`` (case-insensitive) is a reserved key. If used as value for ``SpecificAssetId/name,`` ``SpecificAssetId/value`` shall be identical to ``AssetInformation/globalAssetId``. +.. |aasd116| replace:: ``globalAssetId`` (case-insensitive) is a reserved key for ``SpecificAssetId/name`` with the semantics as defined in ``:attr:`basyx.aas.model.aas.AssetInformation.global_asset_id``. .. |aasd117| replace:: ``idShort`` of non-identifiable ``Referables`` not being a direct child of a ``SubmodelElementList`` shall be specified. .. |aasd118| replace:: If a supplemental semantic ID (``HasSemantics/supplementalSemanticId``) is defined, there shall also be a main semantic ID (``HasSemantics/semanticId``). .. |aasd119| replace:: If any ``Qualifier/kind`` value of a ``Qualifiable/qualifier`` is equal to ``TemplateQualifier`` and the qualified element inherits from ``HasKind``, the qualified element shall be of kind ``Template`` (``HasKind/kind = Template``). From 7430a4af4febc2d1e85a93b736f8193ea237d24b Mon Sep 17 00:00:00 2001 From: Leon Huang Date: Wed, 4 Feb 2026 12:54:50 +0100 Subject: [PATCH 10/17] Update/metamodel v3.1.2: AASd-014 (#70) AASd-014: `entityType` now optional. Update documentation and changed related code accordingly ([Changelog/AASd-014](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#:~:text=CHANGED:%20Entity/entityType%20and%20Constraint%20AASd%2D014:%20entityType%20now%20optional%20(#287))). --- sdk/basyx/aas/adapter/json/json_deserialization.py | 9 ++++++--- sdk/basyx/aas/adapter/xml/xml_deserialization.py | 10 +++++++--- sdk/basyx/aas/model/submodel.py | 4 ++-- sdk/docs/source/constraints.rst | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/sdk/basyx/aas/adapter/json/json_deserialization.py b/sdk/basyx/aas/adapter/json/json_deserialization.py index 84635703d..ab038bb1f 100644 --- a/sdk/basyx/aas/adapter/json/json_deserialization.py +++ b/sdk/basyx/aas/adapter/json/json_deserialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -528,9 +528,12 @@ def _construct_entity(cls, dct: Dict[str, object], object_class=model.Entity) -> if 'specificAssetIds' in dct: for desc_data in _get_ts(dct, "specificAssetIds", list): specific_asset_id.add(cls._construct_specific_asset_id(desc_data, model.SpecificAssetId)) - + if 'entityType' in dct: + entity_type = ENTITY_TYPES_INVERSE[_get_ts(dct, 'entityType', str)] + else: + entity_type = None ret = object_class(id_short=None, - entity_type=ENTITY_TYPES_INVERSE[_get_ts(dct, "entityType", str)], + entity_type=entity_type, global_asset_id=global_asset_id, specific_asset_id=specific_asset_id) cls._amend_abstract_attributes(ret, dct) diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py index b263820d1..de9bf8742 100644 --- a/sdk/basyx/aas/adapter/xml/xml_deserialization.py +++ b/sdk/basyx/aas/adapter/xml/xml_deserialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -827,10 +827,14 @@ def construct_entity(cls, element: etree._Element, object_class=model.Entity, ** for id in _child_construct_multiple(specific_asset_ids, NS_AAS + "specificAssetId", cls.construct_specific_asset_id, cls.failsafe): specific_asset_id.add(id) - + entity_type_text = _get_text_or_none(element.find(NS_AAS + "entityType")) + if entity_type_text is not None: + entity_type = ENTITY_TYPES_INVERSE[entity_type_text] + else: + entity_type = None entity = object_class( id_short=None, - entity_type=_child_text_mandatory_mapped(element, NS_AAS + "entityType", ENTITY_TYPES_INVERSE), + entity_type=entity_type, global_asset_id=_get_text_or_none(element.find(NS_AAS + "globalAssetId")), specific_asset_id=specific_asset_id) diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index f60d80b2d..72514913c 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -1041,8 +1041,8 @@ class Entity(SubmodelElement, base.UniqueIdShortNamespace): """ An entity is a :class:`~.SubmodelElement` that is used to model entities - **Constraint AASd-014:** global_asset_id or specific_asset_id must be set if ``entity_type`` is set to - :attr:`~basyx.aas.model.base.EntityType.SELF_MANAGED_ENTITY`. They must be empty otherwise. + **Constraint AASd-014:** Either the attribute ``globalAssetId`` or ``specificAssetId`` of an ``Entity`` + must be set if ``Entity/entityType`` is set to ``SelfManagedEntity``. :ivar id_short: Identifying string of the element within its name space. (inherited from :class:`~basyx.aas.model.base.Referable`) diff --git a/sdk/docs/source/constraints.rst b/sdk/docs/source/constraints.rst index de937d0d3..fb8cb260f 100644 --- a/sdk/docs/source/constraints.rst +++ b/sdk/docs/source/constraints.rst @@ -19,7 +19,7 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised .. |aasd006| replace:: If both, the ``value`` and the ``valueId`` of a ``Qualifier`` are present, the value shall be identical to the value of the referenced coded value in ``Qualifier/valueId``. .. |aasd007| replace:: If both the ``Property/value`` and the ``Property/valueId`` are present, the value of ``Property/value`` shall be identical to the value of the referenced coded value in ``Property/valueId``. .. |aasd012| replace:: if both the ``MultiLanguageProperty/value`` and the ``MultiLanguageProperty/valueId`` are present, the meaning must be the same for each string in a specific language, as specified in ``MultiLanguageProperty/valueId``. -.. |aasd014| replace:: Either the attribute ``globalAssetId`` or ``specificAssetId`` of an ``Entity`` must be set if ``Entity/entityType`` is set to ``SelfManagedEntity``. Otherwise, they do not exist. +.. |aasd014| replace:: Either the attribute ``globalAssetId`` or ``specificAssetId`` of an ``Entity`` must be set if ``Entity/entityType`` is set to ``SelfManagedEntity``. .. |aasd020| replace:: The value of ``Qualifier/value`` shall be consistent with the data type as defined in ``Qualifier/valueType``. .. |aasd021| replace:: Every qualifiable shall only have one qualifier with the same ``Qualifier/type``. .. |aasd022| replace:: ``idShort`` of non-identifiable referables within the same name space shall be unique (case-sensitive). From 81278b90354fbead17d27e10682c1c4d90398d04 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:00:11 +0100 Subject: [PATCH 11/17] Update metamodel element IDs and links to V3.1 (#63) See [here](https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.1.2/changelog.html#_metamodel_changes_v3_1_vs_v3_0_2) for the changes. --- README.md | 2 +- sdk/basyx/aas/adapter/_generic.py | 2 +- sdk/basyx/aas/adapter/xml/xml_deserialization.py | 2 +- sdk/basyx/aas/examples/data/example_aas.py | 4 ++-- sdk/basyx/aas/model/base.py | 2 +- sdk/test/adapter/xml/test_xml_deserialization.py | 14 +++++++------- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9894d320c..468fe63e5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ These are the implemented AAS specifications of the [current SDK release](https: | Specification | Version | |---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Part 1: Metamodel | [v3.0.1 (01001-3-0-1)](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) | | Schemata (JSONSchema, XSD) | [v3.0.8 (IDTA-01001-3-0-1_schemasV3.0.8)](https://github.com/admin-shell-io/aas-specs/releases/tag/IDTA-01001-3-0-1_schemasV3.0.8) | | Part 2: API | [v3.0 (01002-3-0)](https://industrialdigitaltwin.org/en/wp-content/uploads/sites/2/2023/06/IDTA-01002-3-0_SpecificationAssetAdministrationShell_Part2_API_.pdf) | | Part 3a: Data Specification IEC 61360 | [v3.0 (01003-a-3-0)](https://industrialdigitaltwin.org/wp-content/uploads/2023/04/IDTA-01003-a-3-0_SpecificationAssetAdministrationShell_Part3a_DataSpecification_IEC61360.pdf) | diff --git a/sdk/basyx/aas/adapter/_generic.py b/sdk/basyx/aas/adapter/_generic.py index f09b69add..aa4f9d692 100644 --- a/sdk/basyx/aas/adapter/_generic.py +++ b/sdk/basyx/aas/adapter/_generic.py @@ -27,7 +27,7 @@ ) # XML Namespace definition -XML_NS_MAP = {"aas": "https://admin-shell.io/aas/3/0"} +XML_NS_MAP = {"aas": "https://admin-shell.io/aas/3/1"} XML_NS_AAS = "{" + XML_NS_MAP["aas"] + "}" MODELLING_KIND: Dict[model.ModellingKind, str] = { diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py index de9bf8742..d1b09a8d7 100644 --- a/sdk/basyx/aas/adapter/xml/xml_deserialization.py +++ b/sdk/basyx/aas/adapter/xml/xml_deserialization.py @@ -98,7 +98,7 @@ def _element_pretty_identifier(element: etree._Element) -> str: If the prefix is known, the namespace in the element tag is replaced by the prefix. If additionally also the sourceline is known, it is added as a suffix to name. - For example, instead of "{https://admin-shell.io/aas/3/0}assetAdministrationShell" this function would return + For example, instead of "{https://admin-shell.io/aas/3/1}assetAdministrationShell" this function would return "aas:assetAdministrationShell on line $line", if both, prefix and sourceline, are known. :param element: The xml element. diff --git a/sdk/basyx/aas/examples/data/example_aas.py b/sdk/basyx/aas/examples/data/example_aas.py index e093c603a..225573e94 100644 --- a/sdk/basyx/aas/examples/data/example_aas.py +++ b/sdk/basyx/aas/examples/data/example_aas.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -23,7 +23,7 @@ _embedded_data_specification_iec61360 = model.EmbeddedDataSpecification( data_specification=model.ExternalReference((model.Key(type_=model.KeyTypes.GLOBAL_REFERENCE, value='https://admin-shell.io/DataSpecificationTemplates/' - 'DataSpecificationIEC61360/3/0'),)), + 'DataSpecificationIEC61360/3/1'),)), data_specification_content=model.DataSpecificationIEC61360(preferred_name=model.PreferredNameTypeIEC61360({ 'de': 'Test Specification', 'en-US': 'TestSpecification' diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 7f8b0403d..06249a991 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -1182,7 +1182,7 @@ class DataSpecificationContent: **Constraint AASc-3a-050:** If the ``Data_specification_IEC_61360`` is used for an element, the value of ``HasDataSpecification.embedded_data_specifications`` shall contain the external reference to the IRI of the corresponding data specification - template ``https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/0`` + template ``https://admin-shell.io/DataSpecificationTemplates/DataSpecificationIEC61360/3/1`` """ @abc.abstractmethod def __init__(self): diff --git a/sdk/test/adapter/xml/test_xml_deserialization.py b/sdk/test/adapter/xml/test_xml_deserialization.py index 331ad98c5..c1c84053f 100644 --- a/sdk/test/adapter/xml/test_xml_deserialization.py +++ b/sdk/test/adapter/xml/test_xml_deserialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -450,22 +450,22 @@ def construct_submodel(cls, element: etree._Element, object_class=EnhancedSubmod class TestTagReplaceNamespace(unittest.TestCase): def test_known_namespace(self): - tag = '{https://admin-shell.io/aas/3/0}tag' + tag = '{https://admin-shell.io/aas/3/1}tag' expected = 'aas:tag' self.assertEqual(_tag_replace_namespace(tag, XML_NS_MAP), expected) def test_empty_prefix(self): # Empty prefix should not be replaced as otherwise it would apply everywhere - tag = '{https://admin-shell.io/aas/3/0}tag' - nsmap = {"": "https://admin-shell.io/aas/3/0"} - expected = '{https://admin-shell.io/aas/3/0}tag' + tag = '{https://admin-shell.io/aas/3/1}tag' + nsmap = {"": "https://admin-shell.io/aas/3/1"} + expected = '{https://admin-shell.io/aas/3/1}tag' self.assertEqual(_tag_replace_namespace(tag, nsmap), expected) def test_empty_namespace(self): # Empty namespaces should also have no effect - tag = '{https://admin-shell.io/aas/3/0}tag' + tag = '{https://admin-shell.io/aas/3/1}tag' nsmap = {"aas": ""} - expected = '{https://admin-shell.io/aas/3/0}tag' + expected = '{https://admin-shell.io/aas/3/1}tag' self.assertEqual(_tag_replace_namespace(tag, nsmap), expected) def test_unknown_namespace(self): From bdbfdcc38af199b92bf6b335f9decf14f521a8a2 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Mon, 9 Feb 2026 14:54:15 +0100 Subject: [PATCH 12/17] Improve CI.yml definition (#453) Previously, we had some weird bugs with the CI pipeline sometimes failing (#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 #400 (hopefully) --- .github/workflows/ci.yml | 53 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da22ee48f..caab87d0b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install -r ./check_python_versions_requirements.txt + python -m pip install -r ./check_python_versions_requirements.txt - name: Check Supported Python Versions run: | python check_python_versions_supported.py \ @@ -85,17 +85,17 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install .[dev] + python -m pip install .[dev] - name: Setup test config and CouchDB database server run: | python test/_helper/setup_testdb.py -u "admin" -p "$COUCHDB_ADMIN_PASSWORD" - name: Test with coverage + unittest run: | - coverage run --source=basyx -m unittest + python -m coverage run --source=basyx -m unittest - name: Report test coverage if: ${{ always() }} run: | - coverage report -m + python -m coverage report -m sdk-static-analysis: # This job runs static code analysis, namely pycodestyle and mypy @@ -112,13 +112,13 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install .[dev] + python -m pip install .[dev] - name: Check typing with MyPy run: | - mypy basyx test + python -m mypy basyx test - name: Check code style with PyCodestyle run: | - pycodestyle --count --max-line-length 120 basyx test + python -m pycodestyle --count --max-line-length 120 basyx test sdk-readme-codeblocks: # This job runs the same static code analysis (mypy and pycodestyle) on the codeblocks in our docstrings. @@ -135,16 +135,17 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install .[dev] + python -m pip install .[dev] - name: Check typing with MyPy + shell: bash run: | - mypy <(codeblocks python README.md) + python -m mypy <(python -m codeblocks python README.md) - name: Check code style with PyCodestyle run: | - codeblocks --wrap python README.md | pycodestyle --count --max-line-length 120 - + python -m codeblocks --wrap python README.md | python -m pycodestyle --count --max-line-length 120 - - name: Run readme codeblocks with Python run: | - codeblocks python README.md | python + python -m codeblocks python README.md | python sdk-docs: # This job checks, if the automatically generated documentation using sphinx can be compiled @@ -161,7 +162,7 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install .[docs] + python -m pip install .[docs] - name: Check documentation for errors run: | SPHINXOPTS="-a -E -n -W --keep-going" make -C docs html @@ -181,7 +182,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install build + python -m pip install build - name: Create source and wheel dist run: | python -m build @@ -223,15 +224,15 @@ jobs: # install the local sdk in editable mode so it does not get overwritten run: | python -m pip install --upgrade pip - pip install -e ../sdk[dev] - pip install .[dev] + python -m pip install ../sdk + python -m pip install .[dev] - name: Test with coverage + unittest run: | - coverage run --source=aas_compliance_tool -m unittest + python -m coverage run --source=aas_compliance_tool -m unittest - name: Report test coverage if: ${{ always() }} run: | - coverage report -m + python -m coverage report -m compliance-tool-static-analysis: # This job runs static code analysis, namely pycodestyle and mypy @@ -250,14 +251,14 @@ jobs: # install the local sdk in editable mode so it does not get overwritten run: | python -m pip install --upgrade pip - pip install -e ../sdk[dev] - pip install .[dev] + python -m pip install ../sdk + python -m pip install .[dev] - name: Check typing with MyPy run: | - mypy aas_compliance_tool test + python -m mypy aas_compliance_tool test - name: Check code style with PyCodestyle run: | - pycodestyle --count --max-line-length 120 aas_compliance_tool test + python -m pycodestyle --count --max-line-length 120 aas_compliance_tool test compliance-tool-package: # This job checks if we can build our compliance_tool package @@ -275,7 +276,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install build + python -m pip install build - name: Create source and wheel dist run: | python -m build @@ -301,14 +302,14 @@ jobs: - name: Install Python dependencies run: | python -m pip install --upgrade pip - pip install ../../sdk - pip install .[dev] + python -m pip install ../../sdk + python -m pip install .[dev] - name: Check typing with MyPy run: | - mypy . + python -m mypy . - name: Check code style with PyCodestyle run: | - pycodestyle --count --max-line-length 120 . + python -m pycodestyle --count --max-line-length 120 . server-package: # This job checks if we can build our server package From 738337e5c02a22398936ee9bf20b73532c75ea4b Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Wed, 25 Feb 2026 09:43:06 +0100 Subject: [PATCH 13/17] Make contentType optional for Blob and File (#66) 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 --- sdk/basyx/aas/adapter/json/json_serialization.py | 8 +++++--- sdk/basyx/aas/adapter/xml/xml_serialization.py | 8 +++++--- sdk/basyx/aas/model/submodel.py | 8 ++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sdk/basyx/aas/adapter/json/json_serialization.py b/sdk/basyx/aas/adapter/json/json_serialization.py index 8f21fe912..4f03ce716 100644 --- a/sdk/basyx/aas/adapter/json/json_serialization.py +++ b/sdk/basyx/aas/adapter/json/json_serialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -476,7 +476,8 @@ def _blob_to_json(cls, obj: model.Blob) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data['contentType'] = obj.content_type + if obj.content_type is not None: + data['contentType'] = obj.content_type if obj.value is not None: data['value'] = base64.b64encode(obj.value).decode() return data @@ -490,7 +491,8 @@ def _file_to_json(cls, obj: model.File) -> Dict[str, object]: :return: dict with the serialized attributes of this object """ data = cls._abstract_classes_to_json(obj) - data['contentType'] = obj.content_type + if obj.content_type is not None: + data['contentType'] = obj.content_type if obj.value is not None: data['value'] = obj.value return data diff --git a/sdk/basyx/aas/adapter/xml/xml_serialization.py b/sdk/basyx/aas/adapter/xml/xml_serialization.py index 0607a064a..c309ee1d0 100644 --- a/sdk/basyx/aas/adapter/xml/xml_serialization.py +++ b/sdk/basyx/aas/adapter/xml/xml_serialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -627,7 +627,8 @@ def blob_to_xml(obj: model.Blob, if obj.value is not None: et_value.text = base64.b64encode(obj.value).decode() et_blob.append(et_value) - et_blob.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) + if obj.content_type is not None: + et_blob.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) return et_blob @@ -643,7 +644,8 @@ def file_to_xml(obj: model.File, et_file = abstract_classes_to_xml(tag, obj) if obj.value: et_file.append(_generate_element(NS_AAS + "value", text=obj.value)) - et_file.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) + if obj.content_type is not None: + et_file.append(_generate_element(NS_AAS + "contentType", text=obj.content_type)) return et_file diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index 72514913c..5d16f066e 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -452,7 +452,7 @@ class Blob(DataElement): def __init__(self, id_short: Optional[base.NameType], - content_type: base.ContentType, + content_type: Optional[base.ContentType] = None, value: Optional[base.BlobType] = None, display_name: Optional[base.MultiLanguageNameType] = None, category: Optional[base.NameType] = None, @@ -470,7 +470,7 @@ def __init__(self, super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, supplemental_semantic_id, embedded_data_specifications) self.value: Optional[base.BlobType] = value - self.content_type: base.ContentType = content_type + self.content_type: Optional[base.ContentType] = content_type @_string_constraints.constrain_content_type("content_type") @@ -506,7 +506,7 @@ class File(DataElement): def __init__(self, id_short: Optional[base.NameType], - content_type: base.ContentType, + content_type: Optional[base.ContentType] = None, value: Optional[base.PathType] = None, display_name: Optional[base.MultiLanguageNameType] = None, category: Optional[base.NameType] = None, @@ -524,7 +524,7 @@ def __init__(self, super().__init__(id_short, display_name, category, description, parent, semantic_id, qualifier, extension, supplemental_semantic_id, embedded_data_specifications) self.value: Optional[base.PathType] = value - self.content_type: base.ContentType = content_type + self.content_type: Optional[base.ContentType] = content_type class ReferenceElement(DataElement): From 93c7fdc6094628d2892096c76bb5690365ef2b81 Mon Sep 17 00:00:00 2001 From: Leon Huang Date: Wed, 25 Feb 2026 09:46:17 +0100 Subject: [PATCH 14/17] Remove AASd-120 (#72) 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 --- sdk/basyx/aas/model/base.py | 3 --- sdk/basyx/aas/model/submodel.py | 3 --- sdk/docs/source/constraints.rst | 2 -- sdk/test/model/test_submodel.py | 15 +-------------- 4 files changed, 1 insertion(+), 22 deletions(-) diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index 06249a991..0ee681c7c 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -819,9 +819,6 @@ def _set_id_short(self, id_short: Optional[NameType]): raise AASConstraintViolation(117, f"id_short of {self!r} cannot be unset, since it is already " f"contained in {self.parent!r}") from .submodel import SubmodelElementList - if isinstance(self.parent, SubmodelElementList): - raise AASConstraintViolation(120, f"id_short of {self!r} cannot be set, because it is " - f"contained in a {self.parent!r}") for set_ in self.parent.namespace_element_sets: if set_.contains_id("id_short", id_short): raise AASConstraintViolation(22, "Object with id_short '{}' is already present in the parent " diff --git a/sdk/basyx/aas/model/submodel.py b/sdk/basyx/aas/model/submodel.py index 5d16f066e..62a4e5cb0 100644 --- a/sdk/basyx/aas/model/submodel.py +++ b/sdk/basyx/aas/model/submodel.py @@ -728,9 +728,6 @@ def __init__(self, raise def _generate_id_short(self, new: _SE) -> None: - if new.id_short is not None: - raise base.AASConstraintViolation(120, "Objects with an id_short may not be added to a " - f"SubmodelElementList, got {new!r} with id_short={new.id_short}") # 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). diff --git a/sdk/docs/source/constraints.rst b/sdk/docs/source/constraints.rst index fb8cb260f..ede97394b 100644 --- a/sdk/docs/source/constraints.rst +++ b/sdk/docs/source/constraints.rst @@ -35,7 +35,6 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised .. |aasd117| replace:: ``idShort`` of non-identifiable ``Referables`` not being a direct child of a ``SubmodelElementList`` shall be specified. .. |aasd118| replace:: If a supplemental semantic ID (``HasSemantics/supplementalSemanticId``) is defined, there shall also be a main semantic ID (``HasSemantics/semanticId``). .. |aasd119| replace:: If any ``Qualifier/kind`` value of a ``Qualifiable/qualifier`` is equal to ``TemplateQualifier`` and the qualified element inherits from ``HasKind``, the qualified element shall be of kind ``Template`` (``HasKind/kind = Template``). -.. |aasd120| replace:: ``idShort`` of submodel elements being a direct child of a ``SubmodelElementList`` shall not be specified. .. |aasd121| replace:: For ``References``, the value of ``Key/type`` of the first ``key`` of ``Reference/keys`` shall be one of ``GloballyIdentifiables``. .. |aasd122| replace:: For external references, i.e. ``References`` with ``Reference/type = ExternalReference``, the value of ``Key/type`` of the first key of ``Reference/keys`` shall be one of ``GenericGloballyIdentifiables``. .. |aasd123| replace:: For model references, i.e. ``References`` with ``Reference/type = ModellReference``, the value of ``Key/type`` of the first ``key`` of ``Reference/keys`` shall be one of ``AasIdentifiables``. @@ -84,7 +83,6 @@ an :class:`~basyx.aas.model.base.AASConstraintViolation` will be raised AASd-117, |aasd117|, ✅, AASd-118, |aasd118|, ✅, AASd-119, |aasd119|, ❌, See `#119 `__ - AASd-120, |aasd120|, ✅, AASd-121, |aasd121|, ✅, AASd-122, |aasd122|, ✅, AASd-123, |aasd123|, ✅, diff --git a/sdk/test/model/test_submodel.py b/sdk/test/model/test_submodel.py index 37a5792df..f5d57cc7a 100644 --- a/sdk/test/model/test_submodel.py +++ b/sdk/test/model/test_submodel.py @@ -1,4 +1,4 @@ -# Copyright (c) 2025 the Eclipse BaSyx Authors +# Copyright (c) 2026 the Eclipse BaSyx Authors # # This program and the accompanying materials are made available under the terms of the MIT License, available in # the LICENSE file of this project. @@ -232,19 +232,6 @@ def test_constraints(self): mlp2.semantic_id = semantic_id1 model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp1, mlp2]) - # AASd-120 - mlp = model.MultiLanguageProperty("mlp") - with self.assertRaises(model.AASConstraintViolation) as cm: - model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp]) - self.assertEqual("Objects with an id_short may not be added to a SubmodelElementList, got " - "MultiLanguageProperty[mlp] with id_short=mlp (Constraint AASd-120)", str(cm.exception)) - mlp.id_short = None - model.SubmodelElementList("test_list", model.MultiLanguageProperty, [mlp]) - with self.assertRaises(model.AASConstraintViolation) as cm: - mlp.id_short = "mlp" - self.assertEqual("id_short of MultiLanguageProperty[test_list[0]] cannot be set, because it is " - "contained in a SubmodelElementList[test_list] (Constraint AASd-120)", str(cm.exception)) - def test_aasd_108_add_set(self): prop = model.Property(None, model.datatypes.Int) mlp1 = model.MultiLanguageProperty(None) From 55333f6514cbf7255113b859a4c1f6e2904f0211 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:21:17 +0200 Subject: [PATCH 15/17] release.yml: Implement CI for publishing server image on DockerHub (#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 --- .github/workflows/release.yml | 43 ++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06491c0cb..7c325d303 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: jobs: sdk-publish: - # This job publishes the SDK package to PyPI + # This job publishes the package to PyPI runs-on: ubuntu-latest defaults: run: @@ -58,3 +58,44 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_ORG_TOKEN }} + + server-publish: + # This job publishes the server docker image to DockerHub + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./server + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Extract Docker image metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: eclipsebasyx/basyx-python-server + # This fetches the latest git tag and adds an additional "latest" to it, so e.g. `2.1.0,latest` + tags: | + type=semver,pattern={{version}} + type=raw,value=latest + labels: | + org.opencontainers.image.title=BaSyx Python Server + org.opencontainers.image.description=Eclipse BaSyx Python SDK - HTTP Server + org.opencontainers.image.source=https://github.com/eclipse-basyx/basyx-python-sdk/tree/main/server + org.opencontainers.image.licenses=MIT + + - name: Log in to Docker Hub + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Build and Push Docker Image + uses: docker/build-push-action@v6 + with: + context: . + file: ./server/Dockerfile # Todo: Update paths + push: true + platforms: linux/amd64,linux/arm64 # Todo: Check which platforms we should support + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} From c128a5202a77e548c7c5b69a9a63f2eaf113af52 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Mon, 20 Apr 2026 15:37:21 +0200 Subject: [PATCH 16/17] Remove multiplatform support from DockerHub publishing for now (#481) Remove multiplatform support from DockerHub publishing for now --------- Co-authored-by: Sercan Sahin --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c325d303..2f147c17a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,6 +96,5 @@ jobs: context: . file: ./server/Dockerfile # Todo: Update paths push: true - platforms: linux/amd64,linux/arm64 # Todo: Check which platforms we should support tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From f667a985278d794a35c7a3a8711273f8003d20c0 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Tue, 28 Apr 2026 11:29:17 +0200 Subject: [PATCH 17/17] CI: Temporarily disable compliance-tool tests (#76) Until we implement https://github.com/eclipse-basyx/basyx-python-sdk/issues/485 and update the `compliance-tool` properly, we should exclude it from the CI tests. --- .github/workflows/ci.yml | 59 ++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dedb827a0..2a8cf8088 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -203,36 +203,37 @@ jobs: chmod +x ./etc/scripts/set_copyright_year.sh ./etc/scripts/set_copyright_year.sh --check +# Todo: reset when the compliance-tool was updated (#485) - compliance-tool-test: - # This job runs the unittests on the python versions specified down at the matrix - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10", "3.12"] - defaults: - run: - working-directory: ./compliance_tool - - steps: - - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Install Python dependencies - # install the local sdk in editable mode so it does not get overwritten - run: | - python -m pip install --upgrade pip - python -m pip install ../sdk - python -m pip install .[dev] - - name: Test with coverage + unittest - run: | - python -m coverage run --source=aas_compliance_tool -m unittest - - name: Report test coverage - if: ${{ always() }} - run: | - python -m coverage report -m +# compliance-tool-test: +# # This job runs the unittests on the python versions specified down at the matrix +# runs-on: ubuntu-latest +# strategy: +# matrix: +# python-version: ["3.10", "3.12"] +# defaults: +# run: +# working-directory: ./compliance_tool +# +# steps: +# - uses: actions/checkout@v4 +# - name: Set up Python ${{ matrix.python-version }} +# uses: actions/setup-python@v5 +# with: +# python-version: ${{ matrix.python-version }} +# - name: Install Python dependencies +# # install the local sdk in editable mode so it does not get overwritten +# run: | +# python -m pip install --upgrade pip +# python -m pip install ../sdk +# python -m pip install .[dev] +# - name: Test with coverage + unittest +# run: | +# python -m coverage run --source=aas_compliance_tool -m unittest +# - name: Report test coverage +# if: ${{ always() }} +# run: | +# python -m coverage report -m compliance-tool-static-analysis: # This job runs static code analysis, namely pycodestyle and mypy