diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 2c199411a7a..ca8d5d8cc03 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -149,7 +149,8 @@ class XMLRPCTestCase(unittest.TestCase): @test_support.requires_unicode def test_dump_encoding(self): - value = unichr(0x20ac) + value = {test_support.u(r'key\u20ac\xa4'): + test_support.u(r'value\u20ac\xa4')} strg = xmlrpclib.dumps((value,), encoding='iso-8859-15') strg = "" + strg self.assertEqual(xmlrpclib.loads(strg)[0][0], value) @@ -158,6 +159,12 @@ class XMLRPCTestCase(unittest.TestCase): methodresponse=True) self.assertEqual(xmlrpclib.loads(strg)[0][0], value) + methodname = test_support.u(r'method\u20ac\xa4') + strg = xmlrpclib.dumps((value,), encoding='iso-8859-15', + methodname=methodname) + self.assertEqual(xmlrpclib.loads(strg)[0][0], value) + self.assertEqual(xmlrpclib.loads(strg)[1], methodname) + @test_support.requires_unicode def test_default_encoding_issues(self): # SF bug #1115989: wrong decoding in '_stringify' @@ -332,6 +339,7 @@ def http_server(evt, numrequests, requestHandler=None, encoding=None): serv.register_multicall_functions() serv.register_function(pow) serv.register_function(lambda x,y: x+y, 'add') + serv.register_function(lambda x: x, test_support.u(r't\xea\u0161t')) serv.register_function(my_function) serv.register_instance(TestInstanceClass()) evt.set() @@ -496,7 +504,7 @@ class SimpleServerTestCase(BaseServerTestCase): @test_support.requires_unicode def test_client_encoding(self): start_string = unichr(0x20ac) - end_string = unichr(0xa3) + end_string = unichr(0xa4) try: p = xmlrpclib.ServerProxy(URL, encoding='iso-8859-15') @@ -508,6 +516,18 @@ class SimpleServerTestCase(BaseServerTestCase): # protocol error; provide additional information in test output self.fail("%s\n%s" % (e, getattr(e, "headers", ""))) + @test_support.requires_unicode + def test_nonascii_methodname(self): + try: + p = xmlrpclib.ServerProxy(URL, encoding='iso-8859-15') + m = getattr(p, 't\xea\xa8t') + self.assertEqual(m(42), 42) + except (xmlrpclib.ProtocolError, socket.error) as e: + # ignore failures due to non-blocking socket unavailable errors. + if not is_unavailable_exception(e): + # protocol error; provide additional information in test output + self.fail("%s\n%s" % (e, getattr(e, "headers", ""))) + # [ch] The test 404 is causing lots of false alarms. def XXXtest_404(self): # send POST with httplib, it should return 404 header and @@ -525,6 +545,7 @@ class SimpleServerTestCase(BaseServerTestCase): p = xmlrpclib.ServerProxy(URL) meth = p.system.listMethods() expected_methods = set(['pow', 'div', 'my_function', 'add', + test_support.u(r't\xea\u0161t'), 'system.listMethods', 'system.methodHelp', 'system.methodSignature', 'system.multicall']) self.assertEqual(set(meth), expected_methods) @@ -635,7 +656,7 @@ class SimpleServerEncodingTestCase(BaseServerTestCase): @test_support.requires_unicode def test_server_encoding(self): start_string = unichr(0x20ac) - end_string = unichr(0xa3) + end_string = unichr(0xa4) try: p = xmlrpclib.ServerProxy(URL) diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py index a1800a18a56..e0e399c449a 100644 --- a/Lib/xmlrpclib.py +++ b/Lib/xmlrpclib.py @@ -703,9 +703,8 @@ class Marshaller: if unicode: def dump_unicode(self, value, write, escape=escape): - value = value.encode(self.encoding) write("") - write(escape(value)) + write(escape(value).encode(self.encoding, 'xmlcharrefreplace')) write("\n") dispatch[UnicodeType] = dump_unicode @@ -732,12 +731,13 @@ class Marshaller: write("\n") for k, v in value.items(): write("\n") - if type(k) is not StringType: - if unicode and type(k) is UnicodeType: - k = k.encode(self.encoding) - else: - raise TypeError, "dictionary key must be string" - write("%s\n" % escape(k)) + if type(k) is StringType: + k = escape(k) + elif unicode and type(k) is UnicodeType: + k = escape(k).encode(self.encoding, 'xmlcharrefreplace') + else: + raise TypeError, "dictionary key must be string" + write("%s\n" % k) dump(v, write) write("\n") write("\n") @@ -1099,7 +1099,7 @@ def dumps(params, methodname=None, methodresponse=None, encoding=None, if methodname: # a method call if not isinstance(methodname, StringType): - methodname = methodname.encode(encoding) + methodname = methodname.encode(encoding, 'xmlcharrefreplace') data = ( xmlheader, "\n" diff --git a/Misc/NEWS b/Misc/NEWS index b658f729ad6..0d176456e6d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -39,6 +39,9 @@ Core and Builtins Library ------- +- Issue #26147: xmlrpclib now works with unicode not encodable with used + non-UTF-8 encoding. + - Issue #16620: Fixed AttributeError in msilib.Directory.glob(). - Issue #21847: Fixed xmlrpclib on Unicode-disabled builds.