-
Notifications
You must be signed in to change notification settings - Fork 42
Open
Description
I'm trying to take an existing Python library, and allow it to be used remotely over the network. The library creates and returns Python objects which contain C library handles, so AFAIK they cannot be serialized, and need to be auto-proxied.
So far so good. But, I am running into trouble with autoproxy object lifetimes. When an autoproxy proxy handle goes out of scope, the corresponding server object is never released.
Some pytests which I believe should succeed, yet two fail. Edit: python==3.12.3, Pyro5==5.15, pytest==8.2.2
from concurrent.futures import ThreadPoolExecutor
import pytest
from Pyro5.api import Daemon, Proxy, behavior, expose
@expose
class Child:
def __init__(self, name: str, alive: set[str]):
self.__name = name
self.__alive = alive
alive.add(name)
def __del__(self):
self.__alive.remove(self.__name)
def __repr__(self):
return self.__name
def ping(self):
return f"I am {self.__name}"
_live_objects: set[str]
@expose
@behavior(instance_mode="session", instance_creator=lambda clazz: clazz(_live_objects))
class Parent:
_pyroDaemon: Daemon
def __init__(self, alive: set[str]):
self.__name = f"outer {id(self)}"
self.__alive = alive
alive.add(self.__name)
def __del__(self):
self.__alive.remove(self.__name)
def __repr__(self):
return self.__name
def ping(self):
return f"I am {self.__name}"
def createInstance(self, weak=False):
i = Child(name="single instance", alive=self.__alive)
self._pyroDaemon.register(i, weak)
return i
def createGenerator(self, weak=False):
ii = [
Child(name=f"iterator instance {i}", alive=self.__alive) for i in range(4)
]
for i in ii:
self._pyroDaemon.register(i, weak)
yield i
@pytest.fixture
def proxy():
global _live_objects
_live_objects = set()
with ThreadPoolExecutor(max_workers=1) as e, Daemon() as daemon:
uri = daemon.register(Parent, force=True)
must_shutdown = False
_ = e.submit(daemon.requestLoop, lambda: not must_shutdown)
with Proxy(uri) as proxy1, Proxy(uri) as proxy2:
yield proxy1, proxy2
must_shutdown = True
assert not _live_objects, "some objects were not cleaned up"
# succeeds
def test_proxy_lifetime(proxy):
p1, p2 = proxy
assert "outer" in p1.ping()
assert "outer" in p2.ping()
# fails teardown: AssertionError: some objects were not cleaned up
def test_instance_lifetime(proxy):
p, _ = proxy
assert "outer" in p.ping()
inner = p.createInstance()
assert "single instance" in inner.ping()
# fails teardown: AssertionError: some objects were not cleaned up
def test_generator_lifetime(proxy):
p, _ = proxy
for inner in p.createGenerator():
assert "iterator instance" in inner.ping()Metadata
Metadata
Assignees
Labels
No labels