diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 5f24d253..d4bc1b99 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -2,6 +2,15 @@ Change Log ********** +**Pyro 4.74** + +- fixed marshal serializer dumpsCall to be able to use the + class_to_dict conversion for unmarshallable types (in simple situations, not recursively). + This makes it possible again to use the marshal + serializer to register objects with the name server, something basic that + previously resulted in a ValueError: unmarshallable object. + + **Pyro 4.73** - include LICENSE file in distribution diff --git a/src/Pyro4/constants.py b/src/Pyro4/constants.py index ae16a526..72e624ca 100644 --- a/src/Pyro4/constants.py +++ b/src/Pyro4/constants.py @@ -5,7 +5,7 @@ """ # Pyro version -VERSION = "4.73" +VERSION = "4.74.dev0" # standard object name for the Daemon object DAEMON_NAME = "Pyro.Daemon" diff --git a/src/Pyro4/util.py b/src/Pyro4/util.py index f5c5b33b..09a410fd 100644 --- a/src/Pyro4/util.py +++ b/src/Pyro4/util.py @@ -532,6 +532,8 @@ class MarshalSerializer(SerializerBase): serializer_id = 3 # never change this def dumpsCall(self, obj, method, vargs, kwargs): + vargs = [self.convert_obj_into_marshallable(value) for value in vargs] + kwargs = {key: self.convert_obj_into_marshallable(value) for key, value in kwargs.items()} return marshal.dumps((obj, method, vargs, kwargs)) def dumps(self, data): @@ -567,6 +569,14 @@ def loads(self, data): data = self._convertToBytes(data) return self.recreate_classes(marshal.loads(data)) + def convert_obj_into_marshallable(self, obj): + marshalable_types = {str, int, float, type(None), bool, complex, bytes, bytearray, tuple, set, frozenset, list, dict} + if sys.version_info < (3, 0): + marshalable_types.add(unicode) + if type(obj) in marshalable_types: + return obj + return self.class_to_dict(obj) + @classmethod def class_to_dict(cls, obj): if isinstance(obj, uuid.UUID): diff --git a/src/Pyro4/utils/httpgateway.py b/src/Pyro4/utils/httpgateway.py index 55b83c43..6aa338fd 100644 --- a/src/Pyro4/utils/httpgateway.py +++ b/src/Pyro4/utils/httpgateway.py @@ -117,7 +117,8 @@ def redirect(start_response, target): Docs.

-

Note: performance isn't a key concern here; it is a stateless server. It does a name lookup and uses a new Pyro proxy for each request.

+

Note: performance isn't a key concern here; it is a stateless server. + It does a name lookup and uses a new Pyro proxy for each request.

Currently exposed contents of name server on {hostname}:

(Limited to 10 entries, exposed name pattern = '{ns_regex}')

{name_server_contents_list} diff --git a/tests/PyroTests/test_serialize.py b/tests/PyroTests/test_serialize.py index 9de227be..bd9f64a3 100644 --- a/tests/PyroTests/test_serialize.py +++ b/tests/PyroTests/test_serialize.py @@ -398,13 +398,15 @@ def testCircular(self): self.assertEqual(42, data2[0]) def testCallPlain(self): - ser, compressed = self.ser.serializeCall("object", "method", "vargs", "kwargs") + ser, compressed = self.ser.serializeCall("object", "method", ("vargs1", "vargs2"), {"kwargs": 999}) self.assertFalse(compressed) obj, method, vargs, kwargs = self.ser.deserializeCall(ser, compressed=False) self.assertEqual("object", obj) self.assertEqual("method", method) - self.assertEqual("vargs", vargs) - self.assertEqual("kwargs", kwargs) + self.assertTrue(len(vargs) == 2) + self.assertTrue(vargs[0] == "vargs1") + self.assertTrue(vargs[1] == "vargs2") + self.assertDictEqual({"kwargs": 999}, kwargs) def testCallPyroObjAsArg(self): if self.SERIALIZER == "marshal": @@ -575,6 +577,16 @@ def testSourceByteTypes_loads_memoryview(self): d = self.ser.loads(memoryview(ser)) self.assertEqual([4, 5, 6], d) + def testSerializeDumps(self): + self.ser.dumps(uuid.uuid4()) + self.ser.dumps(Pyro4.URI("PYRO:test@test:4444")) + self.ser.dumps(Pyro4.Proxy("PYRONAME:foobar")) + self.ser.dumpsCall("obj", "method", (1, 2, 3), {"arg1": 999}) + self.ser.dumpsCall("obj", "method", (1, 2, Pyro4.URI("PYRO:test@test:4444")), {"arg1": 999}) + self.ser.dumpsCall("obj", "method", (1, 2, Pyro4.URI("PYRO:test@test:4444")), {"arg1": Pyro4.URI("PYRO:test@test:4444")}) + self.ser.dumpsCall("obj", "method", (1, 2, Pyro4.Proxy("PYRONAME:foobar")), {"arg1": 999}) + self.ser.dumpsCall("obj", "method", (1, 2, Pyro4.Proxy("PYRONAME:foobar")), {"arg1": Pyro4.Proxy("PYRONAME:foobar")}) + class SerializeTests_cloudpickle(SerializeTests_pickle): SERIALIZER = "cloudpickle"