Coder Social home page Coder Social logo

basyx-python-sdk's Introduction

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:

Specification Version
Part 1: Metamodel v3.0 (01001-3-0)
Part 2: API not implemented yet
Part 3a: Data Specification IEC 61360 v3.0 (01003-a-3-0)
Part 5: Package File Format (AASX) v3.0 (01005-3-0)

Features

  • Modelling of AASs as Python objects
    • except for: HasDataSpecification
  • Reading and writing of AASX package files
  • (De-)serialization of AAS objects into/from JSON and XML
  • Storing of AAS objects in CouchDB, Backend infrastructure for easy expansion
  • Compliance checking of AAS XML and JSON files

Project Structure

The BaSyx Python SDK project provides the basax.aas Python package with 6 submodules:

  • basyx.aas.model: The AAS metamodel implemented in python
  • basyx.aas.adapter: Adapters for various file formats
  • basyx.aas.backend: Backend infrastructure for storing and retrieving AAS objects
  • basyx.aas.util: Provides utilities
  • basyx.aas.examples: Example data and tutorials

License

The BaSyx Python SDK project is licensed under the terms of the MIT License.

SPDX-License-Identifier: MIT

For more information, especially considering the licenses of included third-party works, please consult the NOTICE file.

Release Schedule

The Eclipse BaSyx-Python SDK Team evaluates bi-monthly the newly added commits to the main branch towards the need of releasing a new version. If decided the changes warrant a release, it is initiated, using semantic versioning for the new release number. If the changes do not warrant a release, the decision is postponed to the next meeting.

Additionally, security fixes may be released at any point.

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:

  • 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)

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)

Dependencies for building the documentation (see docs/add-requirements.txt):

  • Sphinx and its dependencies (BSD 2-clause License, MIT License, Apache License)
  • sphinx-rtd-theme and its dependencies (MIT License, PSF License)
  • sphinx-argparse (MIT License)

Getting Started

Installation

Eclipse BaSyx Python SDK can be installed from PyPI, the Python Package Index, just as nearly every other Python package:

pip install basyx-python-sdk

For working with the current development version, you can also install the package directly from GitHub, using Pip's Git feature:

pip install git+https://github.com/eclipse-basyx/basyx-python-sdk.git@main

You may want to use a Python's venv or a similar tool to install BaSyx Python SDK and its dependencies only in a project-specific local environment.

Example

The following code example shows how to create a Submodel with a Property serialize it into an XML file using the Eclipse BaSyx Python SDK:

Create a Submodel:

from basyx.aas import model  # Import all BaSyx Python SDK classes from the model package

identifier = 'https://acplt.org/Simple_Submodel'
submodel = model.Submodel(identifier)

Create a Property and add it to the Submodel:

# create an external reference to a semantic description of the property
semantic_reference = model.ExternalReference(
    (model.Key(
        type_=model.KeyTypes.GLOBAL_REFERENCE,
        value='http://acplt.org/Properties/SimpleProperty'
    ),)
)
property = model.Property(
    id_short='ExampleProperty',  # Identifying string of the element within the submodel namespace
    value_type=model.datatypes.String,  # Data type of the value
    value='exampleValue',  # Value of the property
    semantic_id=semantic_reference  # set the semantic reference
)
submodel.submodel_element.add(property)

Serialize the Submodel to XML:

from basyx.aas.adapter.xml import write_aas_xml_file

data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
data.add(submodel)
write_aas_xml_file(file='Simple_Submodel.xml', data=data)

Examples and Tutorials

For further examples and tutorials, check out the basyx.aas.examples-package. Here is a quick overview:

  • tutorial_create_simple_aas: Create an Asset Administration Shell, including an Asset object and a Submodel
  • tutorial_storage: Manage a larger number of Asset Administration Shells in an ObjectStore and resolve references
  • tutorial_serialization_deserialization: Use the JSON and XML serialization/deserialization for single objects or full standard-compliant files
  • tutorial_aasx: Export Asset Administration Shells with related objects and auxiliary files to AASX package files
  • tutorial_backend_couchdb: Use the Backends interface (update()/commit() methods) to manage and retrieve AAS objects in a CouchDB document database

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.

Contributing

For contributing with issues and code, please see our Contribution Guideline.

Eclipse Contributor Agreement

To contribute code to this project you need to sign the Eclipse Contributor Agreement (ECA). This is done by creating an Eclipse account for your git e-mail address and then submitting the following form: https://accounts.eclipse.org/user/eca

basyx-python-sdk's People

Contributors

dxvidnrt avatar frankschnicke avatar frosty2500 avatar jkhsjdhjs avatar mhrimaz avatar mhthies avatar otto-ifak avatar s-heppner avatar scharf avatar supreetshm947 avatar torbend avatar zrgt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

basyx-python-sdk's Issues

model._string_constraints: Add AASd-130 to strings

According to the spec: AASd-130:

Ensures that encoding is possible and interoperability between different
serializations is possible.
Constraint AASd-130: An attribute with data type "string" shall consist of these
characters only: ^[\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u00010000-
\u0010FFFF]*$.

My suggestion is to add this regex to the general check() function

DotAAS V3.0 Compatbility

Tracking issue for V3.0 release.

TODOs:

  • finish #18
  • fix id_short attribute defaulting to the string literal NotSet (see discussion on Zulip)
  • revert 8fee1c5
  • make NamespaceSet immutable (inherit from FrozenSet) and rename the current NamespaceSet to MutableNamespaceSet, which inherits from the new immutable NamespaceSet -> for SubmodelElementCollection
  • update JSON + XML schemata -> Check diff to improve/V30 schemata and adapt if necessary -> see below
  • #96
  • #72 -> Problem of the spec

(s-heppner, 2023-10-19)
EDIT: Copied comment from below, so that not just me can edit. Furtheremore, I took the liberty to clean up this comment.

Since we're closing in to the last steps, here a summary of the Todos left before the v3.0 Release:

  • Adapt the changes in the constraints
  • #96
  • #117
  • #118
  • Add case-sensitive matching for idShorts (AASd-003)
  • Repair and finalize #91
  • #136
  • Check that the spec Part 3a was fully adapted (I saw a wrong type of unit at first glance)
  • #145
  • #146 @jkhsjdhjs
  • #148 @jkhsjdhjs
  • Double check the completeness of the JSON & XML schemata @jkhsjdhjs
    • I tried and found one mistake through the JSON, but sadly several problems with the XSD.
    • #144 @zrgt
  • Document
    • Update the constraint-implementation table in sphinx @zrgt
    • #112 -> EventPayload as well @zrgt
    • #119 @zrgt
    • Final check of the documentation
  • merge main in improve/V30 (and maybe also improve/V30RC02)

Investigate (and fix) unittests regarding `SubmodelElementList`s

#86 added a missing model.KeyTypes.SUBMODEL_ELEMENT_LIST.

The weird thing about this is that the unittests didn't catch this as a missing KeyType, even though there are SubmodelElementLists in the example test files.

We need to investigate, why the unittests didn't catch this missing KeyType and improve the unittests, so that such mistake can not slip again in the future.

Implement check_schema() for AASX in compliance_tool

Implement a function to check_schema for AASX files in aas/compliance_tool/compliance_check_aasx.py

Idea:

  • identify aas file type in AASX archive: XML or JSON
  • use existing check_schema func for identifed file type

unable to reproduce AAS server JSON serialization

Hi,

I am using the official docker image of AAS server (eclipsebasyx/aas-server:1.3.0). However, the JSON response of AAS server is different than basyx-python-sdk JSON serialization result (Version: 0.2.2)

For example, when kind of submodel is instance there is no "kind":"Instance" in the output. In the image below you can see the structure is not consistent and this is reflected in the code too, however I don't know this is according to specification or just implementaiton difference.

image

And here you can see there are asset and assetRef on the left produced by AAS server. python sdk asset is equivalent to assetRef and asset is completely missing.

image

Is there any way to reproduce exact result of AAS server in python? or which java library should be used, basyx-java-sdk or eclipse-aas4j/aas4j or something else?

Please let me know if you require further information.

Problem of Customized child classes due to AAS Constraint 108 in SEList

The Constraint AASd-108 says: All first level child elements in a SubmodelElementList shall have the same
submodel element type as specified in SubmodelElementList/typeValueListElement.

The _check_constraints method in SubmodelElementList raises Exception if the child element in SubmodelElementList is not of the same Class as it is specified in typeValueListElement.

So if I define my SDK for a specific Submodel and define classes for it (e.g. SpecialProperty) which inherit from e.g. Property class, i get Errors:

  • I set SubmodelElementList/typeValueListElement to Property
  • I add to SubmodelElementList my SpecialProperty object
  • I get error from _check_constraints , because SpecialProperty!=Property .
  • If I set SubmodelElementList/typeValueListElement to SpecialProperty , I get error from _submodel_element_list_to_json in json_serialization.py because SpecialProperty class is not in KEY_TYPES_CLASSES dict

What are possible solutions here?

Missing class `DateTimeStamp` in `model.datatypes`

Hi, in Details of the Asset Administration Shell - Part 1 version 2.0.1 the xsd datatype are listed as below:

image

however when I am trying to parse my AASX file, I get the following error:

ValueError: aas:valueType on line 472 has invalid text: dateTimeStamp
 -> Failed to construct aas:property on line 456 using construct_submodel_element!

It seems that for basyx-python-sdk these datatypes are used:
https://www.w3.org/TR/xmlschema-2/#built-in-datatypes
but in the specification the following newer specified datatypes are used:
https://www.w3.org/TR/xmlschema11-2/#built-in-datatypes

Could you please clear that?

Update examples and tests after introducing `HasDataSpecification`

IEC61360ConceptDescription is removed since V30RC02. New classes HasDataSpecification, Embedded_data_specification, DataSpecificationContent, DataSpecificationIEC61360 and DataSpecificationPhysicalUnit are introduces instead.

Thatยดs why affected methods and classes in the following files should be updated:

  • aas/examples/init.py
  • aas/examples/data/example_concept_description.py
  • test/examples/test_examples.py
  • test/examples/test_helpers.py

model.submodel: Implement AASd-129 and AASd-119

Constraint AASd-129: If any Qualifier/kind value of a SubmodelElement/qualifier (attribute qualifier inherited
via Qualifiable) is equal to TemplateQualifier, the submodel element shall be part of a submodel template,
i.e. a Submodel with Submodel/kind (attribute kind inherited via HasKind) value equal to Template.

Any suggestions as to how to implement this?

In the same step, we should probably also implement AASd-119:

If any Qualifier/kind value of a Qualifiable/qualifier is equal to TemplateQualifier and
the qualified element inherits from "hasKind", the qualified element shall be of kind Template (HasKind/kind =
"Template").

How to add a property to a SubmodelElementCollection?

Hi,

How do I add a property to a SubmodelElementCollection?

With the following code I am able to create and add a SubmodelElementCollection to a Submodel.

smc= model.SubmodelElementCollectionUnordered(id_short="TestSME")
submodel.submodel_element.add(smc)

I am not able to add a property to that smc. The following code below gives error: AttributeError: 'SubmodelElementCollectionUnordered' object has no attribute 'submodel_element'.

smc.submodel_element.add(property_)

Is there a way to add a property to a SubmodelElementCollection?

Unable to parse submodel with json deserialization

I've set up a AAS server and request all submodels. I generate it like this:

submodel = model.Submodel(
    identification=model.Identifier(
        "https://acplt.org/Simple_Submodel", model.IdentifierType.IRI
    ),
    submodel_element={
        model.Property(
            id_short="ExampleProperty",
            value_type=basyx.aas.model.datatypes.String,
            value="exampleValue",
        )
    },
)
submodel_json_string = json.dumps(submodel, cls=basyx.aas.adapter.json.AASToJsonEncoder)

and then simply upload it via a PUT request to the aasServer.

Afterwards I GET the submodel again and the payload from AAS server looks like this

{
    "idShort": "",
    "modelType": {
        "name": "Submodel"
    },
    "identification": {
        "id": "https://acplt.org/Simple_Submodel",
        "idType": "IRI"
    },
    "submodelElements": {
        "ExampleProperty": {
            "idShort": "ExampleProperty",
            "modelType": {
                "name": "Property"
            },
            "semanticId": {
                "keys": [
                    {
                        "type": "GlobalReference",
                        "idType": "IRI",
                        "value": "http://acplt.org/Properties/SimpleProperty",
                        "local": false
                    }
                ]
            },
            "value": "exampleValue",
            "valueType": "string"
        }
    }
}

which fails with TypeError: Dict entry 'submodelElements' has unexpected type dict

this is a bit different from what the json serialization from python returns:

{
    "idShort": "",
    "modelType": {
        "name": "Submodel"
    },
    "identification": {
        "id": "https://acplt.org/Simple_Submodel",
        "idType": "IRI"
    },
    "submodelElements": [
        {
            "idShort": "ExampleProperty",
            "modelType": {
                "name": "Property"
            },
            "semanticId": {
                "keys": [
                    {
                        "type": "GlobalReference",
                        "idType": "IRI",
                        "value": "http://acplt.org/Properties/SimpleProperty",
                        "local": false
                    }
                ]
            },
            "value": "exampleValue",
            "valueType": "string"
        }
    ]
}

Why is the json deserialization incompatible?

Implement Constrained String Types

The following types have to be implemented for v3.0

See the specifcation

  • ContentType
  • Identifier
  • LabelType
  • MessageTopicType
  • NameType
  • PathType Note: Here we may want to constrain the string further
  • RevisionType Note: Here we may want to constrain the string further
  • QualifierType
  • VersionType

If we decide to also fully implement Part 3a, we need the following types as well link to spec:

  • PreferredNameTypeIec61360
  • ShortNameTypeIec61360
  • ValueFormatTypeIec61360
  • ValueTypeIec61360

Implementation of new sub-types of `LangStringSet`

With Version 3.0 the specification added several new sub-types of LangStringSet differing in the length of the string of the underlying LangString:

  • DefinitionTypeIEC61360
  • MultiLanguageNameType
  • PreferredNameTypeIEC61360
  • ShortNameTypeIEC61360
  • MultiLanguageTextType
    Currently, we represent class LangString as Dict and LangStringSet as a List of LangString. Now, we wonder how to implement these changes.

One option would be to implement the types directly and check the length constraints for example through dedicated getter and setter functions.

However, the modelling on the LangStringSet-Level done by the specification could be considered bad style. Therefore, we could decide to introduce a new abstract class LangString with classes inheriting from that class for the different types. We could do something like this:

DefinitionTypeIEC61360 is represented as a List of LangStringDefinitionTypeIEC61360
MultiLanguageNameType is represented as a List of LangStringNameType
PreferredNameTypeIEC61360 is represented as a List of LangStringPreferredNameTypeIEC61360
ShortNameTypeIEC61360 is represented as a List of LangStringShortNameTypeIEC61360
MultiLanguageTextType is represented as a List of Lang_string_text_type
As an added benefit, this would also bring us closer to the specified schemata, where LangStringSet-subtypes all have to be represented via native List objects. Also, this is equivalent to the implementation of aas-core

Multiple AAS in AAX package

Dear team,

# For adding a second AAS to the package, we can simply call `write_aas()` again.
# Warning: This will create a second XML/JSON part in the AASX Package, which is compliant with the "Details of the
# Asset Administration Shell" standard up to version 2.0.1, but not supported by AASX Package Explorer.

could someone update me on a status of AASX-package-explorer versions of multiple AAS in the AASX package?

Fix `LangStringSet._check_language_tag_constraints` after the spec has been clarified

After the spec regarding language tags is clarified(admin-shell-io/aas-specs#293), we need to adapt the method LangStringSet._check_language_tag_constraints

Currently we demand that language tags:

  • can only have one or zero extensions
  • the only possible extension is region

Relevant codesnippet:
https://github.com/eclipse-basyx/basyx-python-sdk/blob/5eb895e1e64cdcd4ba98464d5fda4176292cf942/basyx/aas/model/base.py#L289C1-L296C56

    @classmethod
    def _check_language_tag_constraints(cls, ltag: str):
        split = ltag.split("-", 1)
        if len(split[0]) != 2 or not split[0].isalpha() or not split[0].islower():
            raise ValueError(f"The language code '{split[0]}' of the language tag '{ltag}' doesn't consist of exactly "
                             "two lower-case letters!")
        if len(split) > 1 and (len(split[1]) != 2 or not split[1].isalpha() or not split[1].isupper()):
            raise ValueError(f"The extension '{split[1]}' of the language tag '{ltag}' doesn't consist of exactly "
                             "two upper-case letters!")

Add setter-functions for object attributes that consist of `NamespaceSet`s

When instantiating an AssetAdministrationShell-object, we hand over ConceptDictionarys in any kind of Iterable (See here)

def __init__(self,
                 ...
                 concept_dictionary: Iterable[concept.ConceptDictionary] = (),
                 ...):

However, internally, we create a NamespaceSet containing these ConceptDictionarys in order to be able to resolve them later:

self.concept_dictionary: base.NamespaceSet[concept.ConceptDictionary] = \
            base.NamespaceSet(self, concept_dictionary)

Now, if a user were to only look at the initialization parameters, and wanted to add a ConceptDictionary later, after initalization, they could theoretically assume, they could set it like this:

my_aas.concept_dictionary = [my_concept_dictionary]

This would have terrible results when iterating over ObjectStores containing these objects, since suddenly, we'd get the (not very helpful) error:

AttributeError: 'list' object has no attribute 'update_nss_from' 

This obviously points nowhere in the right direction.

I have the suspicion, that this is not the only time, where such a problem may arise. How can we restrrict the user from making such a mistake in the first place? Should we write getter and setter functions for these kinds of attributes? On the other hand, maybe this is something to be checked by the ObjectStore, when adding an item to it?

Parsing AssetAdministrationShell fails when parsing `asset` element

When parsing an AssetAdministrationShell from json _construct_asset_administration_shell is expecting a type dict in asset element:

def _construct_asset_administration_shell(
            cls, dct: Dict[str, object], object_class=model.AssetAdministrationShell) -> model.AssetAdministrationShell:
        ret = object_class(
            asset=cls._construct_aas_reference(_get_ts(dct, 'asset', dict), model.Asset),
            identification=cls._construct_identifier(_get_ts(dct, 'identification', dict)))

However, at that point the asset element is already parsed and fails with:

TypeError: Dict entry 'asset' has unexpected type Asset

Changing the above line to

def _construct_asset_administration_shell(
            cls, dct: Dict[str, object], object_class=model.AssetAdministrationShell) -> model.AssetAdministrationShell:
        ret = object_class(
            asset=get_ts(dct, 'asset', model.Asset),
            identification=cls._construct_identifier(_get_ts(dct, 'identification', dict)))

seems to fix the problem.

Example python code:

    json_ = """
[
    {
        "conceptDictionary": [],
        "assetRef": {
            "keys": [
                {
                    "idType": "IRI",
                    "type": "Asset",
                    "value": "1030_8141_0112_5510",
                    "local": true
                }
            ]
        },
        "identification": {
            "idType": "IRI",
            "id": "1220_8141_0112_0875"
        },
        "idShort": "AAS",
        "dataSpecification": [],
        "derivedFrom": {
            "keys": [
                {
                    "idType": "IdShort",
                    "type": "AssetAdministrationShell",
                    "value": "6455_1111_0112_4769",
                    "local": true
                }
            ]
        },
        "modelType": {
            "name": "AssetAdministrationShell"
        },
        "asset": {
            "idShort": "CA",
            "modelType": {
                "name": "Asset"
            },
            "identification": {
                "id": "1030_8141_0112_5510",
                "idType": "IRI"
            },
            "kind": "Instance"
        },
        "embeddedDataSpecifications": [],
        "views": []
    }
]
    """
    shells = json.loads(json_, cls=basyx.aas.adapter.json.AASFromJsonDecoder)

Request for Example: Transferring Asset Administration Shell Model using OPC UA

Hello,

I am currently attempting to use your repository in conjunction with OPC UA to transfer Asset Administration Shell models. However, I'm facing some difficulties, particularly in the setup and configuration. Acutally i am a freshman about AAS.

I was wondering if it's possible for the community or contributors to provide an example or guide on how to achieve this. Any code snippets or pointers would be greatly appreciated.

Thanks in advance!

RDF serialization

Is there the possibility to serialize to/from RDF?
If not, is it in the todo list, or it is not in the priority list?

Compliance tool failed

How does the compliance tool work exactly? I tried to validate some same valid aasx.json files with the compliance tool, but It always shows the test failed.
The only time test was successful was when I ran the same files generated from examples that are already inside this repo.

The Getting Started is not working properly

Serialize the Submodel to XML:

from basyx.aas.adapter import write_aas_xml_file
should be
from basyx.aas.adapter.xml import write_aas_xml_file

Furthermore, I had to change
with open('Simple_Submodel.xml', 'w', encoding='utf-8') as f:
to
with open('Simple_Submodel.xml', 'wb') as f:

to get it working.
Is this just my problem or a general one?

adapter.aasx: resolution of `file://` references

When loading an AASX file, the aasx checks all submodels for File elements and tries to resolve the referenced files relative to the aasx container root. In Version 2.0, a document named TestFile.pdf in the AASX packages root would be referenced by a File element via the path /TestFile.pdf.
Since version 3.0, the schemata prohibit values like /TestFile.pdf and require the file:// protocol to be used, e.g. file:///TestFile.pdf. The problem is that File also supports remote references to files, for example via https://. This isn't allowed by the new schemata.

We should discuss whether the restrictions imposed by the schemata are actually correct, and if so, change the aasx adapter and examples accordingly.

See also:


value='https://www.plattform-i40.de/PI40/Redaktion/DE/Downloads/Publikation/Details-of-the-Asset-'
'Administration-Shell-Part1.pdf?__blob=publicationFile&v=5',

def _collect_supplementary_files(self, part_name: str, submodel: model.Submodel,
file_store: "AbstractSupplementaryFileContainer") -> None:
"""
Helper function to search File objects within a single parsed Submodel, extract the referenced supplementary
files and update the File object's values with the absolute path.
:param part_name: The OPC part name of the part the submodel has been parsed from. This is used to resolve
relative file paths.
:param submodel: The Submodel to process
:param file_store: The SupplementaryFileContainer to add the extracted supplementary files to
"""
for element in traversal.walk_submodel(submodel):
if isinstance(element, model.File):
if element.value is None:
continue
# Only absolute-path references and relative-path URI references (see RFC 3986, sec. 4.2) are considered
# to refer to files within the AASX package. Thus, we must skip all other types of URIs (esp. absolute
# URIs and network-path references)
if element.value.startswith('//') or ':' in element.value.split('/')[0]:
logger.info("Skipping supplementary file %s, since it seems to be an absolute URI or network-path "
"URI reference", element.value)
continue
absolute_name = pyecma376_2.package_model.part_realpath(element.value, part_name)
logger.debug("Reading supplementary file {} from AASX package ...".format(absolute_name))
with self.reader.open_part(absolute_name) as p:
final_name = file_store.add_file(absolute_name, p, self.reader.get_content_type(absolute_name))
element.value = final_name

Problem reading Nameplate template package

I am trying to see if I can import a template, in specific the Digital Nameplate. The aasx packages are located here .

Whenever I try to use the aasx.Reader and call read_into I get the following error:

KeyError: aas:mimeType on line 505 has no text!
 -> Failed to construct aas:file on line 495 using construct_submodel_element!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 590 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 627 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 664 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 701 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 738 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 775 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 812 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 849 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 886 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 923 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 960 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 997 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1034 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1071 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1108 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1145 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1182 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1219 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1256 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1293 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1330 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1367 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1404 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1441 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1478 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1515 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1552 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1589 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1626 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1659 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1691 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1723 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1755 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1787 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1819 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1851 using construct_administrative_information!
ValueError: A revision requires a version. This means, if there is no version there is no revision neither.
 -> Failed to construct aas:administration on line 1888 using construct_administrative_information!
IEC61360ConceptDescription[Identifier(IRI=https://admin-shell.io/zvei/nameplate/1/0/Nameplate)] has a duplicate identifier already parsed in the document! skipping it...

Code with the problem

template_path= "SMT_pure_ZVEI_Digital_Nameplate_V10.aasx"

new_object_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
new_file_store = aasx.DictSupplementaryFileContainer()
with aasx.AASXReader(template_path) as reader:
    reader.read_into(object_store=new_object_store,
                     file_store=new_file_store)

Utilize test data from `aas-core3.0-testgen` rather than our proprietary set.

Issue:
We've been using our proprietary test set for validating the SDK against the metamodel. However, with every change in the metamodel that necessitates an update to our SDK, we find ourselves having to make corresponding adjustments to our test data. This iterative process is resource-intensive and can lead to potential inconsistencies and oversights.

Proposal:
To streamline this process and ensure a more robust testing framework, we recommend transitioning to the test data provided by aas-core3.0-testgen. Here are the key benefits of making this switch:

  1. Comprehensive Coverage: The aas-core3.0-testgen provides an extensive set of test data, ensuring thorough validation of our SDK against a wide range of scenarios.

  2. Automatic Generation: The test data from aas-core3.0-testgen is automatically generated, which means we'll always have the most up-to-date test cases without the manual effort of creating or updating them.

  3. Reduced Maintenance: By relying on this external test set, we can significantly reduce the overhead associated with maintaining our own test data. This will allow our team to focus on enhancing the SDK and addressing other critical priorities.

  4. Consistency with the Community: Adopting a widely-used test set ensures that our SDK is in alignment with community standards and best practices.

Next Steps:
We should initiate a transition plan to integrate aas-core3.0-testgen test data into our testing pipeline. This will involve:

  • Setting up a mechanism to regularly fetch the latest test data from aas-core3.0-testgen.
  • Adapting our testing infrastructure to utilize this new data source.
  • Conducting an initial comprehensive test run to identify any gaps or inconsistencies.
  • Decommissioning our proprietary test set once the transition is complete and verified.

Assign value ModelReference to attribute "type" of class "Reference

I am trying to create an instance of basyx.aas.model.AASReference and specify its type (see 5.7.10.2 of Details of the Asset Adminstration Shell Version 3.0RC02).

From the examples I see that you can add a key attribute and its type

What I dont see in the examples and the source code is how to specify the attribute type to have the value ModelReference: from the enumeration ReferenceTypes from the spec.

Example of what I am trying to achieve:

keys= (model.Key(type_=model.KeyElements.SUBMODEL,
                             local=True,
                             value='MySubmodel',
                             id_type=model.KeyType.IDSHORT),
             model.Key(type_=model.KeyElements.CAPABILITY,
                               local=True,
                               value='MyCapability',
                               id_type=model.KeyType.IDSHORT) )
my_ref= model.AASReference(keys,target_type= ModelReference)

Default value of `base.Identifier`

Each class that inherits from the abstract class base.Identifiable has an attribute id.
By default, id is set to Identifier("").
The new Version 3.0 contains a constraint, that Identifier has a minimum of one character.

Therefore, it's necessary to set id to a new default value.
The current spec describes id as of type Identifier which prohibits the use of None.

We should discuss a suitable solution.

Compliance tool fails to check aasx package without thumbnail

When checking https://admin-shell-io.com/samples/aasx/22_Festo.aasx the compliance tool crashes due to an unhandled exception:

python3 ./basyx/aas/compliance_tool/cli.py -vv d --aasx  --json  22_Festo.aasx 
Traceback (most recent call last):
  File "~/.local/lib/python3.8/site-packages/pyecma376_2/package_model.py", line 150, in open_part
    part_descriptor = self._parts[normalize_part_name(name)]
KeyError: '/thumbnail.jpg'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "./basyx/aas/compliance_tool/cli.py", line 189, in <module>
    main()
  File "./basyx/aas/compliance_tool/cli.py", line 151, in main
    compliance_tool_aasx.check_deserialization(args.file_1, manager)
  File "~/Projects/basyx-python-sdk/basyx/aas/compliance_tool/compliance_check_aasx.py", line 86, in check_deserialization
    reader.read_into(obj_store, files)
  File "~/Projects/basyx-python-sdk/basyx/aas/adapter/aasx.py", line 151, in read_into
    self._read_aas_part_into(aas_part, object_store, file_store, read_identifiables, override_existing)
  File "~/Projects/basyx-python-sdk/basyx/aas/adapter/aasx.py", line 206, in _read_aas_part_into
    self._collect_supplementary_files(part_name, obj, file_store)
  File "~/Projects/basyx-python-sdk/basyx/aas/adapter/aasx.py", line 257, in _collect_supplementary_files
    with self.reader.open_part(absolute_name) as p:
  File "~/.local/lib/python3.8/site-packages/pyecma376_2/package_model.py", line 152, in open_part
    raise KeyError("Could not find part {} in package".format(name)) from e
KeyError: 'Could not find part /thumbnail.jpg in package'

Asset serialization not recognized by basyx-registry component

I am testing the Basyx registry component and I am having a problem when creating a new asset, saving it as AASX and sending it to the registry with the HTTP API .

As a test I have created a package from the example located here.

Afterwards I created a script to try to upload the package to the Basyx-registry but I get the following error:

{
    "success": false,
    "isException": true,
    "messages": [{
        "messageType": 6,
        "code": "400",
        "text": "MalformedRequestException: AssetAdministrationShellDescriptor is missing identification entry"
    }]
}

The script I am using to send the asset (.aasx) is the following:

import requests
import json
from basyx.aas import model
from basyx.aas.adapter import aasx
import basyx.aas.adapter.json


def AddAsset(asset_path):
    object_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
    file_store = aasx.DictSupplementaryFileContainer()
    with aasx.AASXReader(asset_path) as reader:
        reader.read_into(object_store=object_store,
                         file_store=file_store)

   #Store the serialized basyx json to debug the serialization
    with open('data.json', 'w', encoding='utf-8') as json_file:
        basyx.aas.adapter.json.write_aas_json_file(json_file, object_store)

    json_aasx_str = basyx.aas.adapter.json.object_store_to_json(object_store)
    json_aasx = json.loads(json_aasx_str)
    # Assuming there is only one asset
    asset_id = "asset_sample"
    json_aasx["shortId"]= asset_id #Removes bug about missing shortId in Asset Admin. shell descriptor
    registry_url = "http://localhost:8082/registry/api/v1/registry"
    asset_put = registry_url+"/"+asset_id
    payload = str(json_aasx)
    r = requests.put(asset_put, data=payload)
    print(r)
    print(r.content)
#Asset generated with basyx-python-sdk example
asset_path = "MyAASXPackage.aasx"
AddAsset(asset_path)

I am not sure if I am doing something wrong as I am still new to the basyx middleware and would be helpful to get any feedback at to where the problem might be located. As additional info, I tested the sample JSON payload in the Swaggerhub API website and that works fine but building the package with basxy-python-sdk and serializing for the HTTP endpoint is not working as expected.

What I have noticed is that the serialized JSON from the basyx-python-sdk API does not have a 'shortId', which I fixed by adding this key to the dictionary.

Fix `id_short` attribute defaulting to the string literal `NotSet`

The current behavior of the id_short attribute of Refereable objects is causing unexpected behavior in the codebase. It defaults to the string literal "NotSet" by default. This is problematic because it can lead to confusion and unexpected results when developers interact with this attribute.

We shoud find some other solution for idShort

Implement strict mode for reading AASX files

The sdk reads existing files with unsupported metamodell versions without throwing exceptions. The file contents will be not read.

Suggestion:

  • Implement raising exception if the metamodel version of a file is not supported

Incorrect parameter type hint or method realization of write_aas_xml_file()

The problem occures by using adapter/xml_serialization.py/write_aas_xml_file(). The method has file as parameter, which should be of type IO, but I get Exception, that the expected type of parameter file is str

Traceback (most recent call last):
.........\basyx\aas\adapter\xml\xml_serialization.py", line 897, in write_aas_xml_file
tree.write(file, encoding="UTF-8", xml_declaration=True, method="xml", **kwargs)
File "src\lxml\etree.pyx", line 2057, in lxml.etree._ElementTree.write
File "src\lxml\serializer.pxi", line 758, in lxml.etree._tofilelike
File "src\lxml\etree.pyx", line 318, in lxml.etree._ExceptionContext._raise_if_stored
File "src\lxml\serializer.pxi", line 682, in lxml.etree._FilelikeWriter.write
TypeError: write() argument must be str, not bytes

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.