[Zope-Checkins] SVN: Zope/branches/2.10/lib/python/ Made
DateTime.DateTime marshallable via XML-RPC.
Stefan H. Holek
cvs-admin at zope.org
Fri Jun 16 11:54:51 EDT 2006
Log message for revision 68691:
Made DateTime.DateTime marshallable via XML-RPC.
Fixes http://www.zope.org/Collectors/Zope/2109
Changed:
U Zope/branches/2.10/lib/python/DateTime/DateTime.py
U Zope/branches/2.10/lib/python/ZPublisher/tests/test_xmlrpc.py
U Zope/branches/2.10/lib/python/ZPublisher/xmlrpc.py
-=-
Modified: Zope/branches/2.10/lib/python/DateTime/DateTime.py
===================================================================
--- Zope/branches/2.10/lib/python/DateTime/DateTime.py 2006-06-16 15:45:43 UTC (rev 68690)
+++ Zope/branches/2.10/lib/python/DateTime/DateTime.py 2006-06-16 15:54:47 UTC (rev 68691)
@@ -1797,7 +1797,15 @@
d1 = (( d4 - L) % 365) + L
return d1/7 + 1
+ def encode(self, out):
+ """
+ Encode value for XML-RPC
+ """
+ out.write('<value><dateTime.iso8601>')
+ out.write(self.ISO8601())
+ out.write('</dateTime.iso8601></value>\n')
+
class strftimeFormatter:
def __init__(self, dt, format):
Modified: Zope/branches/2.10/lib/python/ZPublisher/tests/test_xmlrpc.py
===================================================================
--- Zope/branches/2.10/lib/python/ZPublisher/tests/test_xmlrpc.py 2006-06-16 15:45:43 UTC (rev 68690)
+++ Zope/branches/2.10/lib/python/ZPublisher/tests/test_xmlrpc.py 2006-06-16 15:54:47 UTC (rev 68691)
@@ -1,4 +1,5 @@
import unittest
+from DateTime import DateTime
class FauxResponse:
@@ -12,6 +13,9 @@
def setHeader(self, name, value):
self._headers[name] = value
+ def setStatus(self, status):
+ self._status = status
+
class FauxInstance:
def __init__(self, **kw):
self.__dict__.update(kw)
@@ -55,7 +59,139 @@
data, method = xmlrpclib.loads(faux._body)
self.assert_(data[0]['public'] is None)
+ def test_instance(self):
+ # Instances are turned into dicts with their private
+ # attributes removed.
+ import xmlrpclib
+ body = FauxInstance(_secret='abc', public='def')
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]
+ self.assertEqual(data, {'public': 'def'})
+ def test_instanceattribute(self):
+ # While the removal of private ('_') attributes works fine for the
+ # top-level instance, how about attributes that are themselves
+ # instances?
+ import xmlrpclib
+ body = FauxInstance(public=FauxInstance(_secret='abc', public='def'))
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]['public']
+ self.assertEqual(data, {'public': 'def'})
+
+ def test_instanceattribute_recursive(self):
+ # Instance "flattening" should work recursively, ad infinitum
+ import xmlrpclib
+ body = FauxInstance(public=FauxInstance(public=FauxInstance(_secret='abc', public='def')))
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]['public']['public']
+ self.assertEqual(data, {'public': 'def'})
+
+ def test_instance_in_list(self):
+ # Instances are turned into dicts with their private
+ # attributes removed, even when embedded in another
+ # data structure.
+ import xmlrpclib
+ body = [FauxInstance(_secret='abc', public='def')]
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0][0]
+ self.assertEqual(data, {'public': 'def'})
+
+ def test_instance_in_dict(self):
+ # Instances are turned into dicts with their private
+ # attributes removed, even when embedded in another
+ # data structure.
+ import xmlrpclib
+ body = {'faux': FauxInstance(_secret='abc', public='def')}
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]['faux']
+ self.assertEqual(data, {'public': 'def'})
+
+ def test_zopedatetimeinstance(self):
+ # DateTime instance at top-level
+ import xmlrpclib
+ body = DateTime('2006-05-24 07:00:00 GMT+0')
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]
+ self.failUnless(isinstance(data, xmlrpclib.DateTime))
+ self.assertEqual(data.value, u'2006-05-24T07:00:00+00:00')
+
+ def test_zopedatetimeattribute(self):
+ # DateTime instance as attribute
+ import xmlrpclib
+ body = FauxInstance(public=DateTime('2006-05-24 07:00:00 GMT+0'))
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]['public']
+ self.failUnless(isinstance(data, xmlrpclib.DateTime))
+ self.assertEqual(data.value, u'2006-05-24T07:00:00+00:00')
+
+ def test_zopedatetimeattribute_recursive(self):
+ # DateTime encoding should work recursively
+ import xmlrpclib
+ body = FauxInstance(public=FauxInstance(public=DateTime('2006-05-24 07:00:00 GMT+0')))
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]['public']['public']
+ self.failUnless(isinstance(data, xmlrpclib.DateTime))
+ self.assertEqual(data.value, u'2006-05-24T07:00:00+00:00')
+
+ def test_zopedatetimeinstance_in_list(self):
+ # DateTime instance embedded in a list
+ import xmlrpclib
+ body = [DateTime('2006-05-24 07:00:00 GMT+0')]
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0][0]
+ self.failUnless(isinstance(data, xmlrpclib.DateTime))
+ self.assertEqual(data.value, u'2006-05-24T07:00:00+00:00')
+
+ def test_zopedatetimeinstance_in_dict(self):
+ # DateTime instance embedded in a dict
+ import xmlrpclib
+ body = {'date': DateTime('2006-05-24 07:00:00 GMT+0')}
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ data, method = xmlrpclib.loads(faux._body)
+ data = data[0]['date']
+ self.failUnless(isinstance(data, xmlrpclib.DateTime))
+ self.assertEqual(data.value, u'2006-05-24T07:00:00+00:00')
+
+ def test_functionattribute(self):
+ # Cannot marshal functions or methods, obviously
+ import xmlrpclib
+ def foo(): pass
+ body = FauxInstance(public=foo)
+ faux = FauxResponse()
+ response = self._makeOne(faux)
+ response.setBody(body)
+ self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, faux._body)
+
+
def test_suite():
return unittest.TestSuite((unittest.makeSuite(XMLRPCResponseTests),))
Modified: Zope/branches/2.10/lib/python/ZPublisher/xmlrpc.py
===================================================================
--- Zope/branches/2.10/lib/python/ZPublisher/xmlrpc.py 2006-06-16 15:45:43 UTC (rev 68690)
+++ Zope/branches/2.10/lib/python/ZPublisher/xmlrpc.py 2006-06-16 15:54:47 UTC (rev 68691)
@@ -25,7 +25,29 @@
import xmlrpclib
from zExceptions import Unauthorized
+from ZODB.POSException import ConflictError
+# Make DateTime.DateTime marshallable via XML-RPC
+# http://www.zope.org/Collectors/Zope/2109
+from DateTime import DateTime
+WRAPPERS = xmlrpclib.WRAPPERS + (DateTime,)
+
+def dump_instance(self, value, write):
+ # Check for special wrappers
+ if value.__class__ in WRAPPERS:
+ self.write = write
+ value.encode(self)
+ del self.write
+ else:
+ # Store instance attributes as a struct (really?).
+ # We want to avoid disclosing private attributes.
+ # Private attributes are by convention named with
+ # a leading underscore character.
+ value = dict([(k, v) for (k, v) in value.__dict__.items() if k[0] != '_'])
+ self.dump_struct(value, write)
+
+xmlrpclib.Marshaller.dispatch[types.InstanceType] = dump_instance
+
def parse_input(data):
"""Parse input data and return a method path and argument tuple
@@ -100,16 +122,6 @@
# Convert Fault object to XML-RPC response.
body=xmlrpclib.dumps(body, methodresponse=1, allow_none=True)
else:
- if type(body) == types.InstanceType:
- # Avoid disclosing private members. Private members are
- # by convention named with a leading underscore char.
- orig = body.__dict__
- dict = {}
- for key in orig.keys():
- if key[:1] != '_':
- dict[key] = orig[key]
- body = dict
-
# Marshall our body as an XML-RPC response. Strings will be sent
# strings, integers as integers, etc. We do *not* convert
# everything to a string first.
@@ -119,6 +131,8 @@
try:
body = xmlrpclib.dumps(
(body,), methodresponse=1, allow_none=True)
+ except ConflictError:
+ raise
except:
self.exception()
return
@@ -165,6 +179,8 @@
f=Fault(-1, 'Unexpected Zope exception: %s' % value)
else:
f=Fault(-2, 'Unexpected Zope error value: %s' % value)
+ except ConflictError:
+ raise
except:
f=Fault(-3, "Unknown Zope fault type")
More information about the Zope-Checkins
mailing list