Skip to content

Commit 1bb1c65

Browse files
committed
Resolve change requests
1 parent 39e3e69 commit 1bb1c65

9 files changed

Lines changed: 90 additions & 59 deletions

File tree

sdk/basyx/aas/adapter/aasx.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ def write_aas_objects(self,
504504
split_part: bool = False,
505505
additional_relationships: Iterable[pyecma376_2.OPCRelationship] = ()) -> None:
506506
"""
507-
A thin wrapper around :meth:`write_all_aas_objects` to ensure downwards compatibility
507+
A thin wrapper around :meth:`write_all_aas_objects` to ensure backward compatibility
508508
509509
This method takes the AAS's :class:`~basyx.aas.model.base.Identifier` (as ``aas_id``) to retrieve it
510510
from the given object_store. If the list of written identifiables includes

sdk/basyx/aas/backend/couchdb.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,14 @@ def __init__(self, url: str, database: str):
422422
)
423423
super().__init__(url, database)
424424

425+
def get_identifiable(self, identifier: model.Identifier) -> model.Identifiable:
426+
warnings.warn(
427+
"`get_identifiable()` is deprecated. Use `get_item()` from `CouchDBIdentifiableStore` instead.",
428+
DeprecationWarning,
429+
stacklevel=2,
430+
)
431+
return super().get_item(identifier)
432+
425433

426434
# #################################################################################################
427435
# Custom Exception classes for reporting errors during interaction with the CouchDB server

sdk/basyx/aas/backend/local_file.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,3 +184,11 @@ def __init__(self, directory_path: str):
184184
stacklevel=2,
185185
)
186186
super().__init__(directory_path)
187+
188+
def get_identifiable(self, identifier: model.Identifier) -> model.Identifiable:
189+
warnings.warn(
190+
"`get_identifiable()` is deprecated. Use `get_item()` from `LocalFileIdentifiableStore` instead.",
191+
DeprecationWarning,
192+
stacklevel=2,
193+
)
194+
return super().get_item(identifier)

sdk/basyx/aas/model/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import re
1919

2020
from . import datatypes, _string_constraints
21-
from .. import model
2221

2322
if TYPE_CHECKING:
2423
from . import provider

sdk/basyx/aas/model/provider.py

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2025 the Eclipse BaSyx Authors
1+
# Copyright (c) 2026 the Eclipse BaSyx Authors
22
#
33
# This program and the accompanying materials are made available under the terms of the MIT License, available in
44
# the LICENSE file of this project.
@@ -17,36 +17,37 @@
1717
from .base import Identifier, Identifiable
1818

1919

20-
_K = TypeVar('_K')
21-
_V = TypeVar('_V')
20+
_KEY = TypeVar('_KEY') # Generic key type
21+
_VALUE = TypeVar('_VALUE') # Generic value type
2222

2323

24-
class AbstractObjectProvider(Generic[_K, _V], metaclass=abc.ABCMeta):
24+
class AbstractObjectProvider(Generic[_KEY, _VALUE], metaclass=abc.ABCMeta):
2525
"""
26-
Documentation when we agree on this solution.
26+
Abstract base class for all objects that allow retrieving values by a key.
27+
28+
This includes local object stores, database clients and AAS API clients.
2729
"""
2830

2931
@abc.abstractmethod
30-
def get_item(self, key: _K) -> _V:
32+
def get_item(self, key: _KEY) -> _VALUE:
3133
"""Retrieve the item or raise a KeyError."""
3234
pass
3335

34-
def get(self, key: _K, default: Optional[_V] = None) -> Optional[_V]:
36+
def get(self, key: _KEY, default: Optional[_VALUE] = None) -> Optional[_VALUE]:
3537
"""Retrieve the item or return a default value."""
3638
try:
3739
return self.get_item(key)
3840
except KeyError:
3941
return default
4042

4143

42-
class AbstractObjectStore(AbstractObjectProvider[_K, _V], MutableSet[_V]):
44+
class AbstractObjectStore(AbstractObjectProvider[_KEY, _VALUE], MutableSet[_VALUE]):
4345
"""
44-
Abstract baseclass of for container-like objects for storage of :class:`~basyx.aas.model.base.Identifiable` objects.
46+
Abstract base class for container-like objects for storage of values.
4547
46-
ObjectStores are special ObjectProvides that – in addition to retrieving objects by
47-
:class:`~basyx.aas.model.base.Identifier` – allow to add and delete objects (i.e. behave like a Python set).
48-
This includes local object stores (like :class:`~.DictObjectStore`) and specific object stores
49-
(like :class:`~basyx.aas.backend.couchdb.CouchDBObjectStore` and
48+
ObjectStores are special ObjectProviders that, in addition to retrieving values by a key, allow adding and deleting
49+
values (i.e. behave like a Python set). This includes local object stores (like :class:`~.DictObjectStore`) and
50+
specific object stores (like :class:`~basyx.aas.backend.couchdb.CouchDBObjectStore` and
5051
:class:`~basyx.aas.backend.local_file.LocalFileObjectStore`).
5152
5253
The AbstractObjectStore inherits from the :class:`~collections.abc.MutableSet` abstract collections class and
@@ -57,22 +58,20 @@ class AbstractObjectStore(AbstractObjectProvider[_K, _V], MutableSet[_V]):
5758
def __init__(self):
5859
pass
5960

60-
def update(self, other: Iterable[_V]) -> None:
61+
def update(self, other: Iterable[_VALUE]) -> None:
6162
for x in other:
6263
self.add(x)
6364

64-
def sync(self, other: Iterable[_V], overwrite: bool) -> Tuple[int, int, int]:
65+
def sync(self, other: Iterable[_VALUE], overwrite: bool) -> Tuple[int, int, int]:
6566
"""
66-
Merge :class:`Identifiables <basyx.aas.model.base.Identifiable>` from an
67-
:class:`~collections.abc.Iterable` into this :class:`~basyx.aas.model.provider.AbstractObjectStore`.
67+
Merge values from an :class:`~collections.abc.Iterable` into this
68+
:class:`~basyx.aas.model.provider.AbstractObjectStore`.
6869
6970
:param other: :class:`~collections.abc.Iterable` to sync with
70-
:param overwrite: Flag to overwrite existing :class:`Identifiables <basyx.aas.model.base.Identifiable>` in this
71+
:param overwrite: Flag to overwrite existing values in this
7172
:class:`~basyx.aas.model.provider.AbstractObjectStore` with updated versions from ``other``,
72-
:class:`Identifiables <basyx.aas.model.base.Identifiable>` unique to this
73-
:class:`~basyx.aas.model.provider.AbstractObjectStore` are always preserved
74-
:return: Counts of processed :class:`Identifiables <basyx.aas.model.base.Identifiable>` as
75-
``(added, overwritten, skipped)``
73+
values unique to this :class:`~basyx.aas.model.provider.AbstractObjectStore` are always preserved
74+
:return: Counts of processed values as``(added, overwritten, skipped)``
7675
"""
7776
added, overwritten, skipped = 0, 0, 0
7877
for value in other:
@@ -103,6 +102,31 @@ def sync(self, other: Iterable[_V], overwrite: bool) -> Tuple[int, int, int]:
103102
return added, overwritten, skipped
104103

105104

105+
class ObjectProviderMultiplexer(AbstractObjectProvider[_KEY, _VALUE]):
106+
"""
107+
A multiplexer for :class:`AbstractObjectProviders <.AbstractObjectProvider>`.
108+
109+
This class combines multiple :class:`AbstractObjectProviders <.AbstractObjectProvider>` into a single one to allow
110+
retrieving values from different sources. It implements the :class:`~.AbstractObjectProvider` interface to be used
111+
as registry itself.
112+
113+
:param registries: A list of :class:`AbstractObjectProviders <.AbstractObjectProvider>` to query when looking up a
114+
key
115+
"""
116+
117+
def __init__(self, registries: Optional[List[AbstractObjectProvider[_KEY, _VALUE]]] = None) -> None:
118+
self.providers: List[AbstractObjectProvider[_KEY, _VALUE]] = registries if registries is not None else []
119+
120+
def get_item(self, key: _KEY) -> _VALUE:
121+
for provider in self.providers:
122+
try:
123+
return provider.get_item(key)
124+
except KeyError:
125+
pass
126+
raise KeyError("Key could not be found in any of the {} consulted registries."
127+
.format(len(self.providers)))
128+
129+
106130
_IT = TypeVar('_IT', bound=Identifiable)
107131

108132

@@ -153,7 +177,7 @@ def __iter__(self) -> Iterator[_IT]:
153177
return iter(self._backend.values())
154178

155179

156-
class DictObjectStore(DictIdentifiableStore):
180+
class DictObjectStore(DictIdentifiableStore[_IT]):
157181
"""
158182
`DictObjectStore` has been renamed to :class:`~.DictIdentifiableStore` and will be removed in a future release.
159183
Please migrate to :class:`~.DictIdentifiableStore`.
@@ -168,6 +192,14 @@ def __init__(self, iterables: Iterable[_IT] = ()) -> None:
168192
)
169193
super().__init__(iterables)
170194

195+
def get_identifiable(self, identifier: Identifier) -> _IT:
196+
warnings.warn(
197+
"`get_identifiable()` is deprecated. Use `get_item()` from `DictIdentifiableStore` instead.",
198+
DeprecationWarning,
199+
stacklevel=2,
200+
)
201+
return super().get_item(identifier)
202+
171203

172204
class SetIdentifiableStore(AbstractObjectStore[Identifier, _IT]):
173205
"""
@@ -228,7 +260,7 @@ def __iter__(self) -> Iterator[_IT]:
228260
return iter(self._backend)
229261

230262

231-
class SetObjectStore(SetIdentifiableStore):
263+
class SetObjectStore(SetIdentifiableStore[_IT]):
232264
"""
233265
`SetObjectStore` has been renamed to :class:`~.SetIdentifiableStore` and will be removed in a future release.
234266
Please migrate to :class:`~.SetIdentifiableStore`.
@@ -243,27 +275,10 @@ def __init__(self, objects: Iterable[_IT] = ()) -> None:
243275
)
244276
super().__init__(objects)
245277

246-
247-
class ObjectProviderMultiplexer(AbstractObjectProvider[_K, _V]):
248-
"""
249-
A multiplexer for Providers of :class:`~basyx.aas.model.base.Identifiable` objects.
250-
251-
This class combines multiple registries of :class:`~basyx.aas.model.base.Identifiable` objects into a single one
252-
to allow retrieving :class:`~basyx.aas.model.base.Identifiable` objects from different sources.
253-
It implements the :class:`~.AbstractObjectProvider` interface to be used as registry itself.
254-
255-
:param registries: A list of :class:`AbstractObjectProviders <.AbstractObjectProvider>` to query when looking up an
256-
object
257-
"""
258-
259-
def __init__(self, registries: Optional[List[AbstractObjectProvider[_K, _V]]] = None) -> None:
260-
self.providers: List[AbstractObjectProvider[_K, _V]] = registries if registries is not None else []
261-
262-
def get_item(self, key: _K) -> _V:
263-
for provider in self.providers:
264-
try:
265-
return provider.get_item(key)
266-
except KeyError:
267-
pass
268-
raise KeyError("Key could not be found in any of the {} consulted registries."
269-
.format(len(self.providers)))
278+
def get_identifiable(self, identifier: Identifier) -> _IT:
279+
warnings.warn(
280+
"`get_identifiable()` is deprecated. Use `get_item()` from `SetIdentifiableStore` instead.",
281+
DeprecationWarning,
282+
stacklevel=2,
283+
)
284+
return super().get_item(identifier)

sdk/docs/source/model/provider.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ provider - Providers for storing and retrieving AAS-objects
33

44
.. automodule:: basyx.aas.model.provider
55

6-
.. autoclass:: _K
7-
.. autoclass:: _V
6+
.. autoclass:: _KEY
7+
.. autoclass:: _VALUE
88
.. autoclass:: _IT

sdk/test/adapter/aasx/test_aasx.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ def test_only_referenced_submodels(self):
175175
)
176176

177177
# ObjectStore containing all objects
178-
object_store = model.DictObjectStore([aas, referenced_submodel, unreferenced_submodel])
178+
object_store = model.DictIdentifiableStore([aas, referenced_submodel, unreferenced_submodel])
179179

180180
# Empty SupplementaryFileContainer (no files needed)
181181
file_store = aasx.DictSupplementaryFileContainer()
@@ -197,7 +197,7 @@ def test_only_referenced_submodels(self):
197197
)
198198

199199
# Read back
200-
new_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
200+
new_data: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()
201201
new_files = aasx.DictSupplementaryFileContainer()
202202
with aasx.AASXReader(filename) as reader:
203203
reader.read_into(new_data, new_files)
@@ -224,7 +224,7 @@ def test_only_referenced_submodels(self):
224224
)
225225

226226
# Read back
227-
new_data: model.DictObjectStore[model.Identifiable] = model.DictObjectStore()
227+
new_data: model.DictIdentifiableStore[model.Identifiable] = model.DictIdentifiableStore()
228228
new_files = aasx.DictSupplementaryFileContainer()
229229
with aasx.AASXReader(filename) as reader:
230230
reader.read_into(new_data, new_files)

sdk/test/backend/test_local_file.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
# SPDX-License-Identifier: MIT
77
import os.path
88
import shutil
9-
import unittest.mock
9+
10+
from unittest import TestCase
1011

1112
from basyx.aas.backend import local_file
1213
from basyx.aas.examples.data.example_aas import *
@@ -16,7 +17,7 @@
1617
source_core: str = "file://localhost/{}/".format(store_path)
1718

1819

19-
class LocalFileBackendTest(unittest.TestCase):
20+
class LocalFileBackendTest(TestCase):
2021
def setUp(self) -> None:
2122
self.identifiable_store = local_file.LocalFileIdentifiableStore(store_path)
2223
self.identifiable_store.check_directory(create=True)

server/test/interfaces/test_repository.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def _check_transformed(response, case):
9191

9292
class APIWorkflowAAS(AAS_SCHEMA.as_state_machine()): # type: ignore
9393
def setup(self):
94-
self.schema.app.coch_identifiable_store = create_full_example()
94+
self.schema.app.identifiable_store = create_full_example()
9595
# select random identifier for each test scenario
9696
self.schema.base_url = BASE_URL + "/aas/" + random.choice(tuple(IDENTIFIER_AAS))
9797

@@ -108,7 +108,7 @@ def validate_response(self, response, case, additional_checks=()) -> None:
108108

109109
class APIWorkflowSubmodel(SUBMODEL_SCHEMA.as_state_machine()): # type: ignore
110110
def setup(self):
111-
self.schema.app.coch_identifiable_store = create_full_example()
111+
self.schema.app.identifiable_store = create_full_example()
112112
self.schema.base_url = BASE_URL + "/submodels/" + random.choice(tuple(IDENTIFIER_SUBMODEL))
113113

114114
def transform(self, result, direction, case):

0 commit comments

Comments
 (0)