Repository: FreeOpcUa/opcua-asyncio

Issue:
How to pass the cache file to the server
In the docstring at https://github.com/FreeOpcUa/opcua-asyncio/blob/f2f7722d945dbbc04ab20a87f6aff17496f7edf1/asyncua/server/server.py#L58 and on the project documentation at https://pypi.org/project/asyncua/ it is mentioned that one can pass a cache file to the server to improve startup time.

But nowhere it is mentioned *how* to do this. Is this still possible? Or is the documentation just outdated and it isn't possible anymore?


Discussion:
Sounds like the pickle file of the aspace which can be dumped/loaded.
https://github.com/FreeOpcUa/opcua-asyncio/blob/cfe23db170473a0a8e28665c9f24c80b34fbde30/asyncua/server/address_space.py#L691

But tbh, I have never tried that way.

EDIT: But still, the doc at this place may be missleading
Looking into the source I saw that one can pass a `shelf_file` to `init`: https://github.com/FreeOpcUa/opcua-asyncio/blob/f2f7722d945dbbc04ab20a87f6aff17496f7edf1/asyncua/server/server.py#L107 and then passed to https://github.com/FreeOpcUa/opcua-asyncio/blob/f2f7722d945dbbc04ab20a87f6aff17496f7edf1/asyncua/server/address_space.py#L698 which writes the shelf file.

But on the second run it just hits the `NotImplementedError` when trying to load the shelf file again https://github.com/FreeOpcUa/opcua-asyncio/blob/f2f7722d945dbbc04ab20a87f6aff17496f7edf1/asyncua/server/address_space.py#L718



Patch:
diff --git a/asyncua/server/address_space.py b/asyncua/server/address_space.py
index 07de08c86..7a0729156 100644
--- a/asyncua/server/address_space.py
+++ b/asyncua/server/address_space.py
@@ -711,25 +711,23 @@ def make_aspace_shelf(self, path: Path):
             for nodeid, ndata in self._nodes.items():
                 s[nodeid.to_string()] = ndata
 
-    def load_aspace_shelf(self, path):
+    def load_aspace_shelf(self, path: Path):
         """
         Load the standard address space nodes from a python shelve via LazyLoadingDict as needed.
         The dump() method can no longer be used if the address space is being loaded from a shelf
 
         Note: Intended for slow devices, such as Raspberry Pi, to greatly improve start up time
         """
-        raise NotImplementedError
 
-        # ToDo: async friendly implementation - load all at once?
         class LazyLoadingDict(collections.abc.MutableMapping):
             """
             Special dict that only loads nodes as they are accessed. If a node is accessed it gets copied from the
-            shelve to the cache dict. All user nodes are saved in the cache ONLY. Saving data back to the shelf
+            shelf to the cache dict. All user nodes are saved in the cache ONLY. Saving data back to the shelf
             is currently NOT supported
             """
 
-            def __init__(self, source):
-                self.source = source  # python shelf
+            def __init__(self, source: shelve.Shelf):
+                self.source: shelve.Shelf = source  # python shelf
                 self.cache = {}  # internal dict
 
             def __getitem__(self, key):
@@ -759,7 +757,7 @@ def __len__(self):
                 # only returns the length of items in the cache, not unaccessed items in the shelf
                 return len(self.cache)
 
-        self._nodes = LazyLoadingDict(shelve.open(path, "r"))
+        self._nodes = LazyLoadingDict(shelve.open(str(path), "r"))
 
     def read_attribute_value(self, nodeid: ua.NodeId, attr: ua.AttributeIds) -> ua.DataValue:
         # self.logger.debug("get attr val: %s %s", nodeid, attr)


Test patch:
diff --git a/tests/test_server.py b/tests/test_server.py
index b41be5b7b..c0134cd26 100644
--- a/tests/test_server.py
+++ b/tests/test_server.py
@@ -780,7 +780,6 @@ async def test_message_limits_works(restore_transport_limits_server: Server):
         await n.read_value()
 
 
-@pytest.mark.xfail(reason="FIXME broken", strict=True)
 async def test_runTest(tmp_path: Path):
     demo_shelf_file: Path = tmp_path / "some_shelf"