mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Closes #13297: use bytes type to send and receive binary data through XMLRPC.
This commit is contained in:
		
							parent
							
								
									1d8f3f451c
								
							
						
					
					
						commit
						6166519d2b
					
				
					 4 changed files with 132 additions and 48 deletions
				
			
		| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. XXX Not everything is documented yet.  It might be good to describe
 | 
					.. XXX Not everything is documented yet.  It might be good to describe
 | 
				
			||||||
   Marshaller, Unmarshaller, getparser, dumps, loads, and Transport.
 | 
					   Marshaller, Unmarshaller, getparser and Transport.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Source code:** :source:`Lib/xmlrpc/client.py`
 | 
					**Source code:** :source:`Lib/xmlrpc/client.py`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,12 @@ supports writing XML-RPC client code; it handles all the details of translating
 | 
				
			||||||
between conformable Python objects and XML on the wire.
 | 
					between conformable Python objects and XML on the wire.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, allow_none=False, use_datetime=False)
 | 
					.. class:: ServerProxy(uri, transport=None, encoding=None, verbose=False, \
 | 
				
			||||||
 | 
					                       allow_none=False, use_datetime=False, \
 | 
				
			||||||
 | 
					                       use_builtin_types=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   .. versionchanged:: 3.3
 | 
				
			||||||
 | 
					      The *use_builtin_types* flag was added.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   A :class:`ServerProxy` instance is an object that manages communication with a
 | 
					   A :class:`ServerProxy` instance is an object that manages communication with a
 | 
				
			||||||
   remote XML-RPC server.  The required first argument is a URI (Uniform Resource
 | 
					   remote XML-RPC server.  The required first argument is a URI (Uniform Resource
 | 
				
			||||||
| 
						 | 
					@ -34,9 +39,13 @@ between conformable Python objects and XML on the wire.
 | 
				
			||||||
   XML; the default behaviour is for ``None`` to raise a :exc:`TypeError`. This is
 | 
					   XML; the default behaviour is for ``None`` to raise a :exc:`TypeError`. This is
 | 
				
			||||||
   a commonly-used extension to the XML-RPC specification, but isn't supported by
 | 
					   a commonly-used extension to the XML-RPC specification, but isn't supported by
 | 
				
			||||||
   all clients and servers; see http://ontosys.com/xml-rpc/extensions.php for a
 | 
					   all clients and servers; see http://ontosys.com/xml-rpc/extensions.php for a
 | 
				
			||||||
   description.  The *use_datetime* flag can be used to cause date/time values to
 | 
					   description.  The *use_builtin_types* flag can be used to cause date/time values
 | 
				
			||||||
   be presented as :class:`datetime.datetime` objects; this is false by default.
 | 
					   to be presented as :class:`datetime.datetime` objects and binary data to be
 | 
				
			||||||
   :class:`datetime.datetime` objects may be passed to calls.
 | 
					   presented as :class:`bytes` objects; this flag is false by default.
 | 
				
			||||||
 | 
					   :class:`datetime.datetime` and :class:`bytes` objects may be passed to calls.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The obsolete *use_datetime* flag is similar to *use_builtin_types* but it
 | 
				
			||||||
 | 
					   applies only to date/time values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Both the HTTP and HTTPS transports support the URL syntax extension for HTTP
 | 
					   Both the HTTP and HTTPS transports support the URL syntax extension for HTTP
 | 
				
			||||||
   Basic Authentication: ``http://user:pass@host:port/path``.  The  ``user:pass``
 | 
					   Basic Authentication: ``http://user:pass@host:port/path``.  The  ``user:pass``
 | 
				
			||||||
| 
						 | 
					@ -78,12 +87,12 @@ between conformable Python objects and XML on the wire.
 | 
				
			||||||
   |                                 | only their *__dict__* attribute is          |
 | 
					   |                                 | only their *__dict__* attribute is          |
 | 
				
			||||||
   |                                 | transmitted.                                |
 | 
					   |                                 | transmitted.                                |
 | 
				
			||||||
   +---------------------------------+---------------------------------------------+
 | 
					   +---------------------------------+---------------------------------------------+
 | 
				
			||||||
   | :const:`dates`                  | in seconds since the epoch (pass in an      |
 | 
					   | :const:`dates`                  | In seconds since the epoch.  Pass in an     |
 | 
				
			||||||
   |                                 | instance of the :class:`DateTime` class) or |
 | 
					   |                                 | instance of the :class:`DateTime` class or  |
 | 
				
			||||||
   |                                 | a :class:`datetime.datetime` instance.      |
 | 
					   |                                 | a :class:`datetime.datetime` instance.      |
 | 
				
			||||||
   +---------------------------------+---------------------------------------------+
 | 
					   +---------------------------------+---------------------------------------------+
 | 
				
			||||||
   | :const:`binary data`            | pass in an instance of the :class:`Binary`  |
 | 
					   | :const:`binary data`            | Pass in an instance of the :class:`Binary`  |
 | 
				
			||||||
   |                                 | wrapper class                               |
 | 
					   |                                 | wrapper class or a :class:`bytes` instance. |
 | 
				
			||||||
   +---------------------------------+---------------------------------------------+
 | 
					   +---------------------------------+---------------------------------------------+
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   This is the full set of data types supported by XML-RPC.  Method calls may also
 | 
					   This is the full set of data types supported by XML-RPC.  Method calls may also
 | 
				
			||||||
| 
						 | 
					@ -98,8 +107,9 @@ between conformable Python objects and XML on the wire.
 | 
				
			||||||
   ensure that the string is free of characters that aren't allowed in XML, such as
 | 
					   ensure that the string is free of characters that aren't allowed in XML, such as
 | 
				
			||||||
   the control characters with ASCII values between 0 and 31 (except, of course,
 | 
					   the control characters with ASCII values between 0 and 31 (except, of course,
 | 
				
			||||||
   tab, newline and carriage return); failing to do this will result in an XML-RPC
 | 
					   tab, newline and carriage return); failing to do this will result in an XML-RPC
 | 
				
			||||||
   request that isn't well-formed XML.  If you have to pass arbitrary strings via
 | 
					   request that isn't well-formed XML.  If you have to pass arbitrary bytes
 | 
				
			||||||
   XML-RPC, use the :class:`Binary` wrapper class described below.
 | 
					   via XML-RPC, use the :class:`bytes` class or the class:`Binary` wrapper class
 | 
				
			||||||
 | 
					   described below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   :class:`Server` is retained as an alias for :class:`ServerProxy` for backwards
 | 
					   :class:`Server` is retained as an alias for :class:`ServerProxy` for backwards
 | 
				
			||||||
   compatibility.  New code should use :class:`ServerProxy`.
 | 
					   compatibility.  New code should use :class:`ServerProxy`.
 | 
				
			||||||
| 
						 | 
					@ -249,7 +259,7 @@ The client code for the preceding server::
 | 
				
			||||||
Binary Objects
 | 
					Binary Objects
 | 
				
			||||||
--------------
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This class may be initialized from string data (which may include NULs). The
 | 
					This class may be initialized from bytes data (which may include NULs). The
 | 
				
			||||||
primary access to the content of a :class:`Binary` object is provided by an
 | 
					primary access to the content of a :class:`Binary` object is provided by an
 | 
				
			||||||
attribute:
 | 
					attribute:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -257,15 +267,15 @@ attribute:
 | 
				
			||||||
.. attribute:: Binary.data
 | 
					.. attribute:: Binary.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   The binary data encapsulated by the :class:`Binary` instance.  The data is
 | 
					   The binary data encapsulated by the :class:`Binary` instance.  The data is
 | 
				
			||||||
   provided as an 8-bit string.
 | 
					   provided as a :class:`bytes` object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:class:`Binary` objects have the following methods, supported mainly for
 | 
					:class:`Binary` objects have the following methods, supported mainly for
 | 
				
			||||||
internal use by the marshalling/unmarshalling code:
 | 
					internal use by the marshalling/unmarshalling code:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. method:: Binary.decode(string)
 | 
					.. method:: Binary.decode(bytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Accept a base64 string and decode it as the instance's new data.
 | 
					   Accept a base64 :class:`bytes` object and decode it as the instance's new data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. method:: Binary.encode(out)
 | 
					.. method:: Binary.encode(out)
 | 
				
			||||||
| 
						 | 
					@ -471,14 +481,21 @@ Convenience Functions
 | 
				
			||||||
   it via an extension,  provide a true value for *allow_none*.
 | 
					   it via an extension,  provide a true value for *allow_none*.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. function:: loads(data, use_datetime=False)
 | 
					.. function:: loads(data, use_datetime=False, use_builtin_types=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   Convert an XML-RPC request or response into Python objects, a ``(params,
 | 
					   Convert an XML-RPC request or response into Python objects, a ``(params,
 | 
				
			||||||
   methodname)``.  *params* is a tuple of argument; *methodname* is a string, or
 | 
					   methodname)``.  *params* is a tuple of argument; *methodname* is a string, or
 | 
				
			||||||
   ``None`` if no method name is present in the packet. If the XML-RPC packet
 | 
					   ``None`` if no method name is present in the packet. If the XML-RPC packet
 | 
				
			||||||
   represents a fault condition, this function will raise a :exc:`Fault` exception.
 | 
					   represents a fault condition, this function will raise a :exc:`Fault` exception.
 | 
				
			||||||
   The *use_datetime* flag can be used to cause date/time values to be presented as
 | 
					   The *use_builtin_types* flag can be used to cause date/time values to be
 | 
				
			||||||
   :class:`datetime.datetime` objects; this is false by default.
 | 
					   presented as :class:`datetime.datetime` objects and binary data to be
 | 
				
			||||||
 | 
					   presented as :class:`bytes` objects; this flag is false by default.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The obsolete *use_datetime* flag is similar to *use_builtin_types* but it
 | 
				
			||||||
 | 
					   applies only to date/time values.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   .. versionchanged:: 3.3
 | 
				
			||||||
 | 
					      The *use_builtin_types* flag was added.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. _xmlrpc-client-example:
 | 
					.. _xmlrpc-client-example:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,8 @@
 | 
				
			||||||
          'ashortlong': 2,
 | 
					          'ashortlong': 2,
 | 
				
			||||||
          'anotherlist': ['.zyx.41'],
 | 
					          'anotherlist': ['.zyx.41'],
 | 
				
			||||||
          'abase64': xmlrpclib.Binary(b"my dog has fleas"),
 | 
					          'abase64': xmlrpclib.Binary(b"my dog has fleas"),
 | 
				
			||||||
 | 
					          'b64bytes': b"my dog has fleas",
 | 
				
			||||||
 | 
					          'b64bytearray': bytearray(b"my dog has fleas"),
 | 
				
			||||||
          'boolean': False,
 | 
					          'boolean': False,
 | 
				
			||||||
          'unicode': '\u4000\u6000\u8000',
 | 
					          'unicode': '\u4000\u6000\u8000',
 | 
				
			||||||
          'ukey\u4000': 'regular value',
 | 
					          'ukey\u4000': 'regular value',
 | 
				
			||||||
| 
						 | 
					@ -44,27 +46,54 @@ def test_dump_load(self):
 | 
				
			||||||
    def test_dump_bare_datetime(self):
 | 
					    def test_dump_bare_datetime(self):
 | 
				
			||||||
        # This checks that an unwrapped datetime.date object can be handled
 | 
					        # This checks that an unwrapped datetime.date object can be handled
 | 
				
			||||||
        # by the marshalling code.  This can't be done via test_dump_load()
 | 
					        # by the marshalling code.  This can't be done via test_dump_load()
 | 
				
			||||||
        # since with use_datetime set to 1 the unmarshaller would create
 | 
					        # since with use_builtin_types set to 1 the unmarshaller would create
 | 
				
			||||||
        # datetime objects for the 'datetime[123]' keys as well
 | 
					        # datetime objects for the 'datetime[123]' keys as well
 | 
				
			||||||
        dt = datetime.datetime(2005, 2, 10, 11, 41, 23)
 | 
					        dt = datetime.datetime(2005, 2, 10, 11, 41, 23)
 | 
				
			||||||
 | 
					        self.assertEqual(dt, xmlrpclib.DateTime('20050210T11:41:23'))
 | 
				
			||||||
        s = xmlrpclib.dumps((dt,))
 | 
					        s = xmlrpclib.dumps((dt,))
 | 
				
			||||||
        (newdt,), m = xmlrpclib.loads(s, use_datetime=1)
 | 
					 | 
				
			||||||
        self.assertEqual(newdt, dt)
 | 
					 | 
				
			||||||
        self.assertEqual(m, None)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
 | 
					        result, m = xmlrpclib.loads(s, use_builtin_types=True)
 | 
				
			||||||
        self.assertEqual(newdt, xmlrpclib.DateTime('20050210T11:41:23'))
 | 
					        (newdt,) = result
 | 
				
			||||||
 | 
					        self.assertEqual(newdt, dt)
 | 
				
			||||||
 | 
					        self.assertIs(type(newdt), datetime.datetime)
 | 
				
			||||||
 | 
					        self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result, m = xmlrpclib.loads(s, use_builtin_types=False)
 | 
				
			||||||
 | 
					        (newdt,) = result
 | 
				
			||||||
 | 
					        self.assertEqual(newdt, dt)
 | 
				
			||||||
 | 
					        self.assertIs(type(newdt), xmlrpclib.DateTime)
 | 
				
			||||||
 | 
					        self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result, m = xmlrpclib.loads(s, use_datetime=True)
 | 
				
			||||||
 | 
					        (newdt,) = result
 | 
				
			||||||
 | 
					        self.assertEqual(newdt, dt)
 | 
				
			||||||
 | 
					        self.assertIs(type(newdt), datetime.datetime)
 | 
				
			||||||
 | 
					        self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result, m = xmlrpclib.loads(s, use_datetime=False)
 | 
				
			||||||
 | 
					        (newdt,) = result
 | 
				
			||||||
 | 
					        self.assertEqual(newdt, dt)
 | 
				
			||||||
 | 
					        self.assertIs(type(newdt), xmlrpclib.DateTime)
 | 
				
			||||||
 | 
					        self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_datetime_before_1900(self):
 | 
					    def test_datetime_before_1900(self):
 | 
				
			||||||
        # same as before but with a date before 1900
 | 
					        # same as before but with a date before 1900
 | 
				
			||||||
        dt = datetime.datetime(1,  2, 10, 11, 41, 23)
 | 
					        dt = datetime.datetime(1,  2, 10, 11, 41, 23)
 | 
				
			||||||
 | 
					        self.assertEqual(dt, xmlrpclib.DateTime('00010210T11:41:23'))
 | 
				
			||||||
        s = xmlrpclib.dumps((dt,))
 | 
					        s = xmlrpclib.dumps((dt,))
 | 
				
			||||||
        (newdt,), m = xmlrpclib.loads(s, use_datetime=1)
 | 
					 | 
				
			||||||
        self.assertEqual(newdt, dt)
 | 
					 | 
				
			||||||
        self.assertEqual(m, None)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        (newdt,), m = xmlrpclib.loads(s, use_datetime=0)
 | 
					        result, m = xmlrpclib.loads(s, use_builtin_types=True)
 | 
				
			||||||
        self.assertEqual(newdt, xmlrpclib.DateTime('00010210T11:41:23'))
 | 
					        (newdt,) = result
 | 
				
			||||||
 | 
					        self.assertEqual(newdt, dt)
 | 
				
			||||||
 | 
					        self.assertIs(type(newdt), datetime.datetime)
 | 
				
			||||||
 | 
					        self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result, m = xmlrpclib.loads(s, use_builtin_types=False)
 | 
				
			||||||
 | 
					        (newdt,) = result
 | 
				
			||||||
 | 
					        self.assertEqual(newdt, dt)
 | 
				
			||||||
 | 
					        self.assertIs(type(newdt), xmlrpclib.DateTime)
 | 
				
			||||||
 | 
					        self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_bug_1164912 (self):
 | 
					    def test_bug_1164912 (self):
 | 
				
			||||||
        d = xmlrpclib.DateTime()
 | 
					        d = xmlrpclib.DateTime()
 | 
				
			||||||
| 
						 | 
					@ -133,6 +162,25 @@ def test_dump_none(self):
 | 
				
			||||||
                          xmlrpclib.loads(strg)[0][0])
 | 
					                          xmlrpclib.loads(strg)[0][0])
 | 
				
			||||||
        self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
 | 
					        self.assertRaises(TypeError, xmlrpclib.dumps, (arg1,))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_dump_bytes(self):
 | 
				
			||||||
 | 
					        sample = b"my dog has fleas"
 | 
				
			||||||
 | 
					        self.assertEqual(sample, xmlrpclib.Binary(sample))
 | 
				
			||||||
 | 
					        for type_ in bytes, bytearray, xmlrpclib.Binary:
 | 
				
			||||||
 | 
					            value = type_(sample)
 | 
				
			||||||
 | 
					            s = xmlrpclib.dumps((value,))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result, m = xmlrpclib.loads(s, use_builtin_types=True)
 | 
				
			||||||
 | 
					            (newvalue,) = result
 | 
				
			||||||
 | 
					            self.assertEqual(newvalue, sample)
 | 
				
			||||||
 | 
					            self.assertIs(type(newvalue), bytes)
 | 
				
			||||||
 | 
					            self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result, m = xmlrpclib.loads(s, use_builtin_types=False)
 | 
				
			||||||
 | 
					            (newvalue,) = result
 | 
				
			||||||
 | 
					            self.assertEqual(newvalue, sample)
 | 
				
			||||||
 | 
					            self.assertIs(type(newvalue), xmlrpclib.Binary)
 | 
				
			||||||
 | 
					            self.assertIsNone(m)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_get_host_info(self):
 | 
					    def test_get_host_info(self):
 | 
				
			||||||
        # see bug #3613, this raised a TypeError
 | 
					        # see bug #3613, this raised a TypeError
 | 
				
			||||||
        transp = xmlrpc.client.Transport()
 | 
					        transp = xmlrpc.client.Transport()
 | 
				
			||||||
| 
						 | 
					@ -140,9 +188,6 @@ def test_get_host_info(self):
 | 
				
			||||||
                          ('host.tld',
 | 
					                          ('host.tld',
 | 
				
			||||||
                           [('Authorization', 'Basic dXNlcg==')], {}))
 | 
					                           [('Authorization', 'Basic dXNlcg==')], {}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_dump_bytes(self):
 | 
					 | 
				
			||||||
        self.assertRaises(TypeError, xmlrpclib.dumps, (b"my dog has fleas",))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_ssl_presence(self):
 | 
					    def test_ssl_presence(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            import ssl
 | 
					            import ssl
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -386,8 +386,8 @@ def __init__(self, data=None):
 | 
				
			||||||
        if data is None:
 | 
					        if data is None:
 | 
				
			||||||
            data = b""
 | 
					            data = b""
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            if not isinstance(data, bytes):
 | 
					            if not isinstance(data, (bytes, bytearray)):
 | 
				
			||||||
                raise TypeError("expected bytes, not %s" %
 | 
					                raise TypeError("expected bytes or bytearray, not %s" %
 | 
				
			||||||
                                data.__class__.__name__)
 | 
					                                data.__class__.__name__)
 | 
				
			||||||
            data = bytes(data)  # Make a copy of the bytes!
 | 
					            data = bytes(data)  # Make a copy of the bytes!
 | 
				
			||||||
        self.data = data
 | 
					        self.data = data
 | 
				
			||||||
| 
						 | 
					@ -559,6 +559,14 @@ def dump_unicode(self, value, write, escape=escape):
 | 
				
			||||||
        write("</string></value>\n")
 | 
					        write("</string></value>\n")
 | 
				
			||||||
    dispatch[str] = dump_unicode
 | 
					    dispatch[str] = dump_unicode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dump_bytes(self, value, write):
 | 
				
			||||||
 | 
					        write("<value><base64>\n")
 | 
				
			||||||
 | 
					        encoded = base64.encodebytes(value)
 | 
				
			||||||
 | 
					        write(encoded.decode('ascii'))
 | 
				
			||||||
 | 
					        write("</base64></value>\n")
 | 
				
			||||||
 | 
					    dispatch[bytes] = dump_bytes
 | 
				
			||||||
 | 
					    dispatch[bytearray] = dump_bytes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def dump_array(self, value, write):
 | 
					    def dump_array(self, value, write):
 | 
				
			||||||
        i = id(value)
 | 
					        i = id(value)
 | 
				
			||||||
        if i in self.memo:
 | 
					        if i in self.memo:
 | 
				
			||||||
| 
						 | 
					@ -629,7 +637,7 @@ class Unmarshaller:
 | 
				
			||||||
    # and again, if you don't understand what's going on in here,
 | 
					    # and again, if you don't understand what's going on in here,
 | 
				
			||||||
    # that's perfectly ok.
 | 
					    # that's perfectly ok.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, use_datetime=False):
 | 
					    def __init__(self, use_datetime=False, use_builtin_types=False):
 | 
				
			||||||
        self._type = None
 | 
					        self._type = None
 | 
				
			||||||
        self._stack = []
 | 
					        self._stack = []
 | 
				
			||||||
        self._marks = []
 | 
					        self._marks = []
 | 
				
			||||||
| 
						 | 
					@ -637,7 +645,8 @@ def __init__(self, use_datetime=False):
 | 
				
			||||||
        self._methodname = None
 | 
					        self._methodname = None
 | 
				
			||||||
        self._encoding = "utf-8"
 | 
					        self._encoding = "utf-8"
 | 
				
			||||||
        self.append = self._stack.append
 | 
					        self.append = self._stack.append
 | 
				
			||||||
        self._use_datetime = use_datetime
 | 
					        self._use_datetime = use_builtin_types or use_datetime
 | 
				
			||||||
 | 
					        self._use_bytes = use_builtin_types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def close(self):
 | 
					    def close(self):
 | 
				
			||||||
        # return response tuple and target method
 | 
					        # return response tuple and target method
 | 
				
			||||||
| 
						 | 
					@ -749,6 +758,8 @@ def end_struct(self, data):
 | 
				
			||||||
    def end_base64(self, data):
 | 
					    def end_base64(self, data):
 | 
				
			||||||
        value = Binary()
 | 
					        value = Binary()
 | 
				
			||||||
        value.decode(data.encode("ascii"))
 | 
					        value.decode(data.encode("ascii"))
 | 
				
			||||||
 | 
					        if self._use_bytes:
 | 
				
			||||||
 | 
					            value = value.data
 | 
				
			||||||
        self.append(value)
 | 
					        self.append(value)
 | 
				
			||||||
        self._value = 0
 | 
					        self._value = 0
 | 
				
			||||||
    dispatch["base64"] = end_base64
 | 
					    dispatch["base64"] = end_base64
 | 
				
			||||||
| 
						 | 
					@ -860,21 +871,26 @@ def __call__(self):
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# return A (parser, unmarshaller) tuple.
 | 
					# return A (parser, unmarshaller) tuple.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getparser(use_datetime=False):
 | 
					def getparser(use_datetime=False, use_builtin_types=False):
 | 
				
			||||||
    """getparser() -> parser, unmarshaller
 | 
					    """getparser() -> parser, unmarshaller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Create an instance of the fastest available parser, and attach it
 | 
					    Create an instance of the fastest available parser, and attach it
 | 
				
			||||||
    to an unmarshalling object.  Return both objects.
 | 
					    to an unmarshalling object.  Return both objects.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    if FastParser and FastUnmarshaller:
 | 
					    if FastParser and FastUnmarshaller:
 | 
				
			||||||
        if use_datetime:
 | 
					        if use_builtin_types:
 | 
				
			||||||
            mkdatetime = _datetime_type
 | 
					            mkdatetime = _datetime_type
 | 
				
			||||||
 | 
					            mkbytes = base64.decodebytes
 | 
				
			||||||
 | 
					        elif use_datetime:
 | 
				
			||||||
 | 
					            mkdatetime = _datetime_type
 | 
				
			||||||
 | 
					            mkbytes = _binary
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            mkdatetime = _datetime
 | 
					            mkdatetime = _datetime
 | 
				
			||||||
        target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
 | 
					            mkbytes = _binary
 | 
				
			||||||
 | 
					        target = FastUnmarshaller(True, False, mkbytes, mkdatetime, Fault)
 | 
				
			||||||
        parser = FastParser(target)
 | 
					        parser = FastParser(target)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        target = Unmarshaller(use_datetime=use_datetime)
 | 
					        target = Unmarshaller(use_datetime=use_datetime, use_builtin_types=use_builtin_types)
 | 
				
			||||||
        if FastParser:
 | 
					        if FastParser:
 | 
				
			||||||
            parser = FastParser(target)
 | 
					            parser = FastParser(target)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
| 
						 | 
					@ -912,7 +928,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        encoding: the packet encoding (default is UTF-8)
 | 
					        encoding: the packet encoding (default is UTF-8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    All 8-bit strings in the data structure are assumed to use the
 | 
					    All byte strings in the data structure are assumed to use the
 | 
				
			||||||
    packet encoding.  Unicode strings are automatically converted,
 | 
					    packet encoding.  Unicode strings are automatically converted,
 | 
				
			||||||
    where necessary.
 | 
					    where necessary.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
| 
						 | 
					@ -971,7 +987,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None,
 | 
				
			||||||
#     (None if not present).
 | 
					#     (None if not present).
 | 
				
			||||||
# @see Fault
 | 
					# @see Fault
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def loads(data, use_datetime=False):
 | 
					def loads(data, use_datetime=False, use_builtin_types=False):
 | 
				
			||||||
    """data -> unmarshalled data, method name
 | 
					    """data -> unmarshalled data, method name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Convert an XML-RPC packet to unmarshalled data plus a method
 | 
					    Convert an XML-RPC packet to unmarshalled data plus a method
 | 
				
			||||||
| 
						 | 
					@ -980,7 +996,7 @@ def loads(data, use_datetime=False):
 | 
				
			||||||
    If the XML-RPC packet represents a fault condition, this function
 | 
					    If the XML-RPC packet represents a fault condition, this function
 | 
				
			||||||
    raises a Fault exception.
 | 
					    raises a Fault exception.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    p, u = getparser(use_datetime=use_datetime)
 | 
					    p, u = getparser(use_datetime=use_datetime, use_builtin_types=use_builtin_types)
 | 
				
			||||||
    p.feed(data)
 | 
					    p.feed(data)
 | 
				
			||||||
    p.close()
 | 
					    p.close()
 | 
				
			||||||
    return u.close(), u.getmethodname()
 | 
					    return u.close(), u.getmethodname()
 | 
				
			||||||
| 
						 | 
					@ -1092,8 +1108,9 @@ class Transport:
 | 
				
			||||||
    # that they can decode such a request
 | 
					    # that they can decode such a request
 | 
				
			||||||
    encode_threshold = None #None = don't encode
 | 
					    encode_threshold = None #None = don't encode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, use_datetime=False):
 | 
					    def __init__(self, use_datetime=False, use_builtin_types=False):
 | 
				
			||||||
        self._use_datetime = use_datetime
 | 
					        self._use_datetime = use_datetime
 | 
				
			||||||
 | 
					        self._use_builtin_types = use_builtin_types
 | 
				
			||||||
        self._connection = (None, None)
 | 
					        self._connection = (None, None)
 | 
				
			||||||
        self._extra_headers = []
 | 
					        self._extra_headers = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1154,7 +1171,8 @@ def single_request(self, host, handler, request_body, verbose=False):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getparser(self):
 | 
					    def getparser(self):
 | 
				
			||||||
        # get parser and unmarshaller
 | 
					        # get parser and unmarshaller
 | 
				
			||||||
        return getparser(use_datetime=self._use_datetime)
 | 
					        return getparser(use_datetime=self._use_datetime,
 | 
				
			||||||
 | 
					                         use_builtin_types=self._use_builtin_types)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ##
 | 
					    ##
 | 
				
			||||||
    # Get authorization info from host parameter
 | 
					    # Get authorization info from host parameter
 | 
				
			||||||
| 
						 | 
					@ -1361,7 +1379,7 @@ class ServerProxy:
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, uri, transport=None, encoding=None, verbose=False,
 | 
					    def __init__(self, uri, transport=None, encoding=None, verbose=False,
 | 
				
			||||||
                 allow_none=False, use_datetime=False):
 | 
					                 allow_none=False, use_datetime=False, use_builtin_types=False):
 | 
				
			||||||
        # establish a "logical" server connection
 | 
					        # establish a "logical" server connection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # get the url
 | 
					        # get the url
 | 
				
			||||||
| 
						 | 
					@ -1375,9 +1393,11 @@ def __init__(self, uri, transport=None, encoding=None, verbose=False,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if transport is None:
 | 
					        if transport is None:
 | 
				
			||||||
            if type == "https":
 | 
					            if type == "https":
 | 
				
			||||||
                transport = SafeTransport(use_datetime=use_datetime)
 | 
					                handler = SafeTransport
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                transport = Transport(use_datetime=use_datetime)
 | 
					                handler = Transport
 | 
				
			||||||
 | 
					            transport = handler(use_datetime=use_datetime,
 | 
				
			||||||
 | 
					                                use_builtin_types=use_builtin_types)
 | 
				
			||||||
        self.__transport = transport
 | 
					        self.__transport = transport
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.__encoding = encoding or 'utf-8'
 | 
					        self.__encoding = encoding or 'utf-8'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -374,6 +374,8 @@ Core and Builtins
 | 
				
			||||||
Library
 | 
					Library
 | 
				
			||||||
-------
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Issue #13297: Use bytes type to send and receive binary data through XMLRPC.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Issue #6397: Support "/dev/poll" polling objects in select module,
 | 
					- Issue #6397: Support "/dev/poll" polling objects in select module,
 | 
				
			||||||
  under Solaris & derivatives.
 | 
					  under Solaris & derivatives.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue