Skip to content

Passing "parents" of type DataService to "children" (of type DataService) does not work #31

@mosmuell

Description

@mosmuell

Passing the parent to a child DataService does not work with the current implementation (and probably shouldn't). When registering callbacks, this will produce a recursive loop. At the moment, it just does not work as some assumptions are not fulfilled.

from typing import Optional

import pydase


class OtherService(pydase.DataService):
    _parent: Optional["MyService"]

    def __init__(self, parent: Optional["MyService"] = None) -> None:
        super().__init__()
        self._parent = parent


class MyService(pydase.DataService):
    def __init__(self) -> None:
        super().__init__()
        self.child = OtherService(self)


if __name__ == "__main__":
    service = MyService()
    pydase.Server(service).run()

This results in the following error message:

Thread stopped due to exception of type KeyError       (note: full exception trace is shown but execution is paused at: _run_module_as_main) (unhandled)
Description: '__root__'
Stack trace:
  File "/home/mose/work/repositories/pydase/src/pydase/utils/helpers.py", line 21, in get_class_and_instance_attributes
    attrs.pop("__root__")
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 87, in _register_list_change_callbacks
    attrs = get_class_and_instance_attributes(obj)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 92, in _register_list_change_callbacks
    self._register_list_change_callbacks(attr_value, new_path)
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 367, in register_callbacks
    self._register_list_change_callbacks(
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/data_service.py", line 56, in __init__
    self._callback_manager.register_callbacks()
  File "/home/mose/work/repositories/pydase/foo.py", line 12, in __init__
    super().__init__()
  File "/home/mose/work/repositories/pydase/foo.py", line 17, in __init__
    child = OtherService(self)
            ^^^^^^^^^^^^^^^^^^
  File "/home/mose/work/repositories/pydase/foo.py", line 22, in <module>
    service = MyService()
              ^^^^^^^^^^^
  File "/usr/lib64/python3.11/runpy.py", line 88, in _run_code
    exec(code, run_globals)
  File "/usr/lib64/python3.11/runpy.py", line 198, in _run_module_as_main (Current frame)
    return _run_code(code, main_globals, None,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: '__root__'

When changing the helper function code to

    attrs.pop("__root__", None)

I get another error:

Thread stopped due to exception of type AttributeError       (note: full exception trace is shown but execution is paused at: _run_module_as_main) (unhandled)
Description: 'MyService' object has no attribute '_callback_manager'
Stack trace:
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 176, in _register_DataService_instance_callbacks
    obj._callback_manager.callbacks.add(callback)
    ^^^^^^^^^^^^^^^^^^^^^
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 211, in _register_service_callbacks
    self._register_DataService_instance_callbacks(nested_attr, new_path)
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 187, in _register_DataService_instance_callbacks
    self._register_service_callbacks(
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/callback_manager.py", line 370, in register_callbacks
    self._register_DataService_instance_callbacks(
  File "/home/mose/work/repositories/pydase/src/pydase/data_service/data_service.py", line 56, in __init__
    self._callback_manager.register_callbacks()
  File "/home/mose/work/repositories/pydase/foo.py", line 11, in __init__
    super().__init__()
  File "/home/mose/work/repositories/pydase/foo.py", line 16, in __init__
    child = OtherService(self)
            ^^^^^^^^^^^^^^^^^^
  File "/home/mose/work/repositories/pydase/foo.py", line 21, in <module>
    service = MyService()
              ^^^^^^^^^^^
  File "/usr/lib64/python3.11/runpy.py", line 88, in _run_code
    exec(code, run_globals)
  File "/usr/lib64/python3.11/runpy.py", line 198, in _run_module_as_main (Current frame)
    return _run_code(code, main_globals, None,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'MyService' object has no attribute '_callback_manager'

Passing the "parent" instance to the "children" should not be done. Maybe I can throw an exception, explaining this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationquestionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions