From 7d4ce31730a50bf41605b697b2c4980b5b93ca9b Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 4 Oct 2015 17:28:32 +0200 Subject: [PATCH] Fixed type of some __copy__ methods to correctly deal with possible subclassing (Proxy). Tweaked handling of methods on the async proxy adapter. This also fixed the problems with current_context on async proxy calls. Fixes #90 --- docs/source/tipstricks.rst | 4 ++-- examples/callcontext/client.py | 7 +++++++ src/Pyro4/core.py | 11 +++++++++-- tests/PyroTests/test_core.py | 26 ++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/docs/source/tipstricks.rst b/docs/source/tipstricks.rst index abb27576..3533a9c8 100644 --- a/docs/source/tipstricks.rst +++ b/docs/source/tipstricks.rst @@ -205,8 +205,8 @@ With a syntax that is slightly different from normal method calls, it provides the same asynchronous function calls as the async proxy has. Note that Python itself has a similar thing in the standard library since version 3.2, see http://docs.python.org/3/library/concurrent.futures.html#future-objects . However Pyro's Future -object is available on older Python versions too, and works slightly differently. It's -also a little bit easier to work with. +object is available on older Python versions too. It works slightly differently and perhaps +a little bit easier as well. You create a ``Future`` object for a callable that you want to execute in the background, and receive its results somewhere in the future:: diff --git a/examples/callcontext/client.py b/examples/callcontext/client.py index 5416a017..101a4af7 100644 --- a/examples/callcontext/client.py +++ b/examples/callcontext/client.py @@ -48,6 +48,13 @@ def _pyroResponseAnnotations(self, annotations, msgtype): p._pyroRelease() with CustomAnnotationProxy(uri) as proxy: + # async + print("Async proxy message...") + asyncproxy = Pyro4.async(proxy) + result = asyncproxy.echo("hello-ASYNC") + _ = result.value + + # oneway print("Finally, sending a oneway message...") proxy.oneway("hello-ONEWAY") diff --git a/src/Pyro4/core.py b/src/Pyro4/core.py index cc6c79e9..d12999e8 100644 --- a/src/Pyro4/core.py +++ b/src/Pyro4/core.py @@ -320,7 +320,7 @@ def __setstate__(self, state): def __copy__(self): uriCopy = URI(self._pyroUri) - p = Proxy(uriCopy) + p = type(self)(uriCopy) p._pyroOneway = set(self._pyroOneway) p._pyroMethods = set(self._pyroMethods) p._pyroAttrs = set(self._pyroAttrs) @@ -664,7 +664,9 @@ def __exit__(self, *args): pass def __copy__(self): - return self + copy = type(self)(self.__proxy) + copy.__calls = list(self.__calls) + return copy def __resultsgenerator(self, results): for result in results: @@ -696,8 +698,13 @@ def __init__(self, proxy): self.__proxy = proxy def __getattr__(self, name): + if name in dir(self.__proxy): + return getattr(self.__proxy, name) return _AsyncRemoteMethod(self.__proxy, name) + def __copy__(self): + return type(self)(self.__proxy) + class _AsyncRemoteMethod(object): """async method call abstraction (call will run in a background thread)""" diff --git a/tests/PyroTests/test_core.py b/tests/PyroTests/test_core.py index a7dce7c6..6d25ff85 100644 --- a/tests/PyroTests/test_core.py +++ b/tests/PyroTests/test_core.py @@ -249,6 +249,13 @@ def testUriCopy(self): self.assertEqual(p1.object, p3.object) self.assertEqual(p1, p3) + def testUriSubclassCopy(self): + class SubURI(Pyro4.core.URI): + pass + u = SubURI("PYRO:12345@hostname:9999") + u2 = copy.copy(u) + self.assertIsInstance(u2, SubURI) + def testUriEqual(self): p1 = Pyro4.core.URI("PYRO:12345@host.com:9999") p2 = Pyro4.core.URI("PYRO:12345@host.com:9999") @@ -305,6 +312,25 @@ def testProxyCopy(self): self.assertEqual(p1._pyroHmacKey, p2._pyroHmacKey) self.assertEqual(p1._pyroHandshake, p2._pyroHandshake) + def testProxySubclassCopy(self): + class ProxySub(Pyro4.core.Proxy): + pass + p = ProxySub("PYRO:12345@hostname:9999") + p2 = copy.copy(p) + self.assertIsInstance(p2, ProxySub) + + def testAsyncProxyAdapterCopy(self): + proxy = Pyro4.core.Proxy("PYRO:12345@hostname:9999") + asyncproxy = proxy._pyroAsync() + p2 = copy.copy(asyncproxy) + self.assertIsInstance(p2, Pyro4.core._AsyncProxyAdapter) + + def testBatchProxyAdapterCopy(self): + proxy = Pyro4.core.Proxy("PYRO:12345@hostname:9999") + batchproxy = proxy._pyroBatch() + p2 = copy.copy(batchproxy) + self.assertIsInstance(p2, Pyro4.core._BatchProxyAdapter) + def testProxyOffline(self): # only offline stuff here. # online stuff needs a running daemon, so we do that in another test, to keep this one simple