From 9c4d40e9ef91c798fdb5b73fd8dcb1c2204659ae Mon Sep 17 00:00:00 2001 From: zrgt Date: Tue, 12 May 2026 23:47:02 +0200 Subject: [PATCH 1/4] Fix load_directory to handle Descriptor objects (not Identifiable) --- server/app/model/provider.py | 44 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/server/app/model/provider.py b/server/app/model/provider.py index 97067e7d..3f529118 100644 --- a/server/app/model/provider.py +++ b/server/app/model/provider.py @@ -1,10 +1,10 @@ +import json from pathlib import Path from typing import IO, Dict, Iterable, Iterator, Union from basyx.aas import model from basyx.aas.model import provider as sdk_provider -import app.adapter as adapter from app.model import descriptor PathOrIO = Union[Path, IO] @@ -51,29 +51,35 @@ def __iter__(self) -> Iterator[_DESCRIPTOR_TYPE]: return iter(self._backend.values()) +_DESCRIPTOR_KEY_TO_CLS = ( + ("assetAdministrationShellDescriptors", descriptor.AssetAdministrationShellDescriptor), + ("submodelDescriptors", descriptor.SubmodelDescriptor), +) + + def load_directory(directory: Union[Path, str]) -> DictDescriptorStore: """ - Create a new :class:`~basyx.aas.model.provider.DictIdentifiableStore` 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 embedded supplementary files into a new :class:`~basyx.aas.adapter.aasx.DictSupplementaryFileContainer`. - - :param directory: :class:`~pathlib.Path` or ``str`` pointing to the directory containing all Asset Administration - Shell and Submodel files to load - :return: Tuple consisting of a :class:`~basyx.aas.model.provider.DictIdentifiableStore` and a - :class:`~basyx.aas.adapter.aasx.DictSupplementaryFileContainer` containing all loaded data - """ + Load AAS/Submodel descriptor JSON files from a directory into a :class:`DictDescriptorStore`. - dict_descriptor_store: DictDescriptorStore = DictDescriptorStore() + :param directory: Path to the directory containing JSON descriptor files + :return: Populated :class:`DictDescriptorStore` + """ + from app.adapter import ServerAASFromJsonDecoder + store = DictDescriptorStore() directory = Path(directory) for file in directory.iterdir(): - if not file.is_file(): + if not file.is_file() or file.suffix.lower() != ".json": continue - - suffix = file.suffix.lower() - if suffix == ".json": - with open(file) as f: - adapter.read_server_aas_json_file_into(dict_descriptor_store, f) - - return dict_descriptor_store + with open(file) as f: + data = json.load(f, cls=ServerAASFromJsonDecoder) + for key, cls in _DESCRIPTOR_KEY_TO_CLS: + for item in data.get(key, []): + if isinstance(item, cls): + try: + store.add(item) + except KeyError: + pass + + return store From 56798a20de9c30542cd8ebfe103d528bc188151c Mon Sep 17 00:00:00 2001 From: zrgt Date: Wed, 13 May 2026 15:05:23 +0200 Subject: [PATCH 2/4] Use explicit loops instead of _DESCRIPTOR_KEY_TO_CLS in load_directory --- server/app/model/provider.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/server/app/model/provider.py b/server/app/model/provider.py index 3f529118..067c8b90 100644 --- a/server/app/model/provider.py +++ b/server/app/model/provider.py @@ -51,12 +51,6 @@ def __iter__(self) -> Iterator[_DESCRIPTOR_TYPE]: return iter(self._backend.values()) -_DESCRIPTOR_KEY_TO_CLS = ( - ("assetAdministrationShellDescriptors", descriptor.AssetAdministrationShellDescriptor), - ("submodelDescriptors", descriptor.SubmodelDescriptor), -) - - def load_directory(directory: Union[Path, str]) -> DictDescriptorStore: """ Load AAS/Submodel descriptor JSON files from a directory into a :class:`DictDescriptorStore`. @@ -74,12 +68,17 @@ def load_directory(directory: Union[Path, str]) -> DictDescriptorStore: continue with open(file) as f: data = json.load(f, cls=ServerAASFromJsonDecoder) - for key, cls in _DESCRIPTOR_KEY_TO_CLS: - for item in data.get(key, []): - if isinstance(item, cls): - try: - store.add(item) - except KeyError: - pass + for item in data.get("assetAdministrationShellDescriptors", []): + if isinstance(item, descriptor.AssetAdministrationShellDescriptor): + try: + store.add(item) + except KeyError: + pass + for item in data.get("submodelDescriptors", []): + if isinstance(item, descriptor.SubmodelDescriptor): + try: + store.add(item) + except KeyError: + pass return store From dd19ad8e58fa1fdee389387f7e384b3331e3ace1 Mon Sep 17 00:00:00 2001 From: zrgt Date: Wed, 13 May 2026 22:02:40 +0200 Subject: [PATCH 3/4] Move ServerAASFromJsonDecoder import to module level in provider.py --- server/app/model/provider.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/app/model/provider.py b/server/app/model/provider.py index 067c8b90..409570fe 100644 --- a/server/app/model/provider.py +++ b/server/app/model/provider.py @@ -5,6 +5,7 @@ from basyx.aas import model from basyx.aas.model import provider as sdk_provider +from app.adapter import ServerAASFromJsonDecoder from app.model import descriptor PathOrIO = Union[Path, IO] @@ -58,8 +59,6 @@ def load_directory(directory: Union[Path, str]) -> DictDescriptorStore: :param directory: Path to the directory containing JSON descriptor files :return: Populated :class:`DictDescriptorStore` """ - from app.adapter import ServerAASFromJsonDecoder - store = DictDescriptorStore() directory = Path(directory) From 87f81501197e9f78e6f52e730600d39843d9421f Mon Sep 17 00:00:00 2001 From: zrgt Date: Wed, 13 May 2026 22:05:46 +0200 Subject: [PATCH 4/4] Remove unused read_server_aas_json_file_into and its imports --- server/app/adapter/jsonization.py | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/server/app/adapter/jsonization.py b/server/app/adapter/jsonization.py index a8ee3471..897590c7 100644 --- a/server/app/adapter/jsonization.py +++ b/server/app/adapter/jsonization.py @@ -1,10 +1,10 @@ import logging -from typing import Callable, Dict, Optional, Set, Type +from typing import Callable, Dict, Type from basyx.aas import model -from basyx.aas.adapter._generic import ASSET_KIND, ASSET_KIND_INVERSE, JSON_AAS_TOP_LEVEL_KEYS_TO_TYPES, PathOrIO +from basyx.aas.adapter._generic import ASSET_KIND, ASSET_KIND_INVERSE, JSON_AAS_TOP_LEVEL_KEYS_TO_TYPES from basyx.aas.adapter.json import AASToJsonEncoder -from basyx.aas.adapter.json.json_deserialization import AASFromJsonDecoder, _get_ts, read_aas_json_file_into +from basyx.aas.adapter.json.json_deserialization import AASFromJsonDecoder, _get_ts import app.model as server_model @@ -207,27 +207,6 @@ class ServerStrictStrippedAASFromJsonDecoder(ServerStrictAASFromJsonDecoder, Ser pass -def read_server_aas_json_file_into( - object_store: model.AbstractObjectStore, - file: PathOrIO, - replace_existing: bool = False, - ignore_existing: bool = False, - failsafe: bool = True, - stripped: bool = False, - decoder: Optional[Type[AASFromJsonDecoder]] = None, -) -> Set[model.Identifier]: - return read_aas_json_file_into( - object_store=object_store, - file=file, - replace_existing=replace_existing, - ignore_existing=ignore_existing, - failsafe=failsafe, - stripped=stripped, - decoder=decoder, - keys_to_types=JSON_SERVER_AAS_TOP_LEVEL_KEYS_TO_TYPES, - ) - - class ServerAASToJsonEncoder(AASToJsonEncoder): @classmethod