From 2a298f6afa6c6a47b92919c0a54b828ae338ccfd Mon Sep 17 00:00:00 2001
From: Irmen de Jong
Date: Sat, 4 Aug 2018 14:05:18 +0200
Subject: [PATCH] marshal serializer dumpsCall is now smarter about
unmarshallable types
---
docs/source/changelog.rst | 9 +++++++++
src/Pyro4/constants.py | 2 +-
src/Pyro4/util.py | 10 ++++++++++
src/Pyro4/utils/httpgateway.py | 3 ++-
tests/PyroTests/test_serialize.py | 18 +++++++++++++++---
5 files changed, 37 insertions(+), 5 deletions(-)
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"