How do I use a Pyro proxy object as a factory?

I want to use Pyro with an existing set of classes that includes a factory pattern, that is, an object of class A (usually there will only be one of them) is used to create objects of class B (there can be an arbitrary number of them) using the factory method. Thus, I expose the class A object as a Pyro proxy object.

I've expanded on Pyro's introductory code sample to reflect what I'm trying to do. The server side code looks like this:

# saved as
import Pyro4
import socket

class NewObj:
    func_count = None
    def __init__(self):
    print "{0} ctor".format(self)
        func_count = 0
    def __del__(self):
    print "{0} dtor".format(self)
    def func(self):
    print "{0} func call {1}".format(self, self.func_count)
    self.func_count += 1

class GreetingMaker(object):
    def __init__(self):
    print "{0} ctor".format(self)
    def __del__(self):
    print "{0} dtor".format(self)
    def get_fortune(self, name):
    print "getting fortune"
        return "Hello, {0}. Here is your fortune message:\n" \
               "Behold the warranty -- the bold print giveth and the fine print taketh away.".format(name)
    def make_obj(self):
    return NewObj()


daemon=Pyro4.Daemon(host=socket.gethostbyname(socket.gethostname()), port=8080)                                      # make a Pyro daemon
uri=daemon.register(greeting_maker, "foo")  # register the greeting object as a Pyro object

print "Ready. Object uri =", uri            # print the uri so we can use it in the client later
daemon.requestLoop()                        # start the event loop of the server to wait for calls


The client code has also been slightly modified:

# saved as
import Pyro4


greeting_maker=Pyro4.Proxy(uri)          # get a Pyro proxy to the greeting object
print greeting_maker.get_fortune(name)   # call method normally
print greeting_maker.make_obj()


My intention is to be able to instantiate NewObj

and manipulate them in the same way I can manipulate instances GreetingMaker

on the client side, but it looks like what happens when a method make_obj

gets called, a NewObj

is created on the server side, goes out of scope immediately and, therefore, garbage is collected.

It looks like this, server side:

<__main__.GreetingMaker object at 0x2aed47e01110> ctor
/usr/lib/python2.6/site-packages/Pyro4-4.12-py2.6.egg/Pyro4/ UserWarning: HMAC_KEY not set, protocol data may not be secure
  warnings.warn("HMAC_KEY not set, protocol data may not be secure")
Ready. Object uri = PYRO:foo@
getting fortune
<__main__.NewObj instance at 0x175c8098> ctor
<__main__.NewObj instance at 0x175c8098> dtor


... and client side:

/usr/local/lib/python2.6/dist-packages/Pyro4-4.12-py2.6.egg/Pyro4/ UserWarning: HMAC_KEY not set, protocol data may not be secure
  warnings.warn("HMAC_KEY not set, protocol data may not be secure")
Hello, foo. Here is your fortune message:
Behold the warranty -- the bold print giveth and the fine print taketh away.
Traceback (most recent call last):
  File "", line 9, in <module>
    print greeting_maker.make_obj()
  File "/usr/local/lib/python2.6/dist-packages/Pyro4-4.12-py2.6.egg/Pyro4/", line 146, in __call__
    return self.__send(self.__name, args, kwargs)
  File "/usr/local/lib/python2.6/dist-packages/Pyro4-4.12-py2.6.egg/Pyro4/", line 269, in _pyroInvoke
    data=self._pyroSerializer.deserialize(data, compressed=flags & MessageFactory.FLAGS_COMPRESSED)
  File "/usr/local/lib/python2.6/dist-packages/Pyro4-4.12-py2.6.egg/Pyro4/", line 146, in deserialize
    return self.pickle.loads(data)
AttributeError: 'module' object has no attribute 'NewObj'


I suspect I can work around this problem if the factory class (i.e. GreetingMaker

) contains a reference to each one created NewObj

and adds a cleanup method of some type ... but is this really necessary? Am I missing something in Pyro that can help me implement this?

(edited for clarity)


source to share

2 answers

The problem is that it pyro

sucks the object NewObj

on the server side, but it cannot flatten it out on the client side because the implementation is NewObj

unknown to the client.

One way to fix the problem is to create a third module, for example,

and then import it on both the server and client as follows:

from new_obj import NewObj


This will allow the client to deploy NewObj

and work with the instance . In any case, please note that this will be a real object NewObj

living on the client and not a proxy for an object living on the server.



I recently came across this feature and am using it. This is very important for my code that uses a similar factory pattern.

Pyro Server

class Foo(object):
    def __init__(self, x=5):
        self.x = x

class Server(object):
    def build_foo(self, x=5):
        foo = Foo(x)
        # This line will register your foo instance as its own proxy
        # Returning foo here returns the proxy, not the actual foo
        return foo

uri = daemon.register(Server()) # In the later versions, just use Server, not Server()




All Articles