RickJames
RickJames

Reputation: 25

Pyro4 Serialize Error : unsupported serialized class

I'm new to Pyro4 and need to get into it, and what better way is there than trying out the examples contained in the Pyro4 package? So my first move was to simply make one work, it's the example "warehouse". The idea is to have a person visit the warehouse and choose items to take or store. The file "warehouse.py" contains the Pyro deamon information while "visit.py" makes the interaction between person and warehouse work.

The nameserver (in my case: Hodor, which is started by pyro4-ns -n Hodorand has an entry in my hosts file in C:\Windows\System32\drivers\etc) and "warehouse.py" must be running in two seperate terminal windows. Every time I start the communication via "visit.py" in a third terminal window, at first it works and asks me if I want to store something. If I do, I get the error message:
"Pyro4.errors.SerializeError: unsupported serialized class: person.Visitor"

  File "visit.py", line 10, in <module>
    janet.visit(warehouse)
  File "C:\Users\RickJames\Pyro_other_machine\person.py", line 14, in visit
    self.retrieve(warehouse)
  File "C:\Users\RickJames\Pyro_other_machine\person.py", line 25, in retrieve
    warehouse.take(self, item)
  File "C:\Python34\lib\site-packages\Pyro4\core.py", line 171, in __call__
    return self.__send(self.__name, args, kwargs)
  File "C:\Python34\lib\site-packages\Pyro4\core.py", line 428, in _pyroInvoke
    raise data
Pyro4.errors.SerializeError: unsupported serialized class: person.Visitor

Here is "warehouse.py":

from __future__ import print_function
import Pyro4
import person


class Warehouse(object):
    def __init__(self):
        self.contents=["chair","bike","flashlight","laptop","couch"]

    def list_contents(self):
        return self.contents

    def take(self, person, item):
        self.contents.remove(item)
        print("{0} took the {1}.".format(person.name, item))

    def store(self, person, item):
        self.contents.append(item)
        print("{0} stored the {1}.".format(person.name, item))


def main():
    warehouse=Warehouse()
    Pyro4.Daemon.serveSimple(
            {
                warehouse: "warehouse"
            },
            host = "Hodor",
            ns=True)

if __name__=="__main__":
    main()

"person.py":

from __future__ import print_function
import sys

if sys.version_info<(3,0):
    input=raw_input


class Visitor(object):
    def __init__(self, name):
        self.name=name
    def visit(self, warehouse):
        print("This is {0}.".format(self.name))
        self.deposit(warehouse)
        self.retrieve(warehouse)
        print("Thank you, come again!")
    def deposit(self, warehouse):
        print("The warehouse contains:", warehouse.list_contents())
        item=input("Type a thing you want to store (or empty): ").strip()
        if item:
            warehouse.store(self, item)
    def retrieve(self, warehouse):
        print("The warehouse contains:", warehouse.list_contents())
        item=input("Type something you want to take (or empty): ").strip()
        if item:
            warehouse.take(self, item)

and finally "visit.py":

import sys
import Pyro4
import Pyro4.util
from person import Visitor

warehouse=Pyro4.Proxy("PYRONAME:warehouse")
janet=Visitor("Janet")
henry=Visitor("Henry")
janet.visit(warehouse)
henry.visit(warehouse)

I know that by default Pyro4 uses the serializer "serpent". I tried to switch to 'marshal','json', 'dill' and 'pickle', but none of them solved my problem. Also, since I read about all the security problems with some serializers, I'd like to keep "serpent".

Upvotes: 2

Views: 3871

Answers (1)

Irmen de Jong
Irmen de Jong

Reputation: 2847

Your source files are wrong. Did you type them in yourself? Where did you get them from? Because the ones you show us here are very old versions of those example files (3 years old!) Those old versions indeed won't work anymore with recent versions of Pyro4 due to some changes to the serializer mechanism that have been made since then.

The most important reason why your code doesn't work anymore is because in your 'Visitor' class, in the deposit and retrieve methods, the code is passing a Visitor instance to the Warehouse pyro service. This is not possible unless you're telling Pyro how to serialize that. Since this is meant to be a simple example, that complexity is not included here but you can read about it in Pyro's docs. The correct version of the example only passes the person's name to the warehouse service thereby avoiding the issue altogether.

The correct versions can be copied from the current Pyro4 documentation, or is provided for you in the examples/warehouse/phase3 folder of the Pyro4 source distribution.

For completeness, the correct versions are as follows. "person.py":

from __future__ import print_function
import sys

if sys.version_info < (3, 0):
    input = raw_input


class Person(object):
    def __init__(self, name):
        self.name = name

    def visit(self, warehouse):
        print("This is {0}.".format(self.name))
        self.deposit(warehouse)
        self.retrieve(warehouse)
        print("Thank you, come again!")

    def deposit(self, warehouse):
        print("The warehouse contains:", warehouse.list_contents())
        item = input("Type a thing you want to store (or empty): ").strip()
        if item:
            warehouse.store(self.name, item)

    def retrieve(self, warehouse):
        print("The warehouse contains:", warehouse.list_contents())
        item = input("Type something you want to take (or empty): ").strip()
        if item:
            warehouse.take(self.name, item)

Then, "visit.py":

# This is the code that visits the warehouse.
import sys

import Pyro4
import Pyro4.util
from person import Person


sys.excepthook = Pyro4.util.excepthook

warehouse = Pyro4.Proxy("PYRONAME:example.warehouse")
janet = Person("Janet")
henry = Person("Henry")
janet.visit(warehouse)
henry.visit(warehouse)

And finally, "warehouse.py":

from __future__ import print_function
import Pyro4


@Pyro4.expose
class Warehouse(object):
    def __init__(self):
        self.contents = ["chair", "bike", "flashlight", "laptop", "couch"]

    def list_contents(self):
        return self.contents

    def take(self, name, item):
        self.contents.remove(item)
        print("{0} took the {1}.".format(name, item))

    def store(self, name, item):
        self.contents.append(item)
        print("{0} stored the {1}.".format(name, item))


def main():
    Pyro4.Daemon.serveSimple(
        {
            Warehouse: "example.warehouse"
        },
        ns=True)


if __name__ == "__main__":
    main()

These work fine with Pyro 4.45.

Upvotes: 0

Related Questions