Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions compliance_tool/aas_compliance_tool/compliance_check_aasx.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

def check_deserialization(file_path: str, state_manager: ComplianceToolStateManager,
file_info: Optional[str] = None) \
-> Tuple[model.DictObjectStore, aasx.DictSupplementaryFileContainer, pyecma376_2.OPCCoreProperties]:
-> Tuple[model.DictIdentifiableStore, aasx.DictSupplementaryFileContainer, pyecma376_2.OPCCoreProperties]:
"""
Read a AASX file and reports any issues using the given
:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager`
Expand Down Expand Up @@ -68,24 +68,24 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana
state_manager.set_step_status_from_log()
state_manager.add_step('Read file')
state_manager.set_step_status(Status.NOT_EXECUTED)
return model.DictObjectStore(), aasx.DictSupplementaryFileContainer(), pyecma376_2.OPCCoreProperties()
return model.DictIdentifiableStore(), aasx.DictSupplementaryFileContainer(), pyecma376_2.OPCCoreProperties()

try:
# read given file
state_manager.add_step('Read file')
obj_store: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
id_store: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()
files = aasx.DictSupplementaryFileContainer()
reader.read_into(obj_store, files)
reader.read_into(id_store, files)
new_cp = reader.get_core_properties()
state_manager.set_step_status(Status.SUCCESS)
except (ValueError, KeyError) as error:
logger.error(error)
state_manager.set_step_status(Status.FAILED)
return model.DictObjectStore(), aasx.DictSupplementaryFileContainer(), pyecma376_2.OPCCoreProperties()
return model.DictIdentifiableStore(), aasx.DictSupplementaryFileContainer(), pyecma376_2.OPCCoreProperties()
finally:
reader.close()

return obj_store, files, new_cp
return id_store, files, new_cp


def check_schema(file_path: str, state_manager: ComplianceToolStateManager) -> None:
Expand Down Expand Up @@ -187,7 +187,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager,

state_manager.add_step('Check if data is equal to example data')
example_data = create_example_aas_binding()
checker.check_object_store(obj_store, example_data)
checker.check_identifiable_store(obj_store, example_data)
state_manager.add_log_records_from_data_checker(checker)

if state_manager.status in (Status.FAILED, Status.NOT_EXECUTED):
Expand Down Expand Up @@ -238,22 +238,25 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager,

# Check if file in file object is the same
list_of_id_shorts = ["ExampleSubmodelCollection", "ExampleFile"]
obj = example_data.get_identifiable("https://acplt.org/Test_Submodel")
identifiable = example_data.get_item("https://acplt.org/Test_Submodel")
for id_short in list_of_id_shorts:
obj = obj.get_referable(id_short)
obj2 = obj_store.get_identifiable("https://acplt.org/Test_Submodel")
identifiable = identifiable.get_referable(id_short)
obj2 = obj_store.get_item("https://acplt.org/Test_Submodel")
for id_short in list_of_id_shorts:
obj2 = obj2.get_referable(id_short)
try:
sha_file = files.get_sha256(obj.value)
sha_file = files.get_sha256(identifiable.value)
except KeyError as error:
state_manager.add_log_records_from_data_checker(checker2)
logger.error(error)
state_manager.set_step_status(Status.FAILED)
return

checker2.check(sha_file == files.get_sha256(obj2.value), "File of {} must be {}.".format(obj.value, obj2.value),
value=obj2.value)
checker2.check(
sha_file == files.get_sha256(obj2.value),
"File of {} must be {}.".format(identifiable.value, obj2.value),
value=obj2.value
)
state_manager.add_log_records_from_data_checker(checker2)
if state_manager.status in (Status.FAILED, Status.NOT_EXECUTED):
state_manager.set_step_status(Status.FAILED)
Expand Down Expand Up @@ -294,7 +297,7 @@ def check_aasx_files_equivalence(file_path_1: str, file_path_2: str, state_manag
checker = AASDataChecker(raise_immediately=False, **kwargs)
try:
state_manager.add_step('Check if data in files are equal')
checker.check_object_store(obj_store_1, obj_store_2)
checker.check_identifiable_store(obj_store_1, obj_store_2)
except (KeyError, AssertionError) as error:
state_manager.set_step_status(Status.FAILED)
logger.error(error)
Expand Down
8 changes: 4 additions & 4 deletions compliance_tool/aas_compliance_tool/compliance_check_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def _check_schema(file_to_be_checked: IO[str], state_manager: ComplianceToolStat


def check_deserialization(file_path: str, state_manager: ComplianceToolStateManager,
file_info: Optional[str] = None) -> model.DictObjectStore:
file_info: Optional[str] = None) -> model.DictIdentifiableStore:
"""
Deserializes a JSON AAS file and reports any issues using the given
:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager`
Expand Down Expand Up @@ -140,7 +140,7 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana
else:
state_manager.add_step('Read file and check if it is deserializable')
state_manager.set_step_status(Status.NOT_EXECUTED)
return model.DictObjectStore()
return model.DictIdentifiableStore()

with file_to_be_checked:
state_manager.set_step_status(Status.SUCCESS)
Expand Down Expand Up @@ -184,7 +184,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager,
checker = AASDataChecker(raise_immediately=False, **kwargs)

state_manager.add_step('Check if data is equal to example data')
checker.check_object_store(obj_store, create_example())
checker.check_identifiable_store(obj_store, create_example())

state_manager.add_log_records_from_data_checker(checker)

Expand Down Expand Up @@ -220,7 +220,7 @@ def check_json_files_equivalence(file_path_1: str, file_path_2: str, state_manag
checker = AASDataChecker(raise_immediately=False, **kwargs)
try:
state_manager.add_step('Check if data in files are equal')
checker.check_object_store(obj_store_1, obj_store_2)
checker.check_identifiable_store(obj_store_1, obj_store_2)
except (KeyError, AssertionError) as error:
state_manager.set_step_status(Status.FAILED)
logger.error(error)
Expand Down
8 changes: 4 additions & 4 deletions compliance_tool/aas_compliance_tool/compliance_check_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def _check_schema(file_to_be_checked, state_manager):


def check_deserialization(file_path: str, state_manager: ComplianceToolStateManager,
file_info: Optional[str] = None) -> model.DictObjectStore:
file_info: Optional[str] = None) -> model.DictIdentifiableStore:
"""
Deserializes a XML AAS file and reports any issues using the given
:class:`~basyx.aas.compliance_tool.state_manager.ComplianceToolStateManager`
Expand Down Expand Up @@ -139,7 +139,7 @@ def check_deserialization(file_path: str, state_manager: ComplianceToolStateMana
else:
state_manager.add_step('Read file and check if it is deserializable')
state_manager.set_step_status(Status.NOT_EXECUTED)
return model.DictObjectStore()
return model.DictIdentifiableStore()

with file_to_be_checked:
state_manager.set_step_status(Status.SUCCESS)
Expand Down Expand Up @@ -183,7 +183,7 @@ def check_aas_example(file_path: str, state_manager: ComplianceToolStateManager,
checker = AASDataChecker(raise_immediately=False, **kwargs)

state_manager.add_step('Check if data is equal to example data')
checker.check_object_store(obj_store, create_example())
checker.check_identifiable_store(obj_store, create_example())

state_manager.add_log_records_from_data_checker(checker)

Expand Down Expand Up @@ -219,7 +219,7 @@ def check_xml_files_equivalence(file_path_1: str, file_path_2: str, state_manage
checker = AASDataChecker(raise_immediately=False, **kwargs)
try:
state_manager.add_step('Check if data in files are equal')
checker.check_object_store(obj_store_1, obj_store_2)
checker.check_identifiable_store(obj_store_1, obj_store_2)
except (KeyError, AssertionError) as error:
state_manager.set_step_status(Status.FAILED)
logger.error(error)
Expand Down
2 changes: 1 addition & 1 deletion compliance_tool/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ requires-python = ">=3.9"
dependencies = [
"pyecma376-2>=0.2.4",
"jsonschema>=4.21.1",
"basyx-python-sdk>=1.0.0",
"basyx-python-sdk @ file:../sdk",
]

[project.optional-dependencies]
Expand Down
6 changes: 3 additions & 3 deletions compliance_tool/test/test_aas_compliance_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def test_json_create_example(self) -> None:
json_object_store = read_aas_json_file(f, failsafe=False)
data = create_example()
checker = AASDataChecker(raise_immediately=True)
checker.check_object_store(json_object_store, data)
checker.check_identifiable_store(json_object_store, data)
os.unlink(filename)

def test_json_deserialization(self) -> None:
Expand Down Expand Up @@ -187,7 +187,7 @@ def test_xml_create_example(self) -> None:
xml_object_store = read_aas_xml_file(f, failsafe=False)
data = create_example()
checker = AASDataChecker(raise_immediately=True)
checker.check_object_store(xml_object_store, data)
checker.check_identifiable_store(xml_object_store, data)
os.unlink(filename)

def test_xml_deseralization(self) -> None:
Expand Down Expand Up @@ -229,7 +229,7 @@ def test_aasx_create_example(self) -> None:
self.assertIn('SUCCESS: Write data to file', str(output.stdout))

# Read AASX file
new_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
new_data: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()
new_files = aasx.DictSupplementaryFileContainer()
with aasx.AASXReader(filename) as reader:
reader.read_into(new_data, new_files)
Expand Down
2 changes: 1 addition & 1 deletion sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Serialize the `Submodel` to XML:
```python
from basyx.aas.adapter.xml import write_aas_xml_file

data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
data: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()
data.add(submodel)
write_aas_xml_file(file='Simple_Submodel.xml', data=data)
```
Expand Down
14 changes: 7 additions & 7 deletions sdk/basyx/aas/adapter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
from basyx.aas.adapter.aasx import AASXReader, DictSupplementaryFileContainer
from basyx.aas.adapter.json import read_aas_json_file_into
from basyx.aas.adapter.xml import read_aas_xml_file_into
from basyx.aas.model.provider import DictObjectStore
from basyx.aas.model.provider import DictIdentifiableStore
from pathlib import Path
from typing import Union


def load_directory(directory: Union[Path, str]) -> tuple[DictObjectStore, DictSupplementaryFileContainer]:
def load_directory(directory: Union[Path, str]) -> tuple[DictIdentifiableStore, DictSupplementaryFileContainer]:
"""
Create a new :class:`~basyx.aas.model.provider.DictObjectStore` and use it to load Asset Administration Shell and
Submodel files in ``AASX``, ``JSON`` and ``XML`` format from a given directory into memory. Additionally, load all
Expand All @@ -28,7 +28,7 @@ def load_directory(directory: Union[Path, str]) -> tuple[DictObjectStore, DictSu
:class:`~basyx.aas.adapter.aasx.DictSupplementaryFileContainer` containing all loaded data
"""

dict_object_store: DictObjectStore = DictObjectStore()
dict_identifiable_store: DictIdentifiableStore = DictIdentifiableStore()
file_container: DictSupplementaryFileContainer = DictSupplementaryFileContainer()

directory = Path(directory)
Expand All @@ -40,12 +40,12 @@ def load_directory(directory: Union[Path, str]) -> tuple[DictObjectStore, DictSu
suffix = file.suffix.lower()
if suffix == ".json":
with open(file) as f:
read_aas_json_file_into(dict_object_store, f)
read_aas_json_file_into(dict_identifiable_store, f)
elif suffix == ".xml":
with open(file) as f:
read_aas_xml_file_into(dict_object_store, f)
read_aas_xml_file_into(dict_identifiable_store, f)
elif suffix == ".aasx":
with AASXReader(file) as reader:
reader.read_into(object_store=dict_object_store, file_store=file_container)
reader.read_into(object_store=dict_identifiable_store, file_store=file_container)

return dict_object_store, file_container
return dict_identifiable_store, file_container
48 changes: 26 additions & 22 deletions sdk/basyx/aas/adapter/aasx.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ def _read_aas_part_into(self, part_name: str,
if isinstance(obj, model.Submodel):
self._collect_supplementary_files(part_name, obj, file_store)

def _parse_aas_part(self, part_name: str, **kwargs) -> model.DictObjectStore:
def _parse_aas_part(self, part_name: str, **kwargs) -> model.DictIdentifiableStore:
"""
Helper function to parse the AAS objects from a single JSON or XML part of the AASX package.

Expand All @@ -259,7 +259,7 @@ def _parse_aas_part(self, part_name: str, **kwargs) -> model.DictObjectStore:
logger.error(error_message)
else:
raise ValueError(error_message)
return model.DictObjectStore()
return model.DictIdentifiableStore()

def _collect_supplementary_files(self, part_name: str, submodel: model.Submodel,
file_store: "AbstractSupplementaryFileContainer") -> None:
Expand Down Expand Up @@ -352,7 +352,7 @@ def __init__(self, file: Union[os.PathLike, str, IO], failsafe: bool = True):

def write_aas(self,
aas_ids: Union[model.Identifier, Iterable[model.Identifier]],
object_store: model.AbstractObjectStore,
object_store: model.AbstractObjectStore[model.Identifier, model.Identifiable],
file_store: "AbstractSupplementaryFileContainer",
write_json: bool = False) -> None:
"""
Expand Down Expand Up @@ -402,10 +402,10 @@ def write_aas(self,
if isinstance(aas_ids, model.Identifier):
aas_ids = (aas_ids,)

objects_to_be_written: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
objects_to_be_written: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()
for aas_id in aas_ids:
try:
aas = object_store.get_identifiable(aas_id)
aas = object_store.get_item(aas_id)
if not isinstance(aas, model.AssetAdministrationShell):
raise TypeError(f"Identifier {aas_id} does not belong to an AssetAdministrationShell object but to "
f"{aas!r}")
Expand Down Expand Up @@ -479,9 +479,10 @@ def write_aas_objects(self,
A thin wrapper around :meth:`write_all_aas_objects` to ensure downwards compatibility

This method takes the AAS's :class:`~basyx.aas.model.base.Identifier` (as ``aas_id``) to retrieve it
from the given object_store. If the list of written objects includes :class:`~basyx.aas.model.submodel.Submodel`
objects, Supplementary files which are referenced by :class:`~basyx.aas.model.submodel.File` objects within
those Submodels, are also added to the AASX package.
from the given object_store. If the list of written identifiables includes
:class:`~basyx.aas.model.submodel.Submodel` identifiables, Supplementary files which are referenced by
:class:`~basyx.aas.model.submodel.File` identifiables within those Submodels, are also added to the AASX
package.

.. attention::

Expand All @@ -491,44 +492,47 @@ def write_aas_objects(self,
:param part_name: Name of the Part within the AASX package to write the files to. Must be a valid ECMA376-2
part name and unique within the package. The extension of the part should match the data format (i.e.
'.json' if ``write_json`` else '.xml').
:param object_ids: A list of :class:`Identifiers <basyx.aas.model.base.Identifier>` of the objects to be written
to the AASX package. Only these :class:`~basyx.aas.model.base.Identifiable` objects (and included
:class:`~basyx.aas.model.base.Referable` objects) are written to the package.
:param object_store: The objects store to retrieve the :class:`~basyx.aas.model.base.Identifiable` objects from
:param object_ids: A list of :class:`Identifiers <basyx.aas.model.base.Identifier>` of the identifiables to be
written to the AASX package. Only these :class:`~basyx.aas.model.base.Identifiable` identifiables
(and included :class:`~basyx.aas.model.base.Referable` identifiables) are written to the package.
:param object_store: The identifiables store to retrieve the :class:`~basyx.aas.model.base.Identifiable`
identifiables from
:param file_store: The
:class:`SupplementaryFileContainer <basyx.aas.adapter.aasx.AbstractSupplementaryFileContainer>`
to retrieve supplementary files from (if there are any :class:`~basyx.aas.model.submodel.File`
objects within the written objects.
identifiables within the written identifiables.
:param write_json: If ``True``, the part is written as a JSON file instead of an XML file. Defaults to
``False``.
:param split_part: If ``True``, no aas-spec relationship is added from the aasx-origin to this part. You must
make sure to reference it via an aas-spec-split relationship from another aas-spec part
:param additional_relationships: Optional OPC/ECMA376 relationships which should originate at the AAS object
part to be written, in addition to the aas-suppl relationships which are created automatically.
"""
logger.debug(f"Writing AASX part {part_name} with AAS objects ...")
logger.debug(f"Writing AASX part {part_name} with AAS identifiables ...")

objects: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
identifiables: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()

# Retrieve objects and scan for referenced supplementary files
# Retrieve identifiables and scan for referenced supplementary files
for identifier in object_ids:
try:
the_object = object_store.get_identifiable(identifier)
the_identifiable = object_store.get_item(identifier)
except KeyError:
if self.failsafe:
logger.error(f"Could not find object {identifier} in ObjectStore")
logger.error(f"Could not find identifiable {identifier} in IdentifiableStore")
continue
else:
raise KeyError(f"Could not find object {identifier!r} in ObjectStore")
objects.add(the_object)
raise KeyError(f"Could not find identifiable {identifier!r} in IdentifiableStore")
identifiables.add(the_identifiable)

self.write_all_aas_objects(part_name, objects, file_store, write_json, split_part, additional_relationships)
self.write_all_aas_objects(
part_name, identifiables, file_store, write_json, split_part, additional_relationships
)

# TODO remove `split_part` parameter in future version.
# Not required anymore since changes from DotAAS version 2.0.1 to 3.0RC01
def write_all_aas_objects(self,
part_name: str,
objects: model.AbstractObjectStore[model.Identifiable],
objects: model.AbstractObjectStore[model.Identifier, model.Identifiable],
file_store: "AbstractSupplementaryFileContainer",
write_json: bool = False,
split_part: bool = False,
Expand Down
Loading
Loading