From aec310597ef7f530b8718c039c978fd7d0a6e8b7 Mon Sep 17 00:00:00 2001 From: Sercan Sahin Date: Sun, 29 Dec 2024 20:56:08 +0100 Subject: [PATCH 01/18] fix some typos --- CONTRIBUTING.md | 2 +- compliance_tool/README.md | 2 +- compliance_tool/aas_compliance_tool/cli.py | 2 +- server/README.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce3a4fd6b..95ec0a74f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,7 +94,7 @@ the further steps via the comments. In order to effectively communicate, there are some conventions to respect when writing commit messages and pull requests. -Similarily to when creating an issue, the commit title, as well as the PR title should +Similarly to when creating an issue, the commit title, as well as the PR title should be as short as possible, ideally 72 characters or fewer using imperative language. If a specific module is affected, please mention it at the beginning of the title. diff --git a/compliance_tool/README.md b/compliance_tool/README.md index 40face78e..185e157a0 100644 --- a/compliance_tool/README.md +++ b/compliance_tool/README.md @@ -6,7 +6,7 @@ Following functionalities are supported: * create an aasx file with xml or json files compliant to the official schema containing example Asset Administration Shell elements * check if a given xml or json file is compliant to the official schema -* check if a given xml, json or aasx file is readable even if it is not compliant to the offical schema +* check if a given xml, json or aasx file is readable even if it is not compliant to the official schema * check if the data in a given xml, json or aasx file is the same as the example data * check if two given xml, json or aasx files contain the same Asset Administration Shell elements in any order diff --git a/compliance_tool/aas_compliance_tool/cli.py b/compliance_tool/aas_compliance_tool/cli.py index cfd008140..0a929451e 100644 --- a/compliance_tool/aas_compliance_tool/cli.py +++ b/compliance_tool/aas_compliance_tool/cli.py @@ -71,7 +71,7 @@ def parse_cli_arguments() -> argparse.ArgumentParser: 'f or file_compare: checks if two given files contain the same aas elements in any order') parser.add_argument('file_1', help="path to file 1") parser.add_argument('file_2', nargs='?', default=None, help="path to file 2: is required if action f or files is " - "choosen") + "chosen") parser.add_argument('-v', '--verbose', help="Print detailed information for each check. Multiple -v options " "increase the verbosity. 1: Detailed error information, 2: Additional " "detailed success information", action='count', default=0) diff --git a/server/README.md b/server/README.md index b0e6b80db..339226c53 100644 --- a/server/README.md +++ b/server/README.md @@ -7,7 +7,7 @@ The server currently implements the following interfaces: - [Submodel Repository Service][5] It uses the [HTTP API][1] and the [AASX][7], [JSON][8], and [XML][9] Adapters of the [BaSyx Python SDK][3], to serve regarding files from a given directory. -The files are only read, chages won't persist. +The files are only read, changes won't persist. Alternatively, the container can also be told to use the [Local-File Backend][2] instead, which stores AAS and Submodels as individual JSON files and allows for persistent changes (except supplementary files, i.e. files referenced by `File` submodel elements). See [below](#options) on how to configure this. From 487250687eb58b17c097aa943e583a8313ba16bd Mon Sep 17 00:00:00 2001 From: Sercan Sahin Date: Sun, 29 Dec 2024 22:36:21 +0100 Subject: [PATCH 02/18] fix README.md --- sdk/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sdk/README.md b/sdk/README.md index fde12b465..91f62616e 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -38,19 +38,23 @@ file. ## Dependencies The BaSyx Python SDK requires the following Python packages to be installed for production usage. These dependencies are listed in -`setup.py` to be fetched automatically when installing with `pip`: +`pyproject.toml` to be fetched automatically when installing with `pip`: * `lxml` (BSD 3-clause License, using `libxml2` under MIT License) * `python-dateutil` (BSD 3-clause License) * `pyecma376-2` (Apache License v2.0) * `urllib3` (MIT License) * `Werkzeug` (BSD 3-clause License) - -Optional production usage dependencies: -* For using the Compliance Tool to validate JSON files against the JSON Schema: `jsonschema` and its -dependencies (MIT License, Apache License, PSF License) - -Development/testing/documentation/example dependencies (see `requirements.txt`): -* `jsonschema` and its dependencies (MIT License, Apache License, PSF License) +* `jsonschema` (MIT License, Apache License, PSF License) +* `types-python-dateutil` (Apache License v2.0) +* `schemathesis` (MIT License) +* `hypothesis` (MPL v2.0) +* `lxml-stubs` (Apache License) + +Development/testing/documentation/example dependencies: +* `mypy` (MIT License) +* `pycodestyle` (MIT License) +* `codeblocks` (Apache License v2.0) +* `coverage` (Apache License v2.0) Dependencies for building the documentation (see `docs/add-requirements.txt`): * `Sphinx` and its dependencies (BSD 2-clause License, MIT License, Apache License) @@ -130,7 +134,3 @@ For further examples and tutorials, check out the `basyx.aas.examples`-package. ### Documentation A detailed, complete API documentation is available on Read the Docs: https://basyx-python-sdk.readthedocs.io - -### Compliance Tool - -The compliance tool functionality moved to [github.com/rwth-iat/aas-compliance-tool](https://github.com/rwth-iat/aas-compliance-tool). From 188508ebaaba286352c56911f1d9dff2441299be Mon Sep 17 00:00:00 2001 From: Frosty2500 <125310380+Frosty2500@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:41:51 +0100 Subject: [PATCH 03/18] tutorial_serialization_deserialization: Fix missing import (#363) We add a missing import statement of `basyx.aas.adapter.json`. Fixes #352 --- sdk/basyx/aas/examples/tutorial_serialization_deserialization.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/basyx/aas/examples/tutorial_serialization_deserialization.py b/sdk/basyx/aas/examples/tutorial_serialization_deserialization.py index 6e1f6a889..6c99409a7 100755 --- a/sdk/basyx/aas/examples/tutorial_serialization_deserialization.py +++ b/sdk/basyx/aas/examples/tutorial_serialization_deserialization.py @@ -10,6 +10,7 @@ from basyx.aas import model import basyx.aas.adapter.xml +import basyx.aas.adapter.json # 'Details of the Asset Administration Shell' specifies multiple official serialization formats for AAS data. In this # tutorial, we show how the Eclipse BaSyx Python library can be used to serialize AAS objects into JSON or XML and to From de94f653a80c60e26902ef6a1495f4c69b543325 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Thu, 2 Jan 2025 09:01:30 +0100 Subject: [PATCH 04/18] README.md: Fix typo in Markdown Link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f271c4d5b..82e56055f 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ These are the currently implemented specifications: | Specification | Version | |---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Part 1: Metamodel | [v3.0.1 (01001-3-1)](https://industrialdigitaltwin.org/wp-content/uploads/2024/06/IDTA-01001-3-0-1_SpecificationAssetAdministrationShell_Part1_Metamodel.pdf) | +| 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) | | 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) | From fc99d9ccd66ee245939e23beb2ef52abfbdae037 Mon Sep 17 00:00:00 2001 From: Frosty2500 <125310380+Frosty2500@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:39:21 +0100 Subject: [PATCH 05/18] compliance-tool: Fix compliance tool imports and unitests (#356) Currently, there are several wrong imports and outdated unittests in the `compliance-tool` package. This fixes these issues. Fixes #354 --- .github/workflows/ci.yml | 14 ++++++------- compliance_tool/__init__.py => 1.0.0 | 0 compliance_tool/aas_compliance_tool/cli.py | 9 ++++---- .../compliance_check_aasx.py | 6 +++--- .../compliance_check_json.py | 4 ++-- .../compliance_check_xml.py | 4 ++-- .../aas_compliance_tool/state_manager.py | 2 +- compliance_tool/setup.py | 2 +- .../test/files/test_demo_full_example.json | 10 ++++----- .../test/files/test_demo_full_example.xml | 10 ++++----- .../aasx/data.json | 10 ++++----- ...est_demo_full_example_wrong_attribute.json | 10 ++++----- ...test_demo_full_example_wrong_attribute.xml | 10 ++++----- .../aasx/data.xml | 10 ++++----- .../aasx/data.xml | 10 ++++----- .../test/test_aas_compliance_tool.py | 21 ++++++++++++------- .../test/test_compliance_check_aasx.py | 10 +++++---- .../test/test_compliance_check_json.py | 6 +++--- .../test/test_compliance_check_xml.py | 6 +++--- compliance_tool/test/test_state_manager.py | 4 ++-- 20 files changed, 83 insertions(+), 75 deletions(-) rename compliance_tool/__init__.py => 1.0.0 (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8774ebfd..f1eb8efc2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -191,7 +191,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.8", "3.10", "3.12"] + python-version: ["3.9", "3.12"] defaults: run: working-directory: ./compliance_tool @@ -224,10 +224,10 @@ jobs: working-directory: ./compliance_tool steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ env.X_PYTHON_VERSION }} + - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} uses: actions/setup-python@v2 with: - python-version: ${{ env.X_PYTHON_VERSION }} + python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install Python dependencies run: | python -m pip install --upgrade pip @@ -249,10 +249,10 @@ jobs: working-directory: ./compliance_tool steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ env.X_PYTHON_VERSION }} + - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} uses: actions/setup-python@v2 with: - python-version: ${{ env.X_PYTHON_VERSION }} + python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install Python dependencies run: | python -m pip install --upgrade pip @@ -277,10 +277,10 @@ jobs: working-directory: ./compliance_tool steps: - uses: actions/checkout@v2 - - name: Set up Python ${{ env.X_PYTHON_VERSION }} + - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} uses: actions/setup-python@v2 with: - python-version: ${{ env.X_PYTHON_VERSION }} + python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/compliance_tool/__init__.py b/1.0.0 similarity index 100% rename from compliance_tool/__init__.py rename to 1.0.0 diff --git a/compliance_tool/aas_compliance_tool/cli.py b/compliance_tool/aas_compliance_tool/cli.py index 0a929451e..6aab09d45 100644 --- a/compliance_tool/aas_compliance_tool/cli.py +++ b/compliance_tool/aas_compliance_tool/cli.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -19,11 +19,12 @@ from basyx.aas.adapter import aasx from basyx.aas.adapter.xml import write_aas_xml_file -from basyx.aas.compliance_tool import compliance_check_xml as compliance_tool_xml, \ - compliance_check_json as compliance_tool_json, compliance_check_aasx as compliance_tool_aasx +from aas_compliance_tool import compliance_check_xml as compliance_tool_xml, \ + compliance_check_json as compliance_tool_json, \ + compliance_check_aasx as compliance_tool_aasx from basyx.aas.adapter.json import write_aas_json_file from basyx.aas.examples.data import create_example, create_example_aas_binding, TEST_PDF_FILE -from basyx.aas.compliance_tool.state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status def parse_cli_arguments() -> argparse.ArgumentParser: diff --git a/compliance_tool/aas_compliance_tool/compliance_check_aasx.py b/compliance_tool/aas_compliance_tool/compliance_check_aasx.py index 74c0a3356..d2f76a83d 100644 --- a/compliance_tool/aas_compliance_tool/compliance_check_aasx.py +++ b/compliance_tool/aas_compliance_tool/compliance_check_aasx.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -19,14 +19,14 @@ import pyecma376_2 -from . import compliance_check_json, compliance_check_xml +from aas_compliance_tool import compliance_check_json, compliance_check_xml from basyx.aas import model from basyx.aas.adapter import aasx from basyx.aas.adapter.xml import xml_deserialization from basyx.aas.adapter.json import json_deserialization from basyx.aas.examples.data import example_aas, create_example_aas_binding from basyx.aas.examples.data._helper import AASDataChecker, DataChecker -from .state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status def check_deserialization(file_path: str, state_manager: ComplianceToolStateManager, diff --git a/compliance_tool/aas_compliance_tool/compliance_check_json.py b/compliance_tool/aas_compliance_tool/compliance_check_json.py index 1469e8355..808563cb8 100644 --- a/compliance_tool/aas_compliance_tool/compliance_check_json.py +++ b/compliance_tool/aas_compliance_tool/compliance_check_json.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -20,7 +20,7 @@ from basyx.aas.adapter.json import json_deserialization from basyx.aas.examples.data import example_aas, create_example from basyx.aas.examples.data._helper import AASDataChecker -from .state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status JSON_SCHEMA_FILE = os.path.join(os.path.dirname(__file__), 'schemas/aasJSONSchema.json') diff --git a/compliance_tool/aas_compliance_tool/compliance_check_xml.py b/compliance_tool/aas_compliance_tool/compliance_check_xml.py index 51fb06068..34121a837 100644 --- a/compliance_tool/aas_compliance_tool/compliance_check_xml.py +++ b/compliance_tool/aas_compliance_tool/compliance_check_xml.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -20,7 +20,7 @@ from basyx.aas.adapter.xml import xml_deserialization from basyx.aas.examples.data import example_aas, create_example from basyx.aas.examples.data._helper import AASDataChecker -from .state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status XML_SCHEMA_FILE = os.path.join(os.path.dirname(__file__), 'schemas/aasXMLSchema.xsd') diff --git a/compliance_tool/aas_compliance_tool/state_manager.py b/compliance_tool/aas_compliance_tool/state_manager.py index 3116fe150..3201f01ab 100644 --- a/compliance_tool/aas_compliance_tool/state_manager.py +++ b/compliance_tool/aas_compliance_tool/state_manager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. diff --git a/compliance_tool/setup.py b/compliance_tool/setup.py index c214d4bcd..7401853bb 100644 --- a/compliance_tool/setup.py +++ b/compliance_tool/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2019-2021 the Eclipse BaSyx Authors +# Copyright (c) 2024-2021 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. diff --git a/compliance_tool/test/files/test_demo_full_example.json b/compliance_tool/test/files/test_demo_full_example.json index 31fde424d..68e154f73 100644 --- a/compliance_tool/test/files/test_demo_full_example.json +++ b/compliance_tool/test/files/test_demo_full_example.json @@ -499,7 +499,7 @@ }, { "language": "de", - "text": "Ein Beispiel-BillofMaterial-Submodel f\u00fcr eine Test-Anwendung" + "text": "Ein Beispiel-BillOfMaterial-Submodel f\u00fcr eine Test-Anwendung" } ], "modelType": "Submodel", @@ -1309,7 +1309,7 @@ }, { "language": "de", - "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + "text": "Beispielwert f\u00fcr ein MultiLanguageProperty-Element" } ], "valueId": { @@ -2281,7 +2281,7 @@ }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], "modelType": "MultiLanguageProperty", @@ -2301,7 +2301,7 @@ }, { "language": "de", - "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + "text": "Beispielwert f\u00fcr ein MultiLanguageProperty-Element" } ] }, @@ -2825,7 +2825,7 @@ }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], "modelType": "MultiLanguageProperty", diff --git a/compliance_tool/test/files/test_demo_full_example.xml b/compliance_tool/test/files/test_demo_full_example.xml index 39fae5599..759e3c403 100644 --- a/compliance_tool/test/files/test_demo_full_example.xml +++ b/compliance_tool/test/files/test_demo_full_example.xml @@ -486,7 +486,7 @@ de - Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + Ein Beispiel-BillOfMaterial-Submodel für eine Test-Anwendung @@ -1424,7 +1424,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2109,7 +2109,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element @@ -2128,7 +2128,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2632,7 +2632,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element diff --git a/compliance_tool/test/files/test_demo_full_example_json_aasx/aasx/data.json b/compliance_tool/test/files/test_demo_full_example_json_aasx/aasx/data.json index 7172735e6..7ddb5f17c 100644 --- a/compliance_tool/test/files/test_demo_full_example_json_aasx/aasx/data.json +++ b/compliance_tool/test/files/test_demo_full_example_json_aasx/aasx/data.json @@ -507,7 +507,7 @@ }, { "language": "de", - "text": "Ein Beispiel-BillofMaterial-Submodel f\u00fcr eine Test-Anwendung" + "text": "Ein Beispiel-BillOfMaterial-Submodel f\u00fcr eine Test-Anwendung" } ], "modelType": "Submodel", @@ -1317,7 +1317,7 @@ }, { "language": "de", - "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + "text": "Beispielwert f\u00fcr ein MultiLanguageProperty-Element" } ], "valueId": { @@ -2289,7 +2289,7 @@ }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], "modelType": "MultiLanguageProperty", @@ -2309,7 +2309,7 @@ }, { "language": "de", - "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + "text": "Beispielwert f\u00fcr ein MultiLanguageProperty-Element" } ] }, @@ -2833,7 +2833,7 @@ }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], "modelType": "MultiLanguageProperty", diff --git a/compliance_tool/test/files/test_demo_full_example_wrong_attribute.json b/compliance_tool/test/files/test_demo_full_example_wrong_attribute.json index 8f816697d..d748e7908 100644 --- a/compliance_tool/test/files/test_demo_full_example_wrong_attribute.json +++ b/compliance_tool/test/files/test_demo_full_example_wrong_attribute.json @@ -499,7 +499,7 @@ }, { "language": "de", - "text": "Ein Beispiel-BillofMaterial-Submodel f\u00fcr eine Test-Anwendung" + "text": "Ein Beispiel-BillOfMaterial-Submodel f\u00fcr eine Test-Anwendung" } ], "modelType": "Submodel", @@ -1309,7 +1309,7 @@ }, { "language": "de", - "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + "text": "Beispielwert f\u00fcr ein MultiLanguageProperty-Element" } ], "valueId": { @@ -2281,7 +2281,7 @@ }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], "modelType": "MultiLanguageProperty", @@ -2301,7 +2301,7 @@ }, { "language": "de", - "text": "Beispielswert f\u00fcr ein MulitLanguageProperty-Element" + "text": "Beispielwert f\u00fcr ein MultiLanguageProperty-Element" } ] }, @@ -2825,7 +2825,7 @@ }, { "language": "de", - "text": "Beispiel MulitLanguageProperty Element" + "text": "Beispiel MultiLanguageProperty Element" } ], "modelType": "MultiLanguageProperty", diff --git a/compliance_tool/test/files/test_demo_full_example_wrong_attribute.xml b/compliance_tool/test/files/test_demo_full_example_wrong_attribute.xml index 061ee58b6..94c47d36b 100644 --- a/compliance_tool/test/files/test_demo_full_example_wrong_attribute.xml +++ b/compliance_tool/test/files/test_demo_full_example_wrong_attribute.xml @@ -486,7 +486,7 @@ de - Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + Ein Beispiel-BillOfMaterial-Submodel für eine Test-Anwendung @@ -1424,7 +1424,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2109,7 +2109,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element @@ -2128,7 +2128,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2632,7 +2632,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element diff --git a/compliance_tool/test/files/test_demo_full_example_xml_aasx/aasx/data.xml b/compliance_tool/test/files/test_demo_full_example_xml_aasx/aasx/data.xml index c0eb40769..cb203c9d8 100644 --- a/compliance_tool/test/files/test_demo_full_example_xml_aasx/aasx/data.xml +++ b/compliance_tool/test/files/test_demo_full_example_xml_aasx/aasx/data.xml @@ -494,7 +494,7 @@ de - Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + Ein Beispiel-BillOfMaterial-Submodel für eine Test-Anwendung @@ -1432,7 +1432,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2117,7 +2117,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element @@ -2136,7 +2136,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2640,7 +2640,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element diff --git a/compliance_tool/test/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml b/compliance_tool/test/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml index 5e952db2f..7f2531f6c 100644 --- a/compliance_tool/test/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml +++ b/compliance_tool/test/files/test_demo_full_example_xml_wrong_attribute_aasx/aasx/data.xml @@ -494,7 +494,7 @@ de - Ein Beispiel-BillofMaterial-Submodel für eine Test-Anwendung + Ein Beispiel-BillOfMaterial-Submodel für eine Test-Anwendung @@ -1432,7 +1432,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2117,7 +2117,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element @@ -2136,7 +2136,7 @@ de - Beispielswert für ein MulitLanguageProperty-Element + Beispielwert für ein MultiLanguageProperty-Element @@ -2640,7 +2640,7 @@ de - Beispiel MulitLanguageProperty Element + Beispiel MultiLanguageProperty Element diff --git a/compliance_tool/test/test_aas_compliance_tool.py b/compliance_tool/test/test_aas_compliance_tool.py index 8cd3004db..972bcf366 100644 --- a/compliance_tool/test/test_aas_compliance_tool.py +++ b/compliance_tool/test/test_aas_compliance_tool.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -13,8 +13,6 @@ import io import tempfile - -import basyx.aas.compliance_tool from basyx.aas import model from basyx.aas.adapter import aasx from basyx.aas.adapter.json import read_aas_json_file @@ -25,14 +23,21 @@ def _run_compliance_tool(*compliance_tool_args, **kwargs) -> subprocess.CompletedProcess: """ - This function runs the compliance tool using subprocess.run() while adjusting the PYTHONPATH environment variable - and setting the stdout and stderr parameters of subprocess.run() to PIPE. + This function runs the compliance tool using subprocess.run() + and sets the stdout and stderr parameters of subprocess.run() to PIPE. Positional arguments are passed to the compliance tool, while keyword arguments are passed to subprocess.run(). """ env = os.environ.copy() - env['PYTHONPATH'] = "{}:{}".format(os.environ.get('PYTHONPATH', ''), - os.path.join(os.path.dirname(basyx.__file__), os.pardir)) - compliance_tool_path = os.path.join(os.path.dirname(basyx.aas.compliance_tool.__file__), 'cli.py') + parent_dir = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + 'aas_compliance_tool' + ) + env["PYTHONPATH"] = parent_dir + os.pathsep + env.get("PYTHONPATH", "") + compliance_tool_path = os.path.join( + os.path.dirname(os.path.dirname(__file__)), + 'aas_compliance_tool', + 'cli.py' + ) return subprocess.run([sys.executable, compliance_tool_path] + list(compliance_tool_args), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, **kwargs) diff --git a/compliance_tool/test/test_compliance_check_aasx.py b/compliance_tool/test/test_compliance_check_aasx.py index 78d9e04b7..fa2e15b29 100644 --- a/compliance_tool/test/test_compliance_check_aasx.py +++ b/compliance_tool/test/test_compliance_check_aasx.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -7,8 +7,8 @@ import os import unittest -from basyx.aas.compliance_tool import compliance_check_aasx as compliance_tool -from basyx.aas.compliance_tool.state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool import compliance_check_aasx as compliance_tool +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status class ComplianceToolAASXTest(unittest.TestCase): @@ -20,7 +20,9 @@ def test_check_deserialization(self) -> None: compliance_tool.check_deserialization(file_path_1, manager) self.assertEqual(2, len(manager.steps)) self.assertEqual(Status.FAILED, manager.steps[0].status) - self.assertIn("is not a valid ECMA376-2 (OPC) file", manager.format_step(0, verbose_level=1)) + # we should expect a FileNotFound error here since the file does not exist and that is the first error + # aasx.py will throw if you try to open a file that does not exist. + self.assertIn("No such file or directory:", manager.format_step(0, verbose_level=1)) self.assertEqual(Status.NOT_EXECUTED, manager.steps[1].status) # Todo add more tests for checking wrong aasx files diff --git a/compliance_tool/test/test_compliance_check_json.py b/compliance_tool/test/test_compliance_check_json.py index b6201d108..651895b9c 100644 --- a/compliance_tool/test/test_compliance_check_json.py +++ b/compliance_tool/test/test_compliance_check_json.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -7,8 +7,8 @@ import os import unittest -import basyx.aas.compliance_tool.compliance_check_json as compliance_tool -from basyx.aas.compliance_tool.state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool import compliance_check_json as compliance_tool +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status class ComplianceToolJsonTest(unittest.TestCase): diff --git a/compliance_tool/test/test_compliance_check_xml.py b/compliance_tool/test/test_compliance_check_xml.py index a1658e508..5afe06870 100644 --- a/compliance_tool/test/test_compliance_check_xml.py +++ b/compliance_tool/test/test_compliance_check_xml.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -7,8 +7,8 @@ import os import unittest -import basyx.aas.compliance_tool.compliance_check_xml as compliance_tool -from basyx.aas.compliance_tool.state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool import compliance_check_xml as compliance_tool +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status class ComplianceToolXmlTest(unittest.TestCase): diff --git a/compliance_tool/test/test_state_manager.py b/compliance_tool/test/test_state_manager.py index fc1c8260e..398f08e13 100644 --- a/compliance_tool/test/test_state_manager.py +++ b/compliance_tool/test/test_state_manager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2020 the Eclipse BaSyx Authors +# Copyright (c) 2024 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. @@ -7,7 +7,7 @@ import logging import unittest -from basyx.aas.compliance_tool.state_manager import ComplianceToolStateManager, Status +from aas_compliance_tool.state_manager import ComplianceToolStateManager, Status from basyx.aas.examples.data._helper import DataChecker From 886dcc0525ba2288f12f81a868b019ffeaa52d86 Mon Sep 17 00:00:00 2001 From: Julian Vogel Date: Wed, 15 Jan 2025 11:17:29 +0100 Subject: [PATCH 06/18] aasx.adapter: Fix `semantic_id` type deserialization of `ModelReference` (#337) Previously, if the `semantic_id` was a `ModelReference`, it very often had the generic `type` "`model.Referable`" instead of the actual type of the object it points to. This lead to a bug in the AASX writer, where `ConceptDescription`s were not written to the AASX, even though they existed in the `ObjectStore`. This fixes this problem by tackling three separate points: 1. In `json_deserialization.py`, we now infer the `type` of the `ModelReference` via the Reference's last `Key`. This is more of a hotfix and issue #367 tracks the creation of a better solution. 2. In `aasx.py`, an unneccessary `logger.info` call is removed, that previously cluttered the output of the writer if a `semantic_id` was not pointing to a `ConceptDescription`, which is not something worth noting. Furthermore, we improve other log messages. 3. In `examples.data._helper`, we improve the test for `semantic_id` equality, namely by comparing the `ModelReference`'s attributes explicitly, when it happens to be one, instead of relying on simple string comparision. --- sdk/basyx/aas/adapter/aasx.py | 8 +++++--- sdk/basyx/aas/adapter/json/json_deserialization.py | 10 ++++++++-- sdk/basyx/aas/examples/data/_helper.py | 12 ++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/sdk/basyx/aas/adapter/aasx.py b/sdk/basyx/aas/adapter/aasx.py index 1c27640fa..88c6969a6 100644 --- a/sdk/basyx/aas/adapter/aasx.py +++ b/sdk/basyx/aas/adapter/aasx.py @@ -402,17 +402,19 @@ def write_aas(self, concept_descriptions: List[model.ConceptDescription] = [] for identifiable in objects_to_be_written: for semantic_id in traversal.walk_semantic_ids_recursive(identifiable): + if isinstance(semantic_id, model.ExternalReference): + continue if not isinstance(semantic_id, model.ModelReference) \ or semantic_id.type is not model.ConceptDescription: - logger.info("semanticId %s does not reference a ConceptDescription.", str(semantic_id)) continue try: cd = semantic_id.resolve(object_store) except KeyError: - logger.info("ConceptDescription for semanticId %s not found in object store.", str(semantic_id)) + logger.warning("ConceptDescription for semanticId %s not found in object store. Skipping it.", + str(semantic_id)) continue except model.UnexpectedTypeError as e: - logger.error("semanticId %s resolves to %s, which is not a ConceptDescription", + logger.error("semanticId %s resolves to %s, which is not a ConceptDescription. Skipping it.", str(semantic_id), e.value) continue concept_descriptions.append(cd) diff --git a/sdk/basyx/aas/adapter/json/json_deserialization.py b/sdk/basyx/aas/adapter/json/json_deserialization.py index 455a309e6..c1ce35fef 100644 --- a/sdk/basyx/aas/adapter/json/json_deserialization.py +++ b/sdk/basyx/aas/adapter/json/json_deserialization.py @@ -340,10 +340,16 @@ def _construct_model_reference(cls, dct: Dict[str, object], type_: Type[T], obje if reference_type is not model.ModelReference: raise ValueError(f"Expected a reference of type {model.ModelReference}, got {reference_type}!") keys = [cls._construct_key(key_data) for key_data in _get_ts(dct, "keys", list)] - if keys and not issubclass(KEY_TYPES_CLASSES_INVERSE.get(keys[-1].type, type(None)), type_): + last_key_type = KEY_TYPES_CLASSES_INVERSE.get(keys[-1].type, type(None)) + if keys and not issubclass(last_key_type, type_): logger.warning("type %s of last key of reference to %s does not match reference type %s", keys[-1].type.name, " / ".join(str(k) for k in keys), type_.__name__) - return object_class(tuple(keys), type_, cls._construct_reference(_get_ts(dct, 'referredSemanticId', dict)) + # Infer type the model refence points to using `last_key_type` instead of `type_`. + # `type_` is often a `model.Referable`, which is more abstract than e.g. a `model.ConceptDescription`, + # leading to information loss while deserializing. + # TODO Remove this fix, when this function is called with correct `type_` + return object_class(tuple(keys), last_key_type, + cls._construct_reference(_get_ts(dct, 'referredSemanticId', dict)) if 'referredSemanticId' in dct else None) @classmethod diff --git a/sdk/basyx/aas/examples/data/_helper.py b/sdk/basyx/aas/examples/data/_helper.py index 231ba2ade..4f75e8732 100644 --- a/sdk/basyx/aas/examples/data/_helper.py +++ b/sdk/basyx/aas/examples/data/_helper.py @@ -213,6 +213,18 @@ def _check_has_semantics_equal(self, object_: model.HasSemantics, expected_objec :return: The value of expression to be used in control statements """ self.check_attribute_equal(object_, "semantic_id", expected_object.semantic_id) + if isinstance(expected_object.semantic_id, model.ModelReference) and self.check( + isinstance(object_.semantic_id, model.ModelReference), + "{} must be a ModelReference".format(repr(object_)), + ): # type: ignore + self.check( + object_.semantic_id.type == expected_object.semantic_id.type, # type: ignore + "ModelReference type {} of {} must be equal to {}".format( + object_.semantic_id.type, # type: ignore + repr(object_), + expected_object.semantic_id.type, + ), + ) for suppl_semantic_id in expected_object.supplemental_semantic_id: given_semantic_id = self._find_reference(suppl_semantic_id, object_.supplemental_semantic_id) self.check(given_semantic_id is not None, f"{object_!r} must have supplementalSemanticId", From f858e75f5c3df1c19cfaa672204e8472a113927f Mon Sep 17 00:00:00 2001 From: s-heppner Date: Mon, 20 Jan 2025 15:57:53 +0100 Subject: [PATCH 07/18] sdk: Update version of pyecma dependency in pyproject.toml This updates the minimum version of the dependency `pyecma376` in the `pyproject.toml`, ensuring that our AASX files allow for spaces in file names. Fixes #236 --- sdk/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/pyproject.toml b/sdk/pyproject.toml index 7722b16ef..01f8575d9 100644 --- a/sdk/pyproject.toml +++ b/sdk/pyproject.toml @@ -40,7 +40,7 @@ dependencies = [ "lxml>=4.2,<5", "python-dateutil>=2.8,<3", "types-python-dateutil", - "pyecma376-2>=0.2.4", + "pyecma376-2>=1.0.1", "urllib3>=1.26,<3", "Werkzeug>=3.0.3,<4", "schemathesis~=3.7", From dad15ac9108ced81468c121d11151e785f84f5cd Mon Sep 17 00:00:00 2001 From: Julian Vogel Date: Mon, 20 Jan 2025 16:13:17 +0100 Subject: [PATCH 08/18] sdk: Move testing depencies to dev section in pyproject.toml (#369) Previously, some `sdk` dependencies, that are only necessary for testing were included in the mandatory dependencies. For improving package footprint, these are moved into the `[dev]` section of optional dependencies in the `pyproject.toml`. --------- Co-authored-by: s-heppner --- sdk/README.md | 10 +++++----- sdk/pyproject.toml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sdk/README.md b/sdk/README.md index 91f62616e..f63f7afcb 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -44,17 +44,17 @@ The BaSyx Python SDK requires the following Python packages to be installed for * `pyecma376-2` (Apache License v2.0) * `urllib3` (MIT License) * `Werkzeug` (BSD 3-clause License) -* `jsonschema` (MIT License, Apache License, PSF License) -* `types-python-dateutil` (Apache License v2.0) -* `schemathesis` (MIT License) -* `hypothesis` (MPL v2.0) -* `lxml-stubs` (Apache License) Development/testing/documentation/example dependencies: * `mypy` (MIT License) * `pycodestyle` (MIT License) * `codeblocks` (Apache License v2.0) * `coverage` (Apache License v2.0) +* `jsonschema` (MIT License, Apache License, PSF License) +* `schemathesis` (MIT License) +* `hypothesis` (MPL v2.0) +* `lxml-stubs` (Apache License) +* `types-python-dateutil` (Apache License v2.0) Dependencies for building the documentation (see `docs/add-requirements.txt`): * `Sphinx` and its dependencies (BSD 2-clause License, MIT License, Apache License) diff --git a/sdk/pyproject.toml b/sdk/pyproject.toml index 01f8575d9..baaf6ff05 100644 --- a/sdk/pyproject.toml +++ b/sdk/pyproject.toml @@ -36,16 +36,11 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "jsonschema~=4.7", "lxml>=4.2,<5", "python-dateutil>=2.8,<3", - "types-python-dateutil", "pyecma376-2>=1.0.1", "urllib3>=1.26,<3", "Werkzeug>=3.0.3,<4", - "schemathesis~=3.7", - "hypothesis~=6.13", - "lxml-stubs~=0.5.1", ] [project.optional-dependencies] @@ -54,6 +49,11 @@ dev = [ "pycodestyle", "codeblocks", "coverage", + "schemathesis~=3.7", + "jsonschema~=4.7", + "hypothesis~=6.13", + "types-python-dateutil", + "lxml-stubs~=0.5.1", ] [project.urls] From da1d5b617489711a72015e9d5be543ebbfa5dd44 Mon Sep 17 00:00:00 2001 From: Igor Garmaev <56840636+zrgt@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:30:41 +0100 Subject: [PATCH 09/18] basyx.provider: Add SetObjectStore to provider (#340) This adds a new `SetObjectStore` that is backed by a set. Its main advantage is that it does not have the problem with not updated `Identifier`s that the `DictObjectStore` has (See #216). We make sure to document the differences between `DictObjectStore` and `SetObjectStore` in their respective class docstrings. --- sdk/basyx/aas/model/provider.py | 69 ++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/sdk/basyx/aas/model/provider.py b/sdk/basyx/aas/model/provider.py index 0d4430de5..b95363315 100644 --- a/sdk/basyx/aas/model/provider.py +++ b/sdk/basyx/aas/model/provider.py @@ -11,7 +11,7 @@ """ import abc -from typing import MutableSet, Iterator, Generic, TypeVar, Dict, List, Optional, Iterable +from typing import MutableSet, Iterator, Generic, TypeVar, Dict, List, Optional, Iterable, Set from .base import Identifier, Identifiable @@ -84,6 +84,15 @@ class DictObjectStore(AbstractObjectStore[_IT], Generic[_IT]): """ A local in-memory object store for :class:`~basyx.aas.model.base.Identifiable` objects, backed by a dict, mapping :class:`~basyx.aas.model.base.Identifier` → :class:`~basyx.aas.model.base.Identifiable` + + .. note:: + The `DictObjectStore` provides efficient retrieval of objects by their :class:`~basyx.aas.model.base.Identifier` + However, since object stores are not referenced via the parent attribute, the mapping is not updated + if the :class:`~basyx.aas.model.base.Identifier` of an :class:`~basyx.aas.model.base.Identifiable` changes. + For more details, see [issue #216](https://github.com/eclipse-basyx/basyx-python-sdk/issues/216). + As a result, the `DictObjectStore` is unsuitable for storing objects whose + :class:`~basyx.aas.model.base.Identifier` may change. + In such cases, consider using a :class:`~.SetObjectStore` instead. """ def __init__(self, objects: Iterable[_IT] = ()) -> None: self._backend: Dict[Identifier, _IT] = {} @@ -117,6 +126,64 @@ def __iter__(self) -> Iterator[_IT]: return iter(self._backend.values()) +class SetObjectStore(AbstractObjectStore[_IT], Generic[_IT]): + """ + A local in-memory object store for :class:`~basyx.aas.model.base.Identifiable` objects, backed by a set + + .. note:: + The `SetObjectStore` is slower than the `DictObjectStore` for retrieval of objects, because it has to iterate + over all objects to find the one with the correct :class:`~basyx.aas.model.base.Identifier`. + On the other hand, the `SetObjectStore` is more secure, because it is less affected by changes in the + :class:`~basyx.aas.model.base.Identifier` of an :class:`~basyx.aas.model.base.Identifiable` object. + Therefore, the `SetObjectStore` is suitable for storing objects whose :class:`~basyx.aas.model.base.Identifier` + may change. + """ + def __init__(self, objects: Iterable[_IT] = ()) -> None: + self._backend: Set[_IT] = set() + for x in objects: + self.add(x) + + def get_identifiable(self, identifier: Identifier) -> _IT: + for x in self._backend: + if x.id == identifier: + return x + raise KeyError(identifier) + + def add(self, x: _IT) -> None: + if x in self: + # Object is already in store + return + try: + self.get_identifiable(x.id) + except KeyError: + self._backend.add(x) + else: + raise KeyError(f"Identifiable object with same id {x.id} is already stored in this store") + + def discard(self, x: _IT) -> None: + self._backend.discard(x) + + def remove(self, x: _IT) -> None: + self._backend.remove(x) + + def __contains__(self, x: object) -> bool: + if isinstance(x, Identifier): + try: + self.get_identifiable(x) + return True + except KeyError: + return False + if not isinstance(x, Identifiable): + return False + return x in self._backend + + def __len__(self) -> int: + return len(self._backend) + + def __iter__(self) -> Iterator[_IT]: + return iter(self._backend) + + class ObjectProviderMultiplexer(AbstractObjectProvider): """ A multiplexer for Providers of :class:`~basyx.aas.model.base.Identifiable` objects. From 6dc956d52ab1403efe85e4704ef4f268448e575d Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Mon, 17 Feb 2025 10:31:58 +0100 Subject: [PATCH 10/18] scripts.set_copyright_year: Add a CI check to ensure the copyright is updated (#344) Previously, there was no check if the copyright statement on top of each file (due to the MIT license) was up to date. This adapts our `update_copyright_year.sh` script with a checking mode to determine if any file needs adapting and then adds this check to the CI. At the same time, this also updates all necessary files to the year 2025. Fixes #260 Fixes #331 --------- Co-authored-by: s-heppner --- .github/workflows/ci.yml | 16 +++++++++ compliance_tool/aas_compliance_tool/cli.py | 2 +- .../compliance_check_aasx.py | 2 +- .../compliance_check_json.py | 2 +- .../compliance_check_xml.py | 2 +- .../aas_compliance_tool/state_manager.py | 2 +- compliance_tool/setup.py | 2 +- .../test/test_aas_compliance_tool.py | 2 +- .../test/test_compliance_check_aasx.py | 2 +- .../test/test_compliance_check_json.py | 2 +- .../test/test_compliance_check_xml.py | 2 +- compliance_tool/test/test_state_manager.py | 2 +- etc/scripts/set_copyright_year.sh | 33 +++++++++++++++++-- sdk/basyx/aas/adapter/_generic.py | 2 +- sdk/basyx/aas/adapter/aasx.py | 2 +- .../aas/adapter/json/json_deserialization.py | 2 +- .../aas/adapter/json/json_serialization.py | 2 +- .../aas/adapter/xml/xml_deserialization.py | 2 +- .../aas/adapter/xml/xml_serialization.py | 2 +- sdk/basyx/aas/backend/backends.py | 2 +- sdk/basyx/aas/backend/couchdb.py | 2 +- sdk/basyx/aas/backend/local_file.py | 2 +- sdk/basyx/aas/examples/data/_helper.py | 2 +- sdk/basyx/aas/examples/data/example_aas.py | 2 +- .../data/example_aas_mandatory_attributes.py | 2 +- .../data/example_aas_missing_attributes.py | 2 +- .../data/example_submodel_template.py | 2 +- sdk/basyx/aas/model/_string_constraints.py | 2 +- sdk/basyx/aas/model/aas.py | 2 +- sdk/basyx/aas/model/base.py | 2 +- sdk/basyx/aas/model/concept.py | 2 +- sdk/basyx/aas/model/datatypes.py | 2 +- sdk/basyx/aas/model/provider.py | 2 +- sdk/basyx/aas/util/identification.py | 2 +- sdk/basyx/aas/util/traversal.py | 2 +- sdk/test/_helper/setup_testdb.py | 2 +- sdk/test/adapter/aasx/test_aasx.py | 2 +- .../adapter/json/test_json_deserialization.py | 2 +- .../adapter/json/test_json_serialization.py | 2 +- ...test_json_serialization_deserialization.py | 2 +- .../adapter/xml/test_xml_deserialization.py | 2 +- .../adapter/xml/test_xml_serialization.py | 2 +- .../test_xml_serialization_deserialization.py | 2 +- sdk/test/backend/test_backends.py | 2 +- sdk/test/backend/test_couchdb.py | 2 +- sdk/test/backend/test_local_file.py | 2 +- sdk/test/examples/test_examples.py | 2 +- sdk/test/examples/test_helpers.py | 2 +- sdk/test/examples/test_tutorials.py | 2 +- sdk/test/model/test_aas.py | 2 +- sdk/test/model/test_base.py | 2 +- sdk/test/model/test_concept.py | 2 +- sdk/test/model/test_datatypes.py | 2 +- sdk/test/model/test_provider.py | 2 +- sdk/test/model/test_string_constraints.py | 2 +- sdk/test/model/test_submodel.py | 2 +- sdk/test/util/test_identification.py | 2 +- 57 files changed, 102 insertions(+), 57 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1eb8efc2..34470e8f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -185,6 +185,22 @@ jobs: run: | python -m build + repository-check-copyright: + # This job checks that the copyright year in the header of all files is up to date + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Ensure full history is available + - name: Install required dependencies + run: | + sudo apt-get update + sudo apt-get install -y bash git + - name: Run copyright check + run: | + chmod +x ./etc/scripts/set_copyright_year.sh + ./etc/scripts/set_copyright_year.sh --check + compliance-tool-test: # This job runs the unittests on the python versions specified down at the matrix diff --git a/compliance_tool/aas_compliance_tool/cli.py b/compliance_tool/aas_compliance_tool/cli.py index 6aab09d45..3ffd7d219 100644 --- a/compliance_tool/aas_compliance_tool/cli.py +++ b/compliance_tool/aas_compliance_tool/cli.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/aas_compliance_tool/compliance_check_aasx.py b/compliance_tool/aas_compliance_tool/compliance_check_aasx.py index d2f76a83d..9dfbb982c 100644 --- a/compliance_tool/aas_compliance_tool/compliance_check_aasx.py +++ b/compliance_tool/aas_compliance_tool/compliance_check_aasx.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/aas_compliance_tool/compliance_check_json.py b/compliance_tool/aas_compliance_tool/compliance_check_json.py index 808563cb8..2050f570c 100644 --- a/compliance_tool/aas_compliance_tool/compliance_check_json.py +++ b/compliance_tool/aas_compliance_tool/compliance_check_json.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/aas_compliance_tool/compliance_check_xml.py b/compliance_tool/aas_compliance_tool/compliance_check_xml.py index 34121a837..6d4e10c55 100644 --- a/compliance_tool/aas_compliance_tool/compliance_check_xml.py +++ b/compliance_tool/aas_compliance_tool/compliance_check_xml.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/aas_compliance_tool/state_manager.py b/compliance_tool/aas_compliance_tool/state_manager.py index 3201f01ab..33153038f 100644 --- a/compliance_tool/aas_compliance_tool/state_manager.py +++ b/compliance_tool/aas_compliance_tool/state_manager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/setup.py b/compliance_tool/setup.py index 7401853bb..eb143df75 100644 --- a/compliance_tool/setup.py +++ b/compliance_tool/setup.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2024-2021 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/test/test_aas_compliance_tool.py b/compliance_tool/test/test_aas_compliance_tool.py index 972bcf366..cb631cf9c 100644 --- a/compliance_tool/test/test_aas_compliance_tool.py +++ b/compliance_tool/test/test_aas_compliance_tool.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/test/test_compliance_check_aasx.py b/compliance_tool/test/test_compliance_check_aasx.py index fa2e15b29..953d4e35e 100644 --- a/compliance_tool/test/test_compliance_check_aasx.py +++ b/compliance_tool/test/test_compliance_check_aasx.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/test/test_compliance_check_json.py b/compliance_tool/test/test_compliance_check_json.py index 651895b9c..c738c0f13 100644 --- a/compliance_tool/test/test_compliance_check_json.py +++ b/compliance_tool/test/test_compliance_check_json.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/test/test_compliance_check_xml.py b/compliance_tool/test/test_compliance_check_xml.py index 5afe06870..63089e186 100644 --- a/compliance_tool/test/test_compliance_check_xml.py +++ b/compliance_tool/test/test_compliance_check_xml.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/compliance_tool/test/test_state_manager.py b/compliance_tool/test/test_state_manager.py index 398f08e13..7654203d1 100644 --- a/compliance_tool/test/test_state_manager.py +++ b/compliance_tool/test/test_state_manager.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/etc/scripts/set_copyright_year.sh b/etc/scripts/set_copyright_year.sh index 5ff1fd5f9..de6c97eea 100755 --- a/etc/scripts/set_copyright_year.sh +++ b/etc/scripts/set_copyright_year.sh @@ -9,7 +9,36 @@ # # The script will check the first two lines for a copyright # notice (in case the first line is a shebang). +# +# Run this script with --check to have it raise an error if it +# would change anything. + + +# Set CHECK_MODE based on whether --check is passed + CHECK_MODE=false + if [[ "$1" == "--check" ]]; then + CHECK_MODE=true + shift # Remove --check from the arguments + fi while read -rd $'\0' year file; do - sed -i "1,2s/^\(# Copyright (c) \)[[:digit:]]\{4,\}/\1$year/" "$file" -done < <(git ls-files -z "$@" | xargs -0I{} git log -1 -z --format="%ad {}" --date="format:%Y" "{}") + + # Extract the first year from the copyright notice + current_year=$(sed -n '1,2s/^\(# Copyright (c) \)\([[:digit:]]\{4,\}\).*/\2/p' "$file") + + # Skip the file if no year is found + if [[ -z "$current_year" ]]; then + continue + fi + + if $CHECK_MODE && [[ "$current_year" != "$year" ]]; then + echo "Error: Copyright year mismatch in file $file. Expected $year, found $current_year." + exit 1 + fi + + if ! $CHECK_MODE && [[ "$current_year" != "$year" ]]; then + sed -i "1,2s/^\(# Copyright (c) \)[[:digit:]]\{4,\}/\1$year/" "$file" + echo "Updated copyright year in $file" + fi +done < <(git ls-files -z "$@" | xargs -0I{} git log -1 -z --format="%cd {}" --date="format:%Y" -- "{}") + diff --git a/sdk/basyx/aas/adapter/_generic.py b/sdk/basyx/aas/adapter/_generic.py index 6a37c7412..79c98fc8c 100644 --- a/sdk/basyx/aas/adapter/_generic.py +++ b/sdk/basyx/aas/adapter/_generic.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/adapter/aasx.py b/sdk/basyx/aas/adapter/aasx.py index 88c6969a6..0b66e533e 100644 --- a/sdk/basyx/aas/adapter/aasx.py +++ b/sdk/basyx/aas/adapter/aasx.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/adapter/json/json_deserialization.py b/sdk/basyx/aas/adapter/json/json_deserialization.py index c1ce35fef..78e3713f5 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) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/adapter/json/json_serialization.py b/sdk/basyx/aas/adapter/json/json_serialization.py index 8c6a671f1..f7d6626eb 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) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/adapter/xml/xml_deserialization.py b/sdk/basyx/aas/adapter/xml/xml_deserialization.py index ab78d3c2e..4063b8df7 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) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/adapter/xml/xml_serialization.py b/sdk/basyx/aas/adapter/xml/xml_serialization.py index 2620dad84..7e6585cea 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) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/backend/backends.py b/sdk/basyx/aas/backend/backends.py index d921a52d5..31be12628 100644 --- a/sdk/basyx/aas/backend/backends.py +++ b/sdk/basyx/aas/backend/backends.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/backend/couchdb.py b/sdk/basyx/aas/backend/couchdb.py index 43428ae9d..4b6f43611 100644 --- a/sdk/basyx/aas/backend/couchdb.py +++ b/sdk/basyx/aas/backend/couchdb.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/backend/local_file.py b/sdk/basyx/aas/backend/local_file.py index 3f6bcb8dc..ec0757375 100644 --- a/sdk/basyx/aas/backend/local_file.py +++ b/sdk/basyx/aas/backend/local_file.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/examples/data/_helper.py b/sdk/basyx/aas/examples/data/_helper.py index 4f75e8732..a4c3edfce 100644 --- a/sdk/basyx/aas/examples/data/_helper.py +++ b/sdk/basyx/aas/examples/data/_helper.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/examples/data/example_aas.py b/sdk/basyx/aas/examples/data/example_aas.py index c1c0db426..e093c603a 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) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/examples/data/example_aas_mandatory_attributes.py b/sdk/basyx/aas/examples/data/example_aas_mandatory_attributes.py index d86f6f5fb..a18f3cbc6 100644 --- a/sdk/basyx/aas/examples/data/example_aas_mandatory_attributes.py +++ b/sdk/basyx/aas/examples/data/example_aas_mandatory_attributes.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/examples/data/example_aas_missing_attributes.py b/sdk/basyx/aas/examples/data/example_aas_missing_attributes.py index 45f3df3c2..83232914a 100644 --- a/sdk/basyx/aas/examples/data/example_aas_missing_attributes.py +++ b/sdk/basyx/aas/examples/data/example_aas_missing_attributes.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/examples/data/example_submodel_template.py b/sdk/basyx/aas/examples/data/example_submodel_template.py index 6f5a7789b..358e06b05 100644 --- a/sdk/basyx/aas/examples/data/example_submodel_template.py +++ b/sdk/basyx/aas/examples/data/example_submodel_template.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/model/_string_constraints.py b/sdk/basyx/aas/model/_string_constraints.py index aa9833cf2..376f76b0e 100644 --- a/sdk/basyx/aas/model/_string_constraints.py +++ b/sdk/basyx/aas/model/_string_constraints.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/model/aas.py b/sdk/basyx/aas/model/aas.py index 684a1ff06..4a9fb4640 100644 --- a/sdk/basyx/aas/model/aas.py +++ b/sdk/basyx/aas/model/aas.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/model/base.py b/sdk/basyx/aas/model/base.py index a1dc9f1a9..a93e3cb59 100644 --- a/sdk/basyx/aas/model/base.py +++ b/sdk/basyx/aas/model/base.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/model/concept.py b/sdk/basyx/aas/model/concept.py index 6ee0155b9..a9cbd1a33 100644 --- a/sdk/basyx/aas/model/concept.py +++ b/sdk/basyx/aas/model/concept.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/model/datatypes.py b/sdk/basyx/aas/model/datatypes.py index 24a7fb261..d5acc6d45 100644 --- a/sdk/basyx/aas/model/datatypes.py +++ b/sdk/basyx/aas/model/datatypes.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/model/provider.py b/sdk/basyx/aas/model/provider.py index b95363315..ac50d33da 100644 --- a/sdk/basyx/aas/model/provider.py +++ b/sdk/basyx/aas/model/provider.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/util/identification.py b/sdk/basyx/aas/util/identification.py index c3647ef90..74cccd99a 100644 --- a/sdk/basyx/aas/util/identification.py +++ b/sdk/basyx/aas/util/identification.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/basyx/aas/util/traversal.py b/sdk/basyx/aas/util/traversal.py index 43a55af44..0b288ddf7 100644 --- a/sdk/basyx/aas/util/traversal.py +++ b/sdk/basyx/aas/util/traversal.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/_helper/setup_testdb.py b/sdk/test/_helper/setup_testdb.py index d668ac865..20f56c4d9 100755 --- a/sdk/test/_helper/setup_testdb.py +++ b/sdk/test/_helper/setup_testdb.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/aasx/test_aasx.py b/sdk/test/adapter/aasx/test_aasx.py index 9f1bb5ebb..a83c60186 100644 --- a/sdk/test/adapter/aasx/test_aasx.py +++ b/sdk/test/adapter/aasx/test_aasx.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/json/test_json_deserialization.py b/sdk/test/adapter/json/test_json_deserialization.py index 28da288cd..9272bdf98 100644 --- a/sdk/test/adapter/json/test_json_deserialization.py +++ b/sdk/test/adapter/json/test_json_deserialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/json/test_json_serialization.py b/sdk/test/adapter/json/test_json_serialization.py index 01bc65c95..8e9bc8d01 100644 --- a/sdk/test/adapter/json/test_json_serialization.py +++ b/sdk/test/adapter/json/test_json_serialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/json/test_json_serialization_deserialization.py b/sdk/test/adapter/json/test_json_serialization_deserialization.py index 9b016e17a..e33921a21 100644 --- a/sdk/test/adapter/json/test_json_serialization_deserialization.py +++ b/sdk/test/adapter/json/test_json_serialization_deserialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/xml/test_xml_deserialization.py b/sdk/test/adapter/xml/test_xml_deserialization.py index e62ebaa08..331ad98c5 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) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/xml/test_xml_serialization.py b/sdk/test/adapter/xml/test_xml_serialization.py index 11328f62f..e07e10255 100644 --- a/sdk/test/adapter/xml/test_xml_serialization.py +++ b/sdk/test/adapter/xml/test_xml_serialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/adapter/xml/test_xml_serialization_deserialization.py b/sdk/test/adapter/xml/test_xml_serialization_deserialization.py index 2e06c44d8..7a4f5c12d 100644 --- a/sdk/test/adapter/xml/test_xml_serialization_deserialization.py +++ b/sdk/test/adapter/xml/test_xml_serialization_deserialization.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/backend/test_backends.py b/sdk/test/backend/test_backends.py index a7f025558..e0beee8f8 100644 --- a/sdk/test/backend/test_backends.py +++ b/sdk/test/backend/test_backends.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/backend/test_couchdb.py b/sdk/test/backend/test_couchdb.py index 5e6c2fbe4..89fe992de 100644 --- a/sdk/test/backend/test_couchdb.py +++ b/sdk/test/backend/test_couchdb.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/backend/test_local_file.py b/sdk/test/backend/test_local_file.py index 4a8186ac3..22aaa3155 100644 --- a/sdk/test/backend/test_local_file.py +++ b/sdk/test/backend/test_local_file.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/examples/test_examples.py b/sdk/test/examples/test_examples.py index cacf9395c..5695e3b94 100644 --- a/sdk/test/examples/test_examples.py +++ b/sdk/test/examples/test_examples.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/examples/test_helpers.py b/sdk/test/examples/test_helpers.py index 754d5cdfb..faca8602b 100644 --- a/sdk/test/examples/test_helpers.py +++ b/sdk/test/examples/test_helpers.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/examples/test_tutorials.py b/sdk/test/examples/test_tutorials.py index b82c3bf7b..2b5dbe54e 100644 --- a/sdk/test/examples/test_tutorials.py +++ b/sdk/test/examples/test_tutorials.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_aas.py b/sdk/test/model/test_aas.py index 27ce13b4d..3b974c04f 100644 --- a/sdk/test/model/test_aas.py +++ b/sdk/test/model/test_aas.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_base.py b/sdk/test/model/test_base.py index 3cf7ea2d0..1e0432a58 100644 --- a/sdk/test/model/test_base.py +++ b/sdk/test/model/test_base.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_concept.py b/sdk/test/model/test_concept.py index c8bfefce9..94fc497b8 100644 --- a/sdk/test/model/test_concept.py +++ b/sdk/test/model/test_concept.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_datatypes.py b/sdk/test/model/test_datatypes.py index 8021414db..b83c5e5fb 100644 --- a/sdk/test/model/test_datatypes.py +++ b/sdk/test/model/test_datatypes.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_provider.py b/sdk/test/model/test_provider.py index 549232cc3..68fb01cff 100644 --- a/sdk/test/model/test_provider.py +++ b/sdk/test/model/test_provider.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_string_constraints.py b/sdk/test/model/test_string_constraints.py index 5adb15523..55d5789f5 100644 --- a/sdk/test/model/test_string_constraints.py +++ b/sdk/test/model/test_string_constraints.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/model/test_submodel.py b/sdk/test/model/test_submodel.py index 15746bd5d..37a5792df 100644 --- a/sdk/test/model/test_submodel.py +++ b/sdk/test/model/test_submodel.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. diff --git a/sdk/test/util/test_identification.py b/sdk/test/util/test_identification.py index 9a43ea16b..ebfed8606 100644 --- a/sdk/test/util/test_identification.py +++ b/sdk/test/util/test_identification.py @@ -1,4 +1,4 @@ -# Copyright (c) 2022 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. From e8fc37bf06172d0694b70a1b2bd965b1d1479c48 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:05:34 +0100 Subject: [PATCH 11/18] sdk/.readthedocs.yaml: Install dependencies from pyproject.toml (#359) Previously, we were accidentally still trying to install dependencies from the already deleted `requirements.txt` when generating the documentation. This fixes this and installs them instead from the `pyproject.toml`. Co-authored-by: s-heppner --- sdk/.readthedocs.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/.readthedocs.yaml b/sdk/.readthedocs.yaml index 92880ab17..e64e5daaf 100644 --- a/sdk/.readthedocs.yaml +++ b/sdk/.readthedocs.yaml @@ -12,6 +12,7 @@ sphinx: configuration: docs/source/conf.py python: - install: - - requirements: requirements.txt - - requirements: docs/add-requirements.txt + install: + - method: pip + path: . + - requirements: docs/add-requirements.txt From 8bd2c5416a36ce1c49142467a3b08bf87ece96f6 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Fri, 21 Feb 2025 13:18:33 +0100 Subject: [PATCH 12/18] compliance_tool: add pyproject.toml (#361) This refactors away from `setup.py` and towards `pyproject.toml` for the `compliance_tool` package. At the same step, we also update the relevant CI checks as well. --- .github/workflows/ci.yml | 61 +++++++++++++++++--------------- .github/workflows/release.yml | 4 +-- .gitignore | 1 + compliance_tool/pyproject.toml | 60 +++++++++++++++++++++++++++++++ compliance_tool/requirements.txt | 3 -- 5 files changed, 96 insertions(+), 33 deletions(-) create mode 100644 compliance_tool/pyproject.toml delete mode 100644 compliance_tool/requirements.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34470e8f1..3c66e7ad7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,9 +14,9 @@ jobs: run: working-directory: ./etc/scripts steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install Python dependencies @@ -29,12 +29,14 @@ jobs: ${{ env.X_PYTHON_MIN_VERSION }} \ ${{ env.X_PYTHON_MAX_VERSION }} - - name: Check Python Versions coincide with the SDKs pyproject.toml + - name: Check Python Versions coincide with all pyproject.toml Files run: | - python check_python_versions_coincide.py \ - ../../sdk/pyproject.toml \ - ${{ env.X_PYTHON_MIN_VERSION }} \ - ${{ env.X_PYTHON_MAX_VERSION }} + for file in ../../sdk/pyproject.toml ../../compliance_tool/pyproject.toml; do + python check_python_versions_coincide.py \ + $file \ + ${{ env.X_PYTHON_MIN_VERSION }} \ + ${{ env.X_PYTHON_MAX_VERSION }} + done # Todo: Check other pyproject.toml here as well, as we add them @@ -72,7 +74,7 @@ jobs: exit 1 fi - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Collect schema files from aas-specs @@ -104,7 +106,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install Python dependencies @@ -127,7 +129,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install Python dependencies @@ -153,7 +155,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install Python dependencies @@ -174,7 +176,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install dependencies @@ -213,16 +215,17 @@ jobs: working-directory: ./compliance_tool steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + 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 - pip install coverage - pip install -r requirements.txt + pip install -e ../sdk[dev] + pip install .[dev] - name: Test with coverage + unittest run: | coverage run --source=aas_compliance_tool -m unittest @@ -239,16 +242,17 @@ jobs: run: working-directory: ./compliance_tool steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_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 - pip install pycodestyle mypy - pip install -r requirements.txt + pip install -e ../sdk[dev] + pip install .[dev] - name: Check typing with MyPy run: | mypy ./aas_compliance_tool test @@ -264,16 +268,17 @@ jobs: run: working-directory: ./compliance_tool steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_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 - pip install pycodestyle mypy codeblocks - pip install -r requirements.txt + pip install -e ../sdk[dev] + pip install .[dev] - name: Check typing with MyPy run: | mypy <(codeblocks python README.md) @@ -292,18 +297,18 @@ jobs: run: working-directory: ./compliance_tool steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ env.X_PYTHON_MIN_VERSION }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ env.X_PYTHON_MIN_VERSION }} - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel + pip install build - name: Create source and wheel dist run: | - python setup.py sdist bdist_wheel + python -m build server-package: # This job checks if we can build our server package diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 15b22ea25..991e8ad7b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,9 +12,9 @@ jobs: run: working-directory: ./sdk steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python 3.10 - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install dependencies diff --git a/.gitignore b/.gitignore index dc7eddbb6..18b522c3a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ sdk/test/adapter/schemas # Ignore dynamically generated version file sdk/basyx/version.py +compliance_tool/aas_compliance_tool/version.py # ignore the content of the server storage server/storage/ diff --git a/compliance_tool/pyproject.toml b/compliance_tool/pyproject.toml new file mode 100644 index 000000000..c907f90df --- /dev/null +++ b/compliance_tool/pyproject.toml @@ -0,0 +1,60 @@ +[build-system] +requires = [ + "setuptools>=45", + "wheel", + "setuptools_scm[toml]>=6.2" +] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +# Configure setuptools_scm for version management: +# - Automatically infers the version number from the most recent git tag +# - Generates a version.py file in the package directory +# - Allows for automatic versioning between releases (e.g., 1.0.1.dev4+g12345) +# If you want to use the version anywhere in the code, use +# ``` +# from aas_compliance_tool.version import version +# print(f"Project version: {version}") +# ``` +root = ".." # Defines the path to the root of the repository +version_file = "aas_compliance_tool/version.py" + +[project] +name = "aas_compliance_tool" +dynamic = ["version"] +description = "AAS compliance checker based on the Eclipse BaSyx Python SDK" +authors = [ + { name = "The AAS Compliance Tool authors", email = "admins@iat.rwth-aachen.de" } +] +readme = "README.md" +license = { file = "LICENSE" } +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Development Status :: 5 - Production/Stable" +] +requires-python = ">=3.9" +dependencies = [ + "pyecma376-2>=0.2.4", + "jsonschema>=4.21.1", + "basyx-python-sdk>=1.0.0", +] + +[project.optional-dependencies] +dev = [ + "mypy", + "pycodestyle", + "codeblocks", + "coverage", +] + +[project.urls] +"Homepage" = "https://github.com/eclipse-basyx/basyx-python-sdk" + +[tool.setuptools] +packages = { find = { include = ["aas_compliance_tool*"], exclude = ["test*"] } } + +[tool.setuptools.package-data] +aas_compliance_tool = ["py.typed"] + diff --git a/compliance_tool/requirements.txt b/compliance_tool/requirements.txt deleted file mode 100644 index 89a1d39df..000000000 --- a/compliance_tool/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -pyecma376-2>=0.2.4 -jsonschema>=4.21.1 -basyx-python-sdk>=1.0.0 From 9c98a7bf31aef5c4767c8d67c5d47803f97919a7 Mon Sep 17 00:00:00 2001 From: Sercan Sahin <125310380+Frosty2500@users.noreply.github.com> Date: Tue, 15 Apr 2025 13:58:36 +0200 Subject: [PATCH 13/18] http.py: Fix redirects, bugs, and SDK installation (#362) This fixes the redirects from the AAS repository paths to the Submodel repository paths to work properly. Furthermore, the installation of dependencies inside the server Docker image was previously using the latest release of the SDK. This means, that we could not ensure that each commit in the `main` branch of our monorepo would be interoperable between SDK and server, as a PR would have to be closed in order for the server CI would not report any errors. In order to fix this, issue in the development process, the server Docker image now installs the SDK from the local repository, rather than from GitHub. Lastly, this fixes a wrong status code reported when specifing a model that is malformed or missing information. The specification expects a 400 (Bad Request) response, but the server sent a 422 (Unprocessable Content). Fixes #315 --- .github/workflows/ci.yml | 2 +- sdk/basyx/aas/adapter/http.py | 70 ++++++++++++++++++++++++----------- server/Dockerfile | 15 +++++--- server/README.md | 12 +++--- server/compose.yml | 4 +- 5 files changed, 68 insertions(+), 35 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c66e7ad7..8901688fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -320,7 +320,7 @@ jobs: - uses: actions/checkout@v4 - name: Build the Docker image run: | - docker build -t basyx-python-server . + docker build -t basyx-python-server -f Dockerfile .. - name: Run container run: | docker run -d --name basyx-python-server basyx-python-server diff --git a/sdk/basyx/aas/adapter/http.py b/sdk/basyx/aas/adapter/http.py index a4d7ab289..12bd533f3 100644 --- a/sdk/basyx/aas/adapter/http.py +++ b/sdk/basyx/aas/adapter/http.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 the Eclipse BaSyx Authors +# Copyright (c) 2025 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. @@ -42,13 +42,14 @@ import io import json import itertools +import urllib from lxml import etree import werkzeug.exceptions import werkzeug.routing import werkzeug.urls import werkzeug.utils -from werkzeug.exceptions import BadRequest, Conflict, NotFound, UnprocessableEntity +from werkzeug.exceptions import BadRequest, Conflict, NotFound from werkzeug.routing import MapAdapter, Rule, Submount from werkzeug.wrappers import Request, Response from werkzeug.datastructures import FileStorage @@ -252,7 +253,13 @@ def http_exception_to_response(exception: werkzeug.exceptions.HTTPException, res def is_stripped_request(request: Request) -> bool: - return request.args.get("level") == "core" + level = request.args.get("level") + if level not in {"deep", "core", None}: + raise BadRequest(f"Level {level} is not a valid level!") + extent = request.args.get("extent") + if extent is not None: + raise werkzeug.exceptions.NotImplemented(f"The parameter extent is not yet implemented for this server!") + return level == "core" T = TypeVar("T") @@ -300,7 +307,7 @@ def check_type_supportance(cls, type_: type): @classmethod def assert_type(cls, obj: object, type_: Type[T]) -> T: if not isinstance(obj, type_): - raise UnprocessableEntity(f"Object {obj!r} is not of type {type_.__name__}!") + raise BadRequest(f"Object {obj!r} is not of type {type_.__name__}!") return obj @classmethod @@ -312,10 +319,10 @@ def json_list(cls, data: Union[str, bytes], expect_type: Type[T], stripped: bool parsed = json.loads(data, cls=decoder) if not isinstance(parsed, list): if not expect_single: - raise UnprocessableEntity(f"Expected List[{expect_type.__name__}], got {parsed!r}!") + raise BadRequest(f"Expected List[{expect_type.__name__}], got {parsed!r}!") parsed = [parsed] elif expect_single: - raise UnprocessableEntity(f"Expected a single object of type {expect_type.__name__}, got {parsed!r}!") + raise BadRequest(f"Expected a single object of type {expect_type.__name__}, got {parsed!r}!") # TODO: the following is ugly, but necessary because references aren't self-identified objects # in the json schema # TODO: json deserialization will always create an ModelReference[Submodel], xml deserialization determines @@ -339,7 +346,7 @@ def json_list(cls, data: Union[str, bytes], expect_type: Type[T], stripped: bool return [constructor(obj, *args) for obj in parsed] except (KeyError, ValueError, TypeError, json.JSONDecodeError, model.AASConstraintViolation) as e: - raise UnprocessableEntity(str(e)) from e + raise BadRequest(str(e)) from e return [cls.assert_type(obj, expect_type) for obj in parsed] @@ -369,9 +376,9 @@ def xml(cls, data: bytes, expect_type: Type[T], stripped: bool) -> T: f: BaseException = e while f.__cause__ is not None: f = f.__cause__ - raise UnprocessableEntity(str(f)) from e + raise BadRequest(str(f)) from e except (etree.XMLSyntaxError, model.AASConstraintViolation) as e: - raise UnprocessableEntity(str(e)) from e + raise BadRequest(str(e)) from e return cls.assert_type(rv, expect_type) @classmethod @@ -647,13 +654,13 @@ def _get_submodel_reference(cls, aas: model.AssetAdministrationShell, submodel_i @classmethod def _get_slice(cls, request: Request, iterator: Iterable[T]) -> Tuple[Iterator[T], int]: limit_str = request.args.get('limit', default="10") - cursor_str = request.args.get('cursor', default="0") + cursor_str = request.args.get('cursor', default="1") try: - limit, cursor = int(limit_str), int(cursor_str) + limit, cursor = int(limit_str), int(cursor_str) - 1 # cursor is 1-indexed if limit < 0 or cursor < 0: raise ValueError except ValueError: - raise BadRequest("Cursor and limit must be positive integers!") + raise BadRequest("Limit can not be negative, cursor must be positive!") start_index = cursor end_index = cursor + limit paginated_slice = itertools.islice(iterator, start_index, end_index) @@ -667,14 +674,31 @@ def _get_shells(self, request: Request) -> Tuple[Iterator[model.AssetAdministrat aas = filter(lambda shell: shell.id_short == id_short, aas) asset_ids = request.args.getlist("assetIds") - if asset_ids is not None: - # Decode and instantiate SpecificAssetIds - # This needs to be a list, otherwise we can only iterate it once. - specific_asset_ids: List[model.SpecificAssetId] = list( - map(lambda asset_id: HTTPApiDecoder.base64urljson(asset_id, model.SpecificAssetId, False), asset_ids)) - # Filter AAS based on these SpecificAssetIds - aas = filter(lambda shell: all(specific_asset_id in shell.asset_information.specific_asset_id - for specific_asset_id in specific_asset_ids), aas) + + if asset_ids: + specific_asset_ids = [] + global_asset_ids = [] + + for asset_id in asset_ids: + asset_id_json = base64url_decode(asset_id) + asset_dict = json.loads(asset_id_json) + name = asset_dict["name"] + value = asset_dict["value"] + + if name == "specificAssetId": + decoded_specific_id = HTTPApiDecoder.json_list(value, model.SpecificAssetId, + False, True)[0] + specific_asset_ids.append(decoded_specific_id) + elif name == "globalAssetId": + global_asset_ids.append(value) + + # Filter AAS based on both SpecificAssetIds and globalAssetIds + aas = filter(lambda shell: ( + (not specific_asset_ids or all(specific_asset_id in shell.asset_information.specific_asset_id + for specific_asset_id in specific_asset_ids)) and + (len(global_asset_ids) <= 1 and + (not global_asset_ids or shell.asset_information.global_asset_id in global_asset_ids)) + ), aas) paginated_aas, end_index = self._get_slice(request, aas) return paginated_aas, end_index @@ -843,7 +867,7 @@ def delete_aas_submodel_refs_submodel(self, request: Request, url_args: Dict, re aas.commit() return response_t() - def aas_submodel_refs_redirect(self, request: Request, url_args: Dict, map_adapter: MapAdapter, + def aas_submodel_refs_redirect(self, request: Request, url_args: Dict, map_adapter: MapAdapter, response_t=None, **_kwargs) -> Response: aas = self._get_shell(url_args) # the following makes sure the reference exists @@ -852,7 +876,7 @@ def aas_submodel_refs_redirect(self, request: Request, url_args: Dict, map_adapt "submodel_id": url_args["submodel_id"] }, force_external=True) if "path" in url_args: - redirect_url += url_args["path"] + "/" + redirect_url += "/" + url_args["path"] if request.query_string: redirect_url += "?" + request.query_string.decode("ascii") return werkzeug.utils.redirect(redirect_url, 307) @@ -940,6 +964,8 @@ def get_submodel_submodel_elements_id_short_path(self, request: Request, url_arg def get_submodel_submodel_elements_id_short_path_metadata(self, request: Request, url_args: Dict, response_t: Type[APIResponse], **_kwargs) -> Response: submodel_element = self._get_submodel_submodel_elements_id_short_path(url_args) + if isinstance(submodel_element, model.Capability) or isinstance(submodel_element, model.Operation): + raise BadRequest(f"{submodel_element.id_short} does not allow the content modifier metadata!") return response_t(submodel_element, stripped=True) def get_submodel_submodel_elements_id_short_path_reference(self, request: Request, url_args: Dict, diff --git a/server/Dockerfile b/server/Dockerfile index 6dc3c4cac..4df672c41 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -13,13 +13,12 @@ ENV PYTHONUNBUFFERED=1 RUN apk update && \ apk add --no-cache nginx supervisor gcc musl-dev linux-headers python3-dev git bash && \ pip install uwsgi && \ - pip install --no-cache-dir git+https://github.com/eclipse-basyx/basyx-python-sdk@main#subdirectory=sdk && \ apk del git bash -COPY uwsgi.ini /etc/uwsgi/ -COPY supervisord.ini /etc/supervisor/conf.d/supervisord.ini -COPY stop-supervisor.sh /etc/supervisor/stop-supervisor.sh +COPY server/uwsgi.ini /etc/uwsgi/ +COPY server/supervisord.ini /etc/supervisor/conf.d/supervisord.ini +COPY server/stop-supervisor.sh /etc/supervisor/stop-supervisor.sh RUN chmod +x /etc/supervisor/stop-supervisor.sh # Makes it possible to use a different configuration @@ -34,12 +33,16 @@ ENV LISTEN_PORT=80 ENV CLIENT_BODY_BUFFER_SIZE=1M # Copy the entrypoint that will generate Nginx additional configs -COPY entrypoint.sh /entrypoint.sh +COPY server/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] -COPY ./app /app +ENV SETUPTOOLS_SCM_PRETEND_VERSION=1.0.0 + +COPY ./sdk /sdk +COPY ./server/app /app WORKDIR /app +RUN pip install ../sdk CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.ini"] diff --git a/server/README.md b/server/README.md index 339226c53..37b649d79 100644 --- a/server/README.md +++ b/server/README.md @@ -15,7 +15,7 @@ See [below](#options) on how to configure this. ## Building The container image can be built via: ``` -$ docker buildx build -t basyx-python-sdk-http-server . +$ docker build -t basyx-python-server -f Dockerfile .. ``` ## Running @@ -46,17 +46,17 @@ The container can be configured via environment variables: Putting it all together, the container can be started via the following command: ``` -$ docker run -p 8080:80 -v ./storage:/storage basyx-python-sdk-http-server +$ docker run -p 8080:80 -v ./storage:/storage basyx-python-server ``` Since Windows uses backslashes instead of forward slashes in paths, you'll have to adjust the path to the storage directory there: ``` -> docker run -p 8080:80 -v .\storage:/storage basyx-python-sdk-http-server +> docker run -p 8080:80 -v .\storage:/storage basyx-python-server ``` Per default, the server will use the `LOCAL_FILE_READ_ONLY` storage type and serve the API under `/api/v3.0` and read files from `/storage`. If you want to change this, you can do so like this: ``` -$ docker run -p 8080:80 -v ./storage2:/storage2 -e API_BASE_PATH=/api/v3.1 -e STORAGE_TYPE=LOCAL_FILE_BACKEND -e STORAGE_PATH=/storage2 basyx-python-sdk-http-server +$ docker run -p 8080:80 -v ./storage2:/storage2 -e API_BASE_PATH=/api/v3.1 -e STORAGE_TYPE=LOCAL_FILE_BACKEND -e STORAGE_PATH=/storage2 basyx-python-server ``` ## Building and running the image with docker-compose @@ -70,7 +70,9 @@ This is the exemplary `docker-compose` file for the server: ````yaml services: app: - build: . + build: + context: .. + dockerfile: server/Dockerfile ports: - "8080:80" volumes: diff --git a/server/compose.yml b/server/compose.yml index 5465e04ce..666484a5d 100644 --- a/server/compose.yml +++ b/server/compose.yml @@ -1,6 +1,8 @@ services: app: - build: . + build: + context: .. + dockerfile: server/Dockerfile ports: - "8080:80" volumes: From 1aac79771516b973edcff2ec3040d4bc6381eb12 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Thu, 17 Apr 2025 15:28:56 +0200 Subject: [PATCH 14/18] CONTRIBUTING.md: Improve codestyle and testing section (#376) Previously, the section "Codestyle and Testing" was outdated, still from the time where there was only the SDK inside this repository. This greatly extends the section, renaming it to "Code Quality" and introducing subsections for "Codestyle" and "Testing", where we describe how to run the necessary tests locally on the developer's machine for each of the packages inside this monorepository. Fixes #353 --- CONTRIBUTING.md | 74 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 95ec0a74f..a15c9c20c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -119,16 +119,41 @@ The following guidelines are for the commit or PR message text: via `https://link/to.pdf#Page=123` - Optionally, where applicable reference respective issues: `Fixes #123` -## Codestyle and Testing +## Code Quality +The Eclipse BaSyx Python project emphasizes high code quality. +To achieve this, we apply best practices where possible and have developed an extensive suite of tests that are +expected to pass for each Pull Request to the project. + +### Codestyle Our code follows the [PEP 8 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) with the following exceptions: - Line length is allowed to be up to 120 characters, though lines up to 100 characters are preferred. Additionally, we use [PEP 484 -- Type Hints](https://www.python.org/dev/peps/pep-0484/) throughout the code to enable type checking the code. -Before submitting any changes, make sure to let `mypy` and `pycodestyle` check your code and run the unit tests with -Python's builtin `unittest`. To install the required tools, use: +Before submitting any changes to the SDK, make sure to let `mypy` and `pycodestyle` check your code and run the unit +tests with Python's builtin `unittest`. + +### Testing +There are many automated checks implemented in the CI pipelines of this project, all of which are expected to pass +before new code can be added: + +- We check that the Python packages can be built. +- We run the developed unittests and aim for a code coverage of at least 80%. +- We perform static code analysis for type-checking and codestyle, not just in the code itself, but also in codeblocks + that are inside docstrings and the `README.md`. +- We check that the automatically generated developer documentation compiles. +- We check that the Python Versions we support match between the different subprojects in the monorepository and are + not End of Life. +- We check that the year in the copyright headers in each file (stemming from the license) is correct. + +> [!note] +> We strongly suggest to run the tests locally, before submitting a Pull Request, in order to accelerate the review +> process. + +### Testing the SDK +For testing the SDK locally on your machine, you can install the required tools like so: ```bash pip install .[dev] ``` @@ -142,12 +167,51 @@ Running all checks: mypy basyx test pycodestyle --max-line-length 120 basyx test python -m unittest +coverage run --source basyx --branch -m unittest +coverage report -m ``` -We aim to cover our code with test by at least 80%. To check test coverage, you can use `coverage`: +We aim to cover our code with tests by at least 80%. + +This should help you sort out the most important bugs in your code. +Note that there are more checks that run in the CI once you open a Pull Request. +If you want to run the additional checks, please refer to the [CI definition](./.github/workflows/ci.yml). +### Testing the Server +Currently, the automated server tests are still under development. +To test that the server is working, we expect to at least be able to build the docker images and run a container +of it without error. + +For that, you need to have Docker installed on your system. +In the directory with the `Dockerfile`: ```bash -pip install coverage +docker build -t basyx-python-server . +docker run --name basyx-python-server basyx-python-server +``` +Wait until you see the line: +``` +INFO success: quit_on_failure entered RUNNING state +``` + +### Testing the Compliance Tool +For the Compliance Tool, you can install the required tools like this (from the `./compliance_tool` directory): +```bash +pip install -e ../sdk[dev] +pip install .[dev] +``` +The first line installs the SDK and its dependencies, the second the developer dependencies for the compliance tool +itself. + +Then you can run the checks via: +```bash +mypy basyx test +pycodestyle --max-line-length 120 basyx test +python -m unittest coverage run --source basyx --branch -m unittest coverage report -m ``` + +We aim to cover our code with tests by at least 80%. +This should help you sort out the most important bugs in your code. +Note that there are more checks that run in the CI once you open a Pull Request. +If you want to run the additional checks, please refer to the [CI definition](./.github/workflows/ci.yml). From 079e12810c8e3ed74856ef11d6ab6bd0e43f5c0e Mon Sep 17 00:00:00 2001 From: s-heppner Date: Wed, 23 Apr 2025 14:20:17 +0200 Subject: [PATCH 15/18] compliance_tool: Remove setup.py (#377) We previously refactored the compliance_tool from `setup.py` to `pyproject.toml` (See #361). However, somehow the `setup.py` slipped through and is still in the `compliance_tool` directory. This removes the `setup.py` from the `compliance_tool` completely. --- compliance_tool/setup.py | 43 ---------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 compliance_tool/setup.py diff --git a/compliance_tool/setup.py b/compliance_tool/setup.py deleted file mode 100644 index eb143df75..000000000 --- a/compliance_tool/setup.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2025 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. -# -# SPDX-License-Identifier: MIT - -import setuptools - -with open("README.md", "r", encoding='utf-8') as fh: - long_description = fh.read() - -setuptools.setup( - name="aas_compliance_tool", - version="1.0.0", - author="The AAS Compliance Tool authors", - description="AAS compliance checker based on the Eclipse BaSyx Python SDK", - long_description=long_description, - long_description_content_type="text/markdown", - url="https://github.com/rwth-iat/aas-compliance-tool", - packages=setuptools.find_packages(exclude=["test", "test.*"]), - zip_safe=False, - package_data={ - "aas_compliance_tool": ["py.typed", "schemas/aasJSONSchema.json", "schemas/aasXMLSchema.xsd"], - }, - classifiers=[ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Development Status :: 5 - Production/Stable", - ], - entry_points={ - 'console_scripts': [ - "aas-compliance-check = aas_compliance_tool:main" - ] - }, - python_requires='>=3.8', - install_requires=[ - 'pyecma376-2>=0.2.4', - 'basyx-python-sdk>=1.0.0', - ] -) From 288ea49162cf89b1f5c3fdfa0ca2b55fc5950082 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Wed, 23 Apr 2025 14:22:36 +0200 Subject: [PATCH 16/18] Add CI job to release compliance-tool to PyPI (#382) This adds a job `compliance-tool-publish` to the `release.yml` that automatically publishes the compliance-tool package to PyPI upon release. It is simply copied from the SDK job, with adapted paths. --- .github/workflows/release.yml | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 991e8ad7b..06491c0cb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,8 +5,8 @@ on: types: [published] jobs: - publish: - # This job publishes the package to PyPI + sdk-publish: + # This job publishes the SDK package to PyPI runs-on: ubuntu-latest defaults: run: @@ -31,3 +31,30 @@ jobs: uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_ORG_TOKEN }} + + compliance-tool-publish: + # This job publishes the compliance_tool package to PyPI + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./compliance_tool + steps: + - uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Create source and wheel dist + # (2024-12-11, s-heppner) + # The PyPI Action expects the dist files in a toplevel `/dist` directory, + # so we have to specify this as output directory here. + run: | + python -m build --outdir ../dist + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_ORG_TOKEN }} From a6a904af37f9cccddd1d31f6b2f1921bfded4256 Mon Sep 17 00:00:00 2001 From: Moritz Sommer Date: Sun, 8 Jun 2025 12:16:40 +0200 Subject: [PATCH 17/18] sdk: Update lxml and mypy dependency in pyproject.toml (#392) * sdk: Update lxml dependency in pyproject.toml Previously, the `lxml` dependency in the `pyproject.toml` was pinned to versions `>=4.2,<5`. This caused a faulty installation via `pip` on Windows due to missing binary wheels. This updates the `lxml` dependency to versions `>=5.3` to resolve the issue. Additionally, the `mypy` dependency in the `pyproject.toml` was unpinned, leading to the installation of the latest version. The recent release of `mypy 1.16.0` introduced changes not yet supported by our codebase, resulting in CI pipeline failures. This restricts the `mypy` dependency to version `1.15.0` until we have proper support for `1.16.0` and its new features. Fixes #391 --- sdk/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/pyproject.toml b/sdk/pyproject.toml index baaf6ff05..0fe88d1bd 100644 --- a/sdk/pyproject.toml +++ b/sdk/pyproject.toml @@ -36,7 +36,7 @@ classifiers = [ ] requires-python = ">=3.9" dependencies = [ - "lxml>=4.2,<5", + "lxml>=5.3", "python-dateutil>=2.8,<3", "pyecma376-2>=1.0.1", "urllib3>=1.26,<3", @@ -45,7 +45,7 @@ dependencies = [ [project.optional-dependencies] dev = [ - "mypy", + "mypy==1.15.0", "pycodestyle", "codeblocks", "coverage", From 2455821a7440e5d6803bb4932ef05ea752c5c9e7 Mon Sep 17 00:00:00 2001 From: s-heppner Date: Tue, 7 Oct 2025 18:58:01 +0200 Subject: [PATCH 18/18] Update README.md (#415) Previously, the SDK version could have been confused with the supported AAS specification versions. To alleviate this, this adds an additional text to the top of the `README.md`. --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 82e56055f..9894d320c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # Eclipse BaSyx Python SDK -(formerly known as PyI40AAS – Python Industry 4.0 Asset Administration Shell) - The Eclipse BaSyx Python project focuses on providing a Python implementation of the Asset Administration Shell (AAS) -for Industry 4.0 Systems. -These are the currently implemented specifications: +for Industry 4.0 Systems. + +**Please note that the SDK version number is independent of the supported AAS versions!** + +These are the implemented AAS specifications of the [current SDK release](https://github.com/eclipse-basyx/basyx-python-sdk/releases/latest), which can be also found on [PyPI](https://pypi.org/project/basyx-python-sdk/): | Specification | Version | |---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -14,6 +15,9 @@ These are the currently implemented specifications: | 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) | | Part 5: Package File Format (AASX) | [v3.0 (01005-3-0)](https://industrialdigitaltwin.org/wp-content/uploads/2023/04/IDTA-01005-3-0_SpecificationAssetAdministrationShell_Part5_AASXPackageFileFormat.pdf) | +If you need support to an older version of the specifications, please refer to our [prior releases](https://github.com/eclipse-basyx/basyx-python-sdk/releases). +Each of them has a similar table at the top of the release notes. + ## Features This repository is structured into separate packages. The `sdk` directory provides the AAS metamodel as Python objects and fundamental functionalities to handle AAS.