Skip to content
This repository has been archived by the owner on Jun 4, 2023. It is now read-only.

Commit

Permalink
marshal serializer dumpsCall is now smarter about unmarshallable types
Browse files Browse the repository at this point in the history
  • Loading branch information
irmen committed Aug 4, 2018
1 parent fa08778 commit 2a298f6
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 5 deletions.
9 changes: 9 additions & 0 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/Pyro4/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"""

# Pyro version
VERSION = "4.73"
VERSION = "4.74.dev0"

# standard object name for the Daemon object
DAEMON_NAME = "Pyro.Daemon"
Expand Down
10 changes: 10 additions & 0 deletions src/Pyro4/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down
3 changes: 2 additions & 1 deletion src/Pyro4/utils/httpgateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def redirect(start_response, target):
<a href="http://pyro4.readthedocs.io/en/stable/tipstricks.html#pyro-via-http-and-json">Docs.</a>
</p>
</div>
<p><em>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.</em></p>
<p><em>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.</em></p>
<h2>Currently exposed contents of name server on {hostname}:</h2>
<p>(Limited to 10 entries, exposed name pattern = '{ns_regex}')</p>
{name_server_contents_list}
Expand Down
18 changes: 15 additions & 3 deletions tests/PyroTests/test_serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit 2a298f6

Please sign in to comment.