blob: 9f72931ed07e61054d48deb6621dfdbeec8b0056 [file] [log] [blame]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001#
2# XML-RPC CLIENT LIBRARY
3# $Id$
4#
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00005# an XML-RPC client interface for Python.
6#
7# the marshalling and response parser code can also be used to
8# implement XML-RPC servers.
9#
10# Notes:
Martin v. Löwis37af9862004-08-20 07:31:37 +000011# this version is designed to work with Python 2.1 or newer.
Fredrik Lundhc4c062f2001-09-10 19:45:02 +000012#
Fredrik Lundhb9056332001-07-11 17:42:21 +000013# History:
14# 1999-01-14 fl Created
15# 1999-01-15 fl Changed dateTime to use localtime
16# 1999-01-16 fl Added Binary/base64 element, default to RPC2 service
17# 1999-01-19 fl Fixed array data element (from Skip Montanaro)
18# 1999-01-21 fl Fixed dateTime constructor, etc.
19# 1999-02-02 fl Added fault handling, handle empty sequences, etc.
20# 1999-02-10 fl Fixed problem with empty responses (from Skip Montanaro)
21# 1999-06-20 fl Speed improvements, pluggable parsers/transports (0.9.8)
22# 2000-11-28 fl Changed boolean to check the truth value of its argument
23# 2001-02-24 fl Added encoding/Unicode/SafeTransport patches
24# 2001-02-26 fl Added compare support to wrappers (0.9.9/1.0b1)
25# 2001-03-28 fl Make sure response tuple is a singleton
26# 2001-03-29 fl Don't require empty params element (from Nicholas Riley)
Fredrik Lundh78eedce2001-08-23 20:04:33 +000027# 2001-06-10 fl Folded in _xmlrpclib accelerator support (1.0b2)
28# 2001-08-20 fl Base xmlrpclib.Error on built-in Exception (from Paul Prescod)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +000029# 2001-09-03 fl Allow Transport subclass to override getparser
30# 2001-09-10 fl Lazy import of urllib, cgi, xmllib (20x import speedup)
Fredrik Lundh1538c232001-10-01 19:42:03 +000031# 2001-10-01 fl Remove containers from memo cache when done with them
32# 2001-10-01 fl Use faster escape method (80% dumps speedup)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000033# 2001-10-02 fl More dumps microtuning
34# 2001-10-04 fl Make sure import expat gets a parser (from Guido van Rossum)
Skip Montanaro5e9c71b2001-10-10 15:56:34 +000035# 2001-10-10 sm Allow long ints to be passed as ints if they don't overflow
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000036# 2001-10-17 sm Test for int and long overflow (allows use on 64-bit systems)
Fredrik Lundhb6ab93f2001-12-19 21:40:04 +000037# 2001-11-12 fl Use repr() to marshal doubles (from Paul Felix)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000038# 2002-03-17 fl Avoid buffered read when possible (from James Rucker)
39# 2002-04-07 fl Added pythondoc comments
40# 2002-04-16 fl Added __str__ methods to datetime/binary wrappers
41# 2002-05-15 fl Added error constants (from Andrew Kuchling)
42# 2002-06-27 fl Merged with Python CVS version
Fredrik Lundh1303c7c2002-10-22 18:23:00 +000043# 2002-10-22 fl Added basic authentication (based on code from Phillip Eby)
Martin v. Löwis541342f2003-07-12 07:53:04 +000044# 2003-01-22 sm Add support for the bool type
45# 2003-02-27 gvr Remove apply calls
46# 2003-04-24 sm Use cStringIO if available
47# 2003-04-25 ak Add support for nil
48# 2003-06-15 gn Add support for time.struct_time
49# 2003-07-12 gp Correct marshalling of Faults
Martin v. Löwis45394c22003-10-31 13:49:36 +000050# 2003-10-31 mvl Add multicall support
Martin v. Löwis37af9862004-08-20 07:31:37 +000051# 2004-08-20 mvl Bump minimum supported Python version to 2.1
Fredrik Lundhb9056332001-07-11 17:42:21 +000052#
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000053# Copyright (c) 1999-2002 by Secret Labs AB.
54# Copyright (c) 1999-2002 by Fredrik Lundh.
Fredrik Lundhb9056332001-07-11 17:42:21 +000055#
56# info@pythonware.com
57# http://www.pythonware.com
58#
59# --------------------------------------------------------------------
60# The XML-RPC client interface is
61#
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000062# Copyright (c) 1999-2002 by Secret Labs AB
63# Copyright (c) 1999-2002 by Fredrik Lundh
Fredrik Lundhb9056332001-07-11 17:42:21 +000064#
65# By obtaining, using, and/or copying this software and/or its
66# associated documentation, you agree that you have read, understood,
67# and will comply with the following terms and conditions:
68#
69# Permission to use, copy, modify, and distribute this software and
70# its associated documentation for any purpose and without fee is
71# hereby granted, provided that the above copyright notice appears in
72# all copies, and that both that copyright notice and this permission
73# notice appear in supporting documentation, and that the name of
74# Secret Labs AB or the author not be used in advertising or publicity
75# pertaining to distribution of the software without specific, written
76# prior permission.
77#
78# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
79# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
80# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
81# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
82# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
83# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
84# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
85# OF THIS SOFTWARE.
86# --------------------------------------------------------------------
87
88#
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000089# things to look into some day:
Fredrik Lundhb9056332001-07-11 17:42:21 +000090
Fredrik Lundh3d9addd2002-06-27 21:36:21 +000091# TODO: sort out True/False/boolean issues for Python 2.3
Fredrik Lundhb9056332001-07-11 17:42:21 +000092
Fred Drake1b410792001-09-04 18:55:03 +000093"""
94An XML-RPC client interface for Python.
95
96The marshalling and response parser code can also be used to
97implement XML-RPC servers.
98
Fred Drake1b410792001-09-04 18:55:03 +000099Exported exceptions:
100
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000101 Error Base class for client errors
102 ProtocolError Indicates an HTTP protocol error
103 ResponseError Indicates a broken response package
104 Fault Indicates an XML-RPC fault package
Fred Drake1b410792001-09-04 18:55:03 +0000105
106Exported classes:
107
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000108 ServerProxy Represents a logical connection to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000109
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000110 MultiCall Executor of boxcared xmlrpc requests
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000111 DateTime dateTime wrapper for an ISO 8601 string or time tuple or
112 localtime integer value to generate a "dateTime.iso8601"
113 XML-RPC value
114 Binary binary data wrapper
Fred Drake1b410792001-09-04 18:55:03 +0000115
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000116 Marshaller Generate an XML-RPC params chunk from a Python data structure
117 Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
118 Transport Handles an HTTP transaction to an XML-RPC server
119 SafeTransport Handles an HTTPS transaction to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000120
121Exported constants:
122
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000123 True
124 False
Fred Drake1b410792001-09-04 18:55:03 +0000125
126Exported functions:
127
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000128 getparser Create instance of the fastest available parser & attach
129 to an unmarshalling object
130 dumps Convert an argument tuple or a Fault instance to an XML-RPC
131 request (or response, if the methodresponse option is used).
132 loads Convert an XML-RPC packet to unmarshalled data plus a method
133 name (None if not present).
Fred Drake1b410792001-09-04 18:55:03 +0000134"""
135
Neal Norwitzff113342007-04-17 08:42:15 +0000136import re, time, operator
Georg Brandl24420152008-05-26 16:32:26 +0000137import http.client
Georg Brandlcef803f2009-06-04 09:04:53 +0000138from xml.parsers import expat
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +0000139import gzip
140import socket
141import errno
142from io import BytesIO
Fredrik Lundh1538c232001-10-01 19:42:03 +0000143
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000144# --------------------------------------------------------------------
145# Internal stuff
146
Fredrik Lundhb9056332001-07-11 17:42:21 +0000147try:
Fred Drakeba613c32005-02-10 18:33:30 +0000148 import datetime
149except ImportError:
150 datetime = None
151
Fredrik Lundhb9056332001-07-11 17:42:21 +0000152def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
153 # decode non-ascii string (if possible)
Guido van Rossum54ad5232007-05-27 09:17:48 +0000154 if encoding and is8bit(data):
Guido van Rossumef87d6e2007-05-02 19:09:54 +0000155 data = str(data, encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000156 return data
157
Neal Norwitzff113342007-04-17 08:42:15 +0000158def escape(s):
159 s = s.replace("&", "&")
160 s = s.replace("<", "&lt;")
161 return s.replace(">", "&gt;",)
Fredrik Lundh1538c232001-10-01 19:42:03 +0000162
Guido van Rossum54ad5232007-05-27 09:17:48 +0000163def _stringify(string):
164 # convert to 7-bit ascii if possible
165 try:
Brett Cannon2dbde5e2007-07-30 03:50:35 +0000166 return string.decode("ascii")
Guido van Rossum261f9df2007-08-31 14:07:27 +0000167 except (UnicodeError, TypeError, AttributeError):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000168 return string
169
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000170__version__ = "1.0.1"
171
172# xmlrpc integer limits
Guido van Rossume2a383d2007-01-15 16:59:06 +0000173MAXINT = 2**31-1
174MININT = -2**31
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000175
176# --------------------------------------------------------------------
177# Error constants (from Dan Libby's specification at
178# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
179
180# Ranges of errors
181PARSE_ERROR = -32700
182SERVER_ERROR = -32600
183APPLICATION_ERROR = -32500
184SYSTEM_ERROR = -32400
185TRANSPORT_ERROR = -32300
186
187# Specific errors
188NOT_WELLFORMED_ERROR = -32700
189UNSUPPORTED_ENCODING = -32701
190INVALID_ENCODING_CHAR = -32702
191INVALID_XMLRPC = -32600
192METHOD_NOT_FOUND = -32601
193INVALID_METHOD_PARAMS = -32602
194INTERNAL_ERROR = -32603
Fredrik Lundhb9056332001-07-11 17:42:21 +0000195
196# --------------------------------------------------------------------
197# Exceptions
198
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000199##
200# Base class for all kinds of client-side errors.
201
Fredrik Lundh78eedce2001-08-23 20:04:33 +0000202class Error(Exception):
Fred Drake1b410792001-09-04 18:55:03 +0000203 """Base class for client errors."""
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000204 def __str__(self):
205 return repr(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000206
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000207##
208# Indicates an HTTP-level protocol error. This is raised by the HTTP
209# transport layer, if the server returns an error code other than 200
210# (OK).
211#
212# @param url The target URL.
213# @param errcode The HTTP error code.
214# @param errmsg The HTTP error message.
215# @param headers The HTTP header dictionary.
216
Fredrik Lundhb9056332001-07-11 17:42:21 +0000217class ProtocolError(Error):
Fred Drake1b410792001-09-04 18:55:03 +0000218 """Indicates an HTTP protocol error."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000219 def __init__(self, url, errcode, errmsg, headers):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000220 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000221 self.url = url
222 self.errcode = errcode
223 self.errmsg = errmsg
224 self.headers = headers
225 def __repr__(self):
226 return (
227 "<ProtocolError for %s: %s %s>" %
228 (self.url, self.errcode, self.errmsg)
229 )
230
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000231##
232# Indicates a broken XML-RPC response package. This exception is
233# raised by the unmarshalling layer, if the XML-RPC response is
234# malformed.
235
Fredrik Lundhb9056332001-07-11 17:42:21 +0000236class ResponseError(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000237 """Indicates a broken response package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000238 pass
239
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000240##
241# Indicates an XML-RPC fault response package. This exception is
242# raised by the unmarshalling layer, if the XML-RPC response contains
243# a fault string. This exception can also used as a class, to
244# generate a fault XML-RPC message.
245#
246# @param faultCode The XML-RPC fault code.
247# @param faultString The XML-RPC fault string.
248
Fredrik Lundhb9056332001-07-11 17:42:21 +0000249class Fault(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000250 """Indicates an XML-RPC fault package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000251 def __init__(self, faultCode, faultString, **extra):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000252 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000253 self.faultCode = faultCode
254 self.faultString = faultString
255 def __repr__(self):
256 return (
257 "<Fault %s: %s>" %
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000258 (self.faultCode, repr(self.faultString))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000259 )
260
261# --------------------------------------------------------------------
262# Special values
263
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000264##
Georg Brandl38eceaa2008-05-26 11:14:17 +0000265# Backwards compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000266
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000267boolean = Boolean = bool
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000268
269##
270# Wrapper for XML-RPC DateTime values. This converts a time value to
271# the format used by XML-RPC.
272# <p>
273# The value can be given as a string in the format
274# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
275# time.localtime()), or an integer value (as returned by time.time()).
276# The wrapper uses time.localtime() to convert an integer to a time
277# tuple.
278#
279# @param value The time, given as an ISO 8601 string, a time
280# tuple, or a integer time value.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000281
Christian Heimesdae2a892008-04-19 00:55:37 +0000282def _strftime(value):
283 if datetime:
284 if isinstance(value, datetime.datetime):
285 return "%04d%02d%02dT%02d:%02d:%02d" % (
286 value.year, value.month, value.day,
287 value.hour, value.minute, value.second)
288
289 if not isinstance(value, (tuple, time.struct_time)):
290 if value == 0:
291 value = time.time()
292 value = time.localtime(value)
293
294 return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
295
Fredrik Lundhb9056332001-07-11 17:42:21 +0000296class DateTime:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000297 """DateTime wrapper for an ISO 8601 string or time tuple or
298 localtime integer value to generate 'dateTime.iso8601' XML-RPC
299 value.
300 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000301
302 def __init__(self, value=0):
Christian Heimesdae2a892008-04-19 00:55:37 +0000303 if isinstance(value, str):
304 self.value = value
305 else:
306 self.value = _strftime(value)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000307
Christian Heimes05e8be12008-02-23 18:30:17 +0000308 def make_comparable(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000309 if isinstance(other, DateTime):
Christian Heimes05e8be12008-02-23 18:30:17 +0000310 s = self.value
311 o = other.value
312 elif datetime and isinstance(other, datetime.datetime):
313 s = self.value
314 o = other.strftime("%Y%m%dT%H:%M:%S")
315 elif isinstance(other, (str, unicode)):
316 s = self.value
317 o = other
318 elif hasattr(other, "timetuple"):
319 s = self.timetuple()
320 o = other.timetuple()
321 else:
322 otype = (hasattr(other, "__class__")
323 and other.__class__.__name__
324 or type(other))
325 raise TypeError("Can't compare %s and %s" %
326 (self.__class__.__name__, otype))
327 return s, o
328
329 def __lt__(self, other):
330 s, o = self.make_comparable(other)
331 return s < o
332
333 def __le__(self, other):
334 s, o = self.make_comparable(other)
335 return s <= o
336
337 def __gt__(self, other):
338 s, o = self.make_comparable(other)
339 return s > o
340
341 def __ge__(self, other):
342 s, o = self.make_comparable(other)
343 return s >= o
344
345 def __eq__(self, other):
346 s, o = self.make_comparable(other)
347 return s == o
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000348
349 def __ne__(self, other):
Christian Heimes05e8be12008-02-23 18:30:17 +0000350 s, o = self.make_comparable(other)
351 return s != o
352
353 def timetuple(self):
354 return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
355
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000356 ##
357 # Get date/time value.
358 #
359 # @return Date/time value, as an ISO 8601 string.
360
361 def __str__(self):
362 return self.value
363
Fredrik Lundhb9056332001-07-11 17:42:21 +0000364 def __repr__(self):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000365 return "<DateTime %s at %x>" % (repr(self.value), id(self))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000366
367 def decode(self, data):
Neal Norwitzff113342007-04-17 08:42:15 +0000368 self.value = str(data).strip()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000369
370 def encode(self, out):
371 out.write("<value><dateTime.iso8601>")
372 out.write(self.value)
373 out.write("</dateTime.iso8601></value>\n")
374
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000375def _datetime(data):
376 # decode xml element contents into a DateTime structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000377 value = DateTime()
378 value.decode(data)
379 return value
380
Skip Montanaro174dd222005-05-14 20:54:16 +0000381def _datetime_type(data):
382 t = time.strptime(data, "%Y%m%dT%H:%M:%S")
383 return datetime.datetime(*tuple(t)[:6])
384
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000385##
386# Wrapper for binary data. This can be used to transport any kind
387# of binary data over XML-RPC, using BASE64 encoding.
388#
389# @param data An 8-bit string containing arbitrary data.
390
Skip Montanarobfcbfa72003-04-24 19:51:31 +0000391import base64
Guido van Rossum68937b42007-05-18 00:51:22 +0000392import io
Skip Montanarobfcbfa72003-04-24 19:51:31 +0000393
Fredrik Lundhb9056332001-07-11 17:42:21 +0000394class Binary:
Fred Drake1b410792001-09-04 18:55:03 +0000395 """Wrapper for binary data."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000396
397 def __init__(self, data=None):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000398 if data is None:
399 data = b""
400 else:
401 if not isinstance(data, bytes):
402 raise TypeError("expected bytes, not %s" %
403 data.__class__.__name__)
404 data = bytes(data) # Make a copy of the bytes!
Fredrik Lundhb9056332001-07-11 17:42:21 +0000405 self.data = data
406
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000407 ##
408 # Get buffer contents.
409 #
410 # @return Buffer contents, as an 8-bit string.
411
412 def __str__(self):
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000413 return str(self.data, "latin-1") # XXX encoding?!
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000414
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000415 def __eq__(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000416 if isinstance(other, Binary):
417 other = other.data
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000418 return self.data == other
419
420 def __ne__(self, other):
421 if isinstance(other, Binary):
422 other = other.data
423 return self.data != other
Fredrik Lundhb9056332001-07-11 17:42:21 +0000424
425 def decode(self, data):
Georg Brandlb54d8012009-06-04 09:11:51 +0000426 self.data = base64.decodebytes(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000427
428 def encode(self, out):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000429 out.write("<value><base64>\n")
Georg Brandlb54d8012009-06-04 09:11:51 +0000430 encoded = base64.encodebytes(self.data)
Brett Cannon2dbde5e2007-07-30 03:50:35 +0000431 out.write(encoded.decode('ascii'))
432 out.write('\n')
Fredrik Lundhb9056332001-07-11 17:42:21 +0000433 out.write("</base64></value>\n")
434
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000435def _binary(data):
436 # decode xml element contents into a Binary structure
Fredrik Lundhb9056332001-07-11 17:42:21 +0000437 value = Binary()
438 value.decode(data)
439 return value
440
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000441WRAPPERS = (DateTime, Binary)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000442
443# --------------------------------------------------------------------
444# XML parsers
445
Georg Brandlcef803f2009-06-04 09:04:53 +0000446class ExpatParser:
447 # fast expat parser for Python 2.0 and later.
448 def __init__(self, target):
449 self._parser = parser = expat.ParserCreate(None, None)
450 self._target = target
451 parser.StartElementHandler = target.start
452 parser.EndElementHandler = target.end
453 parser.CharacterDataHandler = target.data
454 encoding = None
455 target.xml(encoding, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000456
Georg Brandlcef803f2009-06-04 09:04:53 +0000457 def feed(self, data):
458 self._parser.Parse(data, 0)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000459
Georg Brandlcef803f2009-06-04 09:04:53 +0000460 def close(self):
461 self._parser.Parse("", 1) # end of data
462 del self._target, self._parser # get rid of circular references
Fredrik Lundhb9056332001-07-11 17:42:21 +0000463
Fredrik Lundhb9056332001-07-11 17:42:21 +0000464# --------------------------------------------------------------------
465# XML-RPC marshalling and unmarshalling code
466
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000467##
468# XML-RPC marshaller.
469#
470# @param encoding Default encoding for 8-bit strings. The default
471# value is None (interpreted as UTF-8).
472# @see dumps
473
Fredrik Lundhb9056332001-07-11 17:42:21 +0000474class Marshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000475 """Generate an XML-RPC params chunk from a Python data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000476
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000477 Create a Marshaller instance for each set of parameters, and use
478 the "dumps" method to convert your data (represented as a tuple)
479 to an XML-RPC params chunk. To write a fault response, pass a
480 Fault instance instead. You may prefer to use the "dumps" module
481 function for this purpose.
Fred Drake1b410792001-09-04 18:55:03 +0000482 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000483
484 # by the way, if you don't understand what's going on in here,
485 # that's perfectly ok.
486
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000487 def __init__(self, encoding=None, allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000488 self.memo = {}
489 self.data = None
490 self.encoding = encoding
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000491 self.allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +0000492
Fredrik Lundhb9056332001-07-11 17:42:21 +0000493 dispatch = {}
494
495 def dumps(self, values):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000496 out = []
497 write = out.append
498 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000499 if isinstance(values, Fault):
500 # fault instance
501 write("<fault>\n")
Martin v. Löwis541342f2003-07-12 07:53:04 +0000502 dump({'faultCode': values.faultCode,
503 'faultString': values.faultString},
504 write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000505 write("</fault>\n")
506 else:
507 # parameter block
Fredrik Lundhc266bb02001-08-23 20:13:08 +0000508 # FIXME: the xml-rpc specification allows us to leave out
509 # the entire <params> block if there are no parameters.
510 # however, changing this may break older code (including
511 # old versions of xmlrpclib.py), so this is better left as
512 # is for now. See @XMLRPC3 for more information. /F
Fredrik Lundhb9056332001-07-11 17:42:21 +0000513 write("<params>\n")
514 for v in values:
515 write("<param>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000516 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000517 write("</param>\n")
518 write("</params>\n")
Neal Norwitzff113342007-04-17 08:42:15 +0000519 result = "".join(out)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000520 return result
521
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000522 def __dump(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000523 try:
524 f = self.dispatch[type(value)]
525 except KeyError:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000526 # check if this object can be marshalled as a structure
527 try:
528 value.__dict__
529 except:
Collin Winterce36ad82007-08-30 01:19:48 +0000530 raise TypeError("cannot marshal %s objects" % type(value))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000531 # check if this class is a sub-class of a basic type,
532 # because we don't know how to marshal these types
533 # (e.g. a string sub-class)
534 for type_ in type(value).__mro__:
535 if type_ in self.dispatch.keys():
Collin Winterce36ad82007-08-30 01:19:48 +0000536 raise TypeError("cannot marshal %s objects" % type(value))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000537 # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
538 # for the p3yk merge, this should probably be fixed more neatly.
539 f = self.dispatch["_arbitrary_instance"]
540 f(self, value, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000541
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000542 def dump_nil (self, value, write):
543 if not self.allow_none:
Collin Winterce36ad82007-08-30 01:19:48 +0000544 raise TypeError("cannot marshal None unless allow_none is enabled")
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000545 write("<value><nil/></value>")
Guido van Rossum13257902007-06-07 23:15:56 +0000546 dispatch[type(None)] = dump_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000547
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000548 def dump_int(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000549 # in case ints are > 32 bits
550 if value > MAXINT or value < MININT:
Collin Winterce36ad82007-08-30 01:19:48 +0000551 raise OverflowError("int exceeds XML-RPC limits")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000552 write("<value><int>")
553 write(str(value))
554 write("</int></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000555 #dispatch[int] = dump_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000556
Georg Brandl38eceaa2008-05-26 11:14:17 +0000557 def dump_bool(self, value, write):
558 write("<value><boolean>")
559 write(value and "1" or "0")
560 write("</boolean></value>\n")
561 dispatch[bool] = dump_bool
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000562
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000563 def dump_long(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000564 if value > MAXINT or value < MININT:
Collin Winterce36ad82007-08-30 01:19:48 +0000565 raise OverflowError("long int exceeds XML-RPC limits")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000566 write("<value><int>")
567 write(str(int(value)))
568 write("</int></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000569 dispatch[int] = dump_long
Skip Montanaro5e9c71b2001-10-10 15:56:34 +0000570
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000571 def dump_double(self, value, write):
572 write("<value><double>")
573 write(repr(value))
574 write("</double></value>\n")
Guido van Rossum13257902007-06-07 23:15:56 +0000575 dispatch[float] = dump_double
Fredrik Lundhb9056332001-07-11 17:42:21 +0000576
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000577 def dump_string(self, value, write, escape=escape):
578 write("<value><string>")
579 write(escape(value))
580 write("</string></value>\n")
Guido van Rossum98297ee2007-11-06 21:34:58 +0000581 dispatch[bytes] = dump_string
Fredrik Lundhb9056332001-07-11 17:42:21 +0000582
Guido van Rossum54ad5232007-05-27 09:17:48 +0000583 def dump_unicode(self, value, write, escape=escape):
Guido van Rossum54ad5232007-05-27 09:17:48 +0000584 write("<value><string>")
585 write(escape(value))
586 write("</string></value>\n")
587 dispatch[str] = dump_unicode
Fredrik Lundhb9056332001-07-11 17:42:21 +0000588
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000589 def dump_array(self, value, write):
590 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000591 if i in self.memo:
Collin Winterce36ad82007-08-30 01:19:48 +0000592 raise TypeError("cannot marshal recursive sequences")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000593 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000594 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000595 write("<value><array><data>\n")
596 for v in value:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000597 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000598 write("</data></array></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000599 del self.memo[i]
Guido van Rossum13257902007-06-07 23:15:56 +0000600 dispatch[tuple] = dump_array
601 dispatch[list] = dump_array
Fredrik Lundhb9056332001-07-11 17:42:21 +0000602
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000603 def dump_struct(self, value, write, escape=escape):
604 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000605 if i in self.memo:
Collin Winterce36ad82007-08-30 01:19:48 +0000606 raise TypeError("cannot marshal recursive dictionaries")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000607 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000608 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000609 write("<value><struct>\n")
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000610 for k, v in value.items():
Fredrik Lundhb9056332001-07-11 17:42:21 +0000611 write("<member>\n")
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000612 if not isinstance(k, str):
Collin Winterce36ad82007-08-30 01:19:48 +0000613 raise TypeError("dictionary key must be string")
Fredrik Lundh1538c232001-10-01 19:42:03 +0000614 write("<name>%s</name>\n" % escape(k))
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000615 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000616 write("</member>\n")
617 write("</struct></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000618 del self.memo[i]
Guido van Rossum13257902007-06-07 23:15:56 +0000619 dispatch[dict] = dump_struct
Fredrik Lundhb9056332001-07-11 17:42:21 +0000620
Fred Drakeba613c32005-02-10 18:33:30 +0000621 if datetime:
622 def dump_datetime(self, value, write):
623 write("<value><dateTime.iso8601>")
Christian Heimesdae2a892008-04-19 00:55:37 +0000624 write(_strftime(value))
Fred Drakeba613c32005-02-10 18:33:30 +0000625 write("</dateTime.iso8601></value>\n")
626 dispatch[datetime.datetime] = dump_datetime
627
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000628 def dump_instance(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000629 # check for special wrappers
630 if value.__class__ in WRAPPERS:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000631 self.write = write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000632 value.encode(self)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000633 del self.write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000634 else:
635 # store instance attributes as a struct (really?)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000636 self.dump_struct(value.__dict__, write)
Guido van Rossume4dea982006-04-21 13:45:00 +0000637 dispatch[DateTime] = dump_instance
638 dispatch[Binary] = dump_instance
Thomas Wouters89f507f2006-12-13 04:49:30 +0000639 # XXX(twouters): using "_arbitrary_instance" as key as a quick-fix
640 # for the p3yk merge, this should probably be fixed more neatly.
641 dispatch["_arbitrary_instance"] = dump_instance
Fredrik Lundhb9056332001-07-11 17:42:21 +0000642
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000643##
644# XML-RPC unmarshaller.
645#
646# @see loads
647
Fredrik Lundhb9056332001-07-11 17:42:21 +0000648class Unmarshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000649 """Unmarshal an XML-RPC response, based on incoming XML event
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000650 messages (start, data, end). Call close() to get the resulting
Fred Drake1b410792001-09-04 18:55:03 +0000651 data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000652
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000653 Note that this reader is fairly tolerant, and gladly accepts bogus
654 XML-RPC data without complaining (but not bogus XML).
Fred Drake1b410792001-09-04 18:55:03 +0000655 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000656
657 # and again, if you don't understand what's going on in here,
658 # that's perfectly ok.
659
Skip Montanaro174dd222005-05-14 20:54:16 +0000660 def __init__(self, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000661 self._type = None
662 self._stack = []
663 self._marks = []
664 self._data = []
665 self._methodname = None
666 self._encoding = "utf-8"
667 self.append = self._stack.append
Skip Montanaro174dd222005-05-14 20:54:16 +0000668 self._use_datetime = use_datetime
669 if use_datetime and not datetime:
Collin Winterce36ad82007-08-30 01:19:48 +0000670 raise ValueError("the datetime module is not available")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000671
672 def close(self):
673 # return response tuple and target method
674 if self._type is None or self._marks:
675 raise ResponseError()
676 if self._type == "fault":
Guido van Rossum68468eb2003-02-27 20:14:51 +0000677 raise Fault(**self._stack[0])
Fredrik Lundhb9056332001-07-11 17:42:21 +0000678 return tuple(self._stack)
679
680 def getmethodname(self):
681 return self._methodname
682
683 #
684 # event handlers
685
686 def xml(self, encoding, standalone):
687 self._encoding = encoding
688 # FIXME: assert standalone == 1 ???
689
690 def start(self, tag, attrs):
691 # prepare to handle this element
692 if tag == "array" or tag == "struct":
693 self._marks.append(len(self._stack))
694 self._data = []
695 self._value = (tag == "value")
696
697 def data(self, text):
698 self._data.append(text)
699
Neal Norwitzff113342007-04-17 08:42:15 +0000700 def end(self, tag):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000701 # call the appropriate end tag handler
702 try:
703 f = self.dispatch[tag]
704 except KeyError:
705 pass # unknown tag ?
706 else:
Neal Norwitzff113342007-04-17 08:42:15 +0000707 return f(self, "".join(self._data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000708
709 #
710 # accelerator support
711
712 def end_dispatch(self, tag, data):
713 # dispatch data
714 try:
715 f = self.dispatch[tag]
716 except KeyError:
717 pass # unknown tag ?
718 else:
719 return f(self, data)
720
721 #
722 # element decoders
723
724 dispatch = {}
725
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000726 def end_nil (self, data):
727 self.append(None)
728 self._value = 0
729 dispatch["nil"] = end_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000730
Fredrik Lundh1538c232001-10-01 19:42:03 +0000731 def end_boolean(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000732 if data == "0":
733 self.append(False)
734 elif data == "1":
735 self.append(True)
736 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000737 raise TypeError("bad boolean value")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000738 self._value = 0
739 dispatch["boolean"] = end_boolean
740
Fredrik Lundh1538c232001-10-01 19:42:03 +0000741 def end_int(self, data):
742 self.append(int(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000743 self._value = 0
744 dispatch["i4"] = end_int
Georg Brandlf08a9dd2008-06-10 16:57:31 +0000745 dispatch["i8"] = end_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000746 dispatch["int"] = end_int
747
Fredrik Lundh1538c232001-10-01 19:42:03 +0000748 def end_double(self, data):
749 self.append(float(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000750 self._value = 0
751 dispatch["double"] = end_double
752
Fredrik Lundh1538c232001-10-01 19:42:03 +0000753 def end_string(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000754 if self._encoding:
755 data = _decode(data, self._encoding)
756 self.append(_stringify(data))
757 self._value = 0
758 dispatch["string"] = end_string
759 dispatch["name"] = end_string # struct keys are always strings
760
761 def end_array(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000762 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000763 # map arrays to Python lists
764 self._stack[mark:] = [self._stack[mark:]]
765 self._value = 0
766 dispatch["array"] = end_array
767
768 def end_struct(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000769 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000770 # map structs to Python dictionaries
771 dict = {}
772 items = self._stack[mark:]
773 for i in range(0, len(items), 2):
774 dict[_stringify(items[i])] = items[i+1]
775 self._stack[mark:] = [dict]
776 self._value = 0
777 dispatch["struct"] = end_struct
778
Fredrik Lundh1538c232001-10-01 19:42:03 +0000779 def end_base64(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000780 value = Binary()
Guido van Rossum54a40cb2007-08-27 22:27:41 +0000781 value.decode(data.encode("ascii"))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000782 self.append(value)
783 self._value = 0
784 dispatch["base64"] = end_base64
785
Fredrik Lundh1538c232001-10-01 19:42:03 +0000786 def end_dateTime(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000787 value = DateTime()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000788 value.decode(data)
Skip Montanaro174dd222005-05-14 20:54:16 +0000789 if self._use_datetime:
790 value = _datetime_type(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000791 self.append(value)
792 dispatch["dateTime.iso8601"] = end_dateTime
793
794 def end_value(self, data):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000795 # if we stumble upon a value element with no internal
Fredrik Lundhb9056332001-07-11 17:42:21 +0000796 # elements, treat it as a string element
797 if self._value:
798 self.end_string(data)
799 dispatch["value"] = end_value
800
801 def end_params(self, data):
802 self._type = "params"
803 dispatch["params"] = end_params
804
805 def end_fault(self, data):
806 self._type = "fault"
807 dispatch["fault"] = end_fault
808
Fredrik Lundh1538c232001-10-01 19:42:03 +0000809 def end_methodName(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000810 if self._encoding:
811 data = _decode(data, self._encoding)
812 self._methodname = data
813 self._type = "methodName" # no params
814 dispatch["methodName"] = end_methodName
815
Martin v. Löwis45394c22003-10-31 13:49:36 +0000816## Multicall support
817#
Fredrik Lundhb9056332001-07-11 17:42:21 +0000818
Martin v. Löwis45394c22003-10-31 13:49:36 +0000819class _MultiCallMethod:
820 # some lesser magic to store calls made to a MultiCall object
821 # for batch execution
822 def __init__(self, call_list, name):
823 self.__call_list = call_list
824 self.__name = name
825 def __getattr__(self, name):
826 return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
827 def __call__(self, *args):
828 self.__call_list.append((self.__name, args))
829
Martin v. Löwis12237b32004-08-22 16:04:50 +0000830class MultiCallIterator:
Martin v. Löwis45394c22003-10-31 13:49:36 +0000831 """Iterates over the results of a multicall. Exceptions are
832 thrown in response to xmlrpc faults."""
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000833
Martin v. Löwis12237b32004-08-22 16:04:50 +0000834 def __init__(self, results):
835 self.results = results
836
837 def __getitem__(self, i):
838 item = self.results[i]
839 if type(item) == type({}):
840 raise Fault(item['faultCode'], item['faultString'])
841 elif type(item) == type([]):
842 return item[0]
Martin v. Löwis45394c22003-10-31 13:49:36 +0000843 else:
Collin Winterce36ad82007-08-30 01:19:48 +0000844 raise ValueError("unexpected type in multicall result")
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000845
Martin v. Löwis45394c22003-10-31 13:49:36 +0000846class MultiCall:
847 """server -> a object used to boxcar method calls
848
849 server should be a ServerProxy object.
850
851 Methods can be added to the MultiCall using normal
852 method call syntax e.g.:
853
854 multicall = MultiCall(server_proxy)
855 multicall.add(2,3)
856 multicall.get_address("Guido")
857
858 To execute the multicall, call the MultiCall object e.g.:
859
860 add_result, address = multicall()
861 """
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000862
Martin v. Löwis45394c22003-10-31 13:49:36 +0000863 def __init__(self, server):
864 self.__server = server
865 self.__call_list = []
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000866
Martin v. Löwis45394c22003-10-31 13:49:36 +0000867 def __repr__(self):
868 return "<MultiCall at %x>" % id(self)
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000869
Martin v. Löwis45394c22003-10-31 13:49:36 +0000870 __str__ = __repr__
871
872 def __getattr__(self, name):
873 return _MultiCallMethod(self.__call_list, name)
874
875 def __call__(self):
876 marshalled_list = []
877 for name, args in self.__call_list:
878 marshalled_list.append({'methodName' : name, 'params' : args})
879
880 return MultiCallIterator(self.__server.system.multicall(marshalled_list))
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000881
Fredrik Lundhb9056332001-07-11 17:42:21 +0000882# --------------------------------------------------------------------
883# convenience functions
884
Georg Brandl38eceaa2008-05-26 11:14:17 +0000885FastMarshaller = FastParser = FastUnmarshaller = None
886
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000887##
888# Create a parser object, and connect it to an unmarshalling instance.
889# This function picks the fastest available XML parser.
890#
891# return A (parser, unmarshaller) tuple.
892
Skip Montanaro174dd222005-05-14 20:54:16 +0000893def getparser(use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000894 """getparser() -> parser, unmarshaller
895
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000896 Create an instance of the fastest available parser, and attach it
897 to an unmarshalling object. Return both objects.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000898 """
Skip Montanaro174dd222005-05-14 20:54:16 +0000899 if use_datetime and not datetime:
Collin Winterce36ad82007-08-30 01:19:48 +0000900 raise ValueError("the datetime module is not available")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000901 if FastParser and FastUnmarshaller:
Skip Montanaro174dd222005-05-14 20:54:16 +0000902 if use_datetime:
903 mkdatetime = _datetime_type
904 else:
905 mkdatetime = _datetime
906 target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000907 parser = FastParser(target)
908 else:
Skip Montanaro174dd222005-05-14 20:54:16 +0000909 target = Unmarshaller(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000910 if FastParser:
911 parser = FastParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000912 else:
Georg Brandlcef803f2009-06-04 09:04:53 +0000913 parser = ExpatParser(target)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000914 return parser, target
915
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000916##
917# Convert a Python tuple or a Fault instance to an XML-RPC packet.
918#
919# @def dumps(params, **options)
920# @param params A tuple or Fault instance.
921# @keyparam methodname If given, create a methodCall request for
922# this method name.
923# @keyparam methodresponse If given, create a methodResponse packet.
924# If used with a tuple, the tuple must be a singleton (that is,
925# it must contain exactly one element).
926# @keyparam encoding The packet encoding.
927# @return A string containing marshalled data.
928
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000929def dumps(params, methodname=None, methodresponse=None, encoding=None,
930 allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000931 """data [,options] -> marshalled data
932
933 Convert an argument tuple or a Fault instance to an XML-RPC
934 request (or response, if the methodresponse option is used).
935
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000936 In addition to the data object, the following options can be given
937 as keyword arguments:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000938
939 methodname: the method name for a methodCall packet
940
941 methodresponse: true to create a methodResponse packet.
942 If this option is used with a tuple, the tuple must be
943 a singleton (i.e. it can contain only one element).
944
945 encoding: the packet encoding (default is UTF-8)
946
947 All 8-bit strings in the data structure are assumed to use the
948 packet encoding. Unicode strings are automatically converted,
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000949 where necessary.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000950 """
951
Guido van Rossum13257902007-06-07 23:15:56 +0000952 assert isinstance(params, (tuple, Fault)), "argument must be tuple or Fault instance"
Fredrik Lundhb9056332001-07-11 17:42:21 +0000953 if isinstance(params, Fault):
954 methodresponse = 1
Guido van Rossum13257902007-06-07 23:15:56 +0000955 elif methodresponse and isinstance(params, tuple):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000956 assert len(params) == 1, "response tuple must be a singleton"
957
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000958 if not encoding:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000959 encoding = "utf-8"
960
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000961 if FastMarshaller:
962 m = FastMarshaller(encoding)
963 else:
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000964 m = Marshaller(encoding, allow_none)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000965
Fredrik Lundhb9056332001-07-11 17:42:21 +0000966 data = m.dumps(params)
967
968 if encoding != "utf-8":
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000969 xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000970 else:
971 xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
972
973 # standard XML-RPC wrappings
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000974 if methodname:
Fredrik Lundhb9056332001-07-11 17:42:21 +0000975 # a method call
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000976 if not isinstance(methodname, str):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000977 methodname = methodname.encode(encoding)
978 data = (
979 xmlheader,
980 "<methodCall>\n"
981 "<methodName>", methodname, "</methodName>\n",
982 data,
983 "</methodCall>\n"
984 )
985 elif methodresponse:
986 # a method response, or a fault structure
987 data = (
988 xmlheader,
989 "<methodResponse>\n",
990 data,
991 "</methodResponse>\n"
992 )
993 else:
994 return data # return as is
Neal Norwitzff113342007-04-17 08:42:15 +0000995 return "".join(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000996
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000997##
998# Convert an XML-RPC packet to a Python object. If the XML-RPC packet
999# represents a fault condition, this function raises a Fault exception.
1000#
1001# @param data An XML-RPC packet, given as an 8-bit string.
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +00001002# @return A tuple containing the unpacked data, and the method name
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001003# (None if not present).
1004# @see Fault
1005
Skip Montanaro174dd222005-05-14 20:54:16 +00001006def loads(data, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001007 """data -> unmarshalled data, method name
1008
1009 Convert an XML-RPC packet to unmarshalled data plus a method
1010 name (None if not present).
1011
1012 If the XML-RPC packet represents a fault condition, this function
1013 raises a Fault exception.
1014 """
Skip Montanaro174dd222005-05-14 20:54:16 +00001015 p, u = getparser(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001016 p.feed(data)
1017 p.close()
1018 return u.close(), u.getmethodname()
1019
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001020##
1021# Encode a string using the gzip content encoding such as specified by the
1022# Content-Encoding: gzip
1023# in the HTTP header, as described in RFC 1952
1024#
1025# @param data the unencoded data
1026# @return the encoded data
1027
1028def gzip_encode(data):
1029 """data -> gzip encoded data
1030
1031 Encode data using the gzip content encoding as described in RFC 1952
1032 """
1033 f = BytesIO()
1034 gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
1035 gzf.write(data)
1036 gzf.close()
1037 encoded = f.getvalue()
1038 f.close()
1039 return encoded
1040
1041##
1042# Decode a string using the gzip content encoding such as specified by the
1043# Content-Encoding: gzip
1044# in the HTTP header, as described in RFC 1952
1045#
1046# @param data The encoded data
1047# @return the unencoded data
1048# @raises ValueError if data is not correctly coded.
1049
1050def gzip_decode(data):
1051 """gzip encoded data -> unencoded data
1052
1053 Decode data using the gzip content encoding as described in RFC 1952
1054 """
1055 f = BytesIO(data)
1056 gzf = gzip.GzipFile(mode="rb", fileobj=f)
1057 try:
1058 decoded = gzf.read()
1059 except IOError:
1060 raise ValueError("invalid data")
1061 f.close()
1062 gzf.close()
1063 return decoded
1064
1065##
1066# Return a decoded file-like object for the gzip encoding
1067# as described in RFC 1952.
1068#
1069# @param response A stream supporting a read() method
1070# @return a file-like object that the decoded data can be read() from
1071
1072class GzipDecodedResponse(gzip.GzipFile):
1073 """a file-like object to decode a response encoded with the gzip
1074 method, as described in RFC 1952.
1075 """
1076 def __init__(self, response):
1077 #response doesn't support tell() and read(), required by
1078 #GzipFile
1079 self.io = BytesIO(response.read())
1080 gzip.GzipFile.__init__(self, mode="rb", fileobj=self.io)
1081
1082 def close(self):
1083 gzip.GzipFile.close(self)
1084 self.io.close()
1085
Fredrik Lundhb9056332001-07-11 17:42:21 +00001086
1087# --------------------------------------------------------------------
1088# request dispatcher
1089
1090class _Method:
1091 # some magic to bind an XML-RPC method to an RPC server.
1092 # supports "nested" methods (e.g. examples.getStateName)
1093 def __init__(self, send, name):
1094 self.__send = send
1095 self.__name = name
1096 def __getattr__(self, name):
1097 return _Method(self.__send, "%s.%s" % (self.__name, name))
1098 def __call__(self, *args):
1099 return self.__send(self.__name, args)
1100
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001101##
1102# Standard transport class for XML-RPC over HTTP.
1103# <p>
1104# You can create custom transports by subclassing this method, and
1105# overriding selected methods.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001106
1107class Transport:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001108 """Handles an HTTP transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001109
1110 # client identifier (may be overridden)
1111 user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
1112
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001113 #if true, we'll request gzip encoding
1114 accept_gzip_encoding = True
1115
1116 # if positive, encode request using gzip if it exceeds this threshold
1117 # note that many server will get confused, so only use it if you know
1118 # that they can decode such a request
1119 encode_threshold = None #None = don't encode
1120
Skip Montanaro174dd222005-05-14 20:54:16 +00001121 def __init__(self, use_datetime=0):
1122 self._use_datetime = use_datetime
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001123 self._connection = (None, None)
1124 self._extra_headers = []
Skip Montanaro174dd222005-05-14 20:54:16 +00001125
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001126 ##
1127 # Send a complete request, and parse the response.
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001128 # Retry request if a cached connection has disconnected.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001129 #
1130 # @param host Target host.
1131 # @param handler Target PRC handler.
1132 # @param request_body XML-RPC request body.
1133 # @param verbose Debugging flag.
1134 # @return Parsed response.
1135
Fredrik Lundhb9056332001-07-11 17:42:21 +00001136 def request(self, host, handler, request_body, verbose=0):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001137 #retry request once if cached connection has gone cold
1138 for i in (0, 1):
1139 try:
1140 return self.single_request(host, handler, request_body, verbose)
Kristján Valur Jónsson43535d92009-07-03 23:23:50 +00001141 except socket.error as e:
1142 if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED):
1143 raise
1144 except http.client.BadStatusLine: #close after we sent request
1145 if i:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001146 raise
1147
1148 def single_request(self, host, handler, request_body, verbose=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001149 # issue XML-RPC request
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001150 try:
1151 http_conn = self.send_request(host, handler, request_body, verbose)
1152 resp = http_conn.getresponse()
1153 if resp.status == 200:
1154 self.verbose = verbose
1155 return self.parse_response(resp)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001156
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001157 except Fault:
1158 raise
1159 except Exception:
1160 #All unexpected errors leave connection in
1161 # a strange state, so we clear it.
1162 self.close()
1163 raise
Fredrik Lundhb9056332001-07-11 17:42:21 +00001164
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001165 #We got an error response.
1166 #Discard any response data and raise exception
1167 if resp.getheader("content-length", ""):
1168 resp.read()
1169 raise ProtocolError(
1170 host + handler,
1171 resp.status, resp.reason,
1172 dict(resp.getheaders())
1173 )
Fredrik Lundhb9056332001-07-11 17:42:21 +00001174
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001175
1176 ##
1177 # Create parser.
1178 #
1179 # @return A 2-tuple containing a parser and a unmarshaller.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001180
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001181 def getparser(self):
1182 # get parser and unmarshaller
Skip Montanaro174dd222005-05-14 20:54:16 +00001183 return getparser(use_datetime=self._use_datetime)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001184
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001185 ##
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001186 # Get authorization info from host parameter
1187 # Host may be a string, or a (host, x509-dict) tuple; if a string,
1188 # it is checked for a "user:pw@host" format, and a "Basic
1189 # Authentication" header is added if appropriate.
1190 #
1191 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1192 # @return A 3-tuple containing (actual host, extra headers,
1193 # x509 info). The header and x509 fields may be None.
1194
1195 def get_host_info(self, host):
1196
1197 x509 = {}
Guido van Rossum13257902007-06-07 23:15:56 +00001198 if isinstance(host, tuple):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001199 host, x509 = host
1200
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001201 import urllib.parse
1202 auth, host = urllib.parse.splituser(host)
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001203
1204 if auth:
1205 import base64
Georg Brandlc8dcfb62009-02-13 10:50:01 +00001206 auth = urllib.parse.unquote_to_bytes(auth)
Georg Brandlb54d8012009-06-04 09:11:51 +00001207 auth = base64.encodebytes(auth).decode("utf-8")
Neal Norwitzff113342007-04-17 08:42:15 +00001208 auth = "".join(auth.split()) # get rid of whitespace
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001209 extra_headers = [
1210 ("Authorization", "Basic " + auth)
1211 ]
1212 else:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001213 extra_headers = []
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001214
1215 return host, extra_headers, x509
1216
1217 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001218 # Connect to server.
1219 #
1220 # @param host Target host.
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001221 # @return An HTTPConnection object
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001222
Fredrik Lundhb9056332001-07-11 17:42:21 +00001223 def make_connection(self, host):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001224 #return an existing connection if possible. This allows
1225 #HTTP/1.1 keep-alive.
1226 if self._connection and host == self._connection[0]:
1227 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001228 # create a HTTP connection object from a host descriptor
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001229 chost, self._extra_headers, x509 = self.get_host_info(host)
1230 self._connection = host, http.client.HTTPConnection(chost)
1231 return self._connection[1]
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001232
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001233 ##
1234 # Clear any cached connection object.
1235 # Used in the event of socket errors.
1236 #
1237 def close(self):
1238 if self._connection[1]:
1239 self._connection[1].close()
1240 self._connection = (None, None)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001241
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001242 ##
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001243 # Send HTTP request.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001244 #
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001245 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1246 # @param handler Targer RPC handler (a path relative to host)
1247 # @param request_body The XML-RPC request body
1248 # @param debug Enable debugging if debug is true.
1249 # @return An HTTPConnection.
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001250
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001251 def send_request(self, host, handler, request_body, debug):
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001252 connection = self.make_connection(host)
1253 headers = self._extra_headers[:]
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001254 if debug:
1255 connection.set_debuglevel(1)
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001256 if self.accept_gzip_encoding:
1257 connection.putrequest("POST", handler, skip_accept_encoding=True)
1258 headers.append(("Accept-Encoding", "gzip"))
1259 else:
1260 connection.putrequest("POST", handler)
1261 headers.append(("Content-Type", "text/xml"))
1262 headers.append(("User-Agent", self.user_agent))
1263 self.send_headers(connection, headers)
1264 self.send_content(connection, request_body)
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001265 return connection
Fredrik Lundhb9056332001-07-11 17:42:21 +00001266
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001267 ##
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001268 # Send request headers.
1269 # This function provides a useful hook for subclassing
1270 #
1271 # @param connection httpConnection.
1272 # @param headers list of key,value pairs for HTTP headers
1273
1274 def send_headers(self, connection, headers):
1275 for key, val in headers:
1276 connection.putheader(key, val)
1277
1278 ##
1279 # Send request body.
1280 # This function provides a useful hook for subclassing
1281 #
1282 # @param connection httpConnection.
1283 # @param request_body XML-RPC request body.
1284
1285 def send_content(self, connection, request_body):
1286 #optionally encode the request
1287 if (self.encode_threshold is not None and
1288 self.encode_threshold < len(request_body)):
1289 connection.putheader("Content-Encoding", "gzip")
1290 request_body = gzip_encode(request_body)
1291
1292 connection.putheader("Content-Length", str(len(request_body)))
1293 connection.endheaders(request_body)
1294
1295 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001296 # Parse response.
1297 #
1298 # @param file Stream.
1299 # @return Response tuple and target method.
1300
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001301 def parse_response(self, response):
1302 # read response data from httpresponse, and parse it
1303 if response.getheader("Content-Encoding", "") == "gzip":
1304 stream = GzipDecodedResponse(response)
1305 else:
1306 stream = response
Fredrik Lundhb9056332001-07-11 17:42:21 +00001307
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001308 p, u = self.getparser()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001309
1310 while 1:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001311 data = stream.read(1024)
1312 if not data:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001313 break
1314 if self.verbose:
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001315 print("body:", repr(data))
1316 p.feed(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001317
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001318 if stream is not response:
1319 stream.close()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001320 p.close()
1321
1322 return u.close()
1323
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001324##
1325# Standard transport class for XML-RPC over HTTPS.
1326
Fredrik Lundhb9056332001-07-11 17:42:21 +00001327class SafeTransport(Transport):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001328 """Handles an HTTPS transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001329
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001330 # FIXME: mostly untested
1331
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001332 def make_connection(self, host):
1333 if self._connection and host == self._connection[0]:
1334 return self._connection[1]
1335
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001336 if not hasattr(socket, "ssl"):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001337 raise NotImplementedError(
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001338 "your version of http.client doesn't support HTTPS")
1339 # create a HTTPS connection object from a host descriptor
1340 # host may be a string, or a (host, x509-dict) tuple
1341 chost, self._extra_headers, x509 = self.get_host_info(host)
1342 self._connection = host, http.client.HTTPSConnection(chost,
1343 None, **(x509 or {}))
1344 return self._connection[1]
Fredrik Lundhb9056332001-07-11 17:42:21 +00001345
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001346##
1347# Standard server proxy. This class establishes a virtual connection
1348# to an XML-RPC server.
1349# <p>
1350# This class is available as ServerProxy and Server. New code should
1351# use ServerProxy, to avoid confusion.
1352#
1353# @def ServerProxy(uri, **options)
1354# @param uri The connection point on the server.
1355# @keyparam transport A transport factory, compatible with the
1356# standard transport class.
1357# @keyparam encoding The default encoding used for 8-bit strings
1358# (default is UTF-8).
1359# @keyparam verbose Use a true value to enable debugging output.
1360# (printed to standard output).
1361# @see Transport
1362
Fredrik Lundhb9056332001-07-11 17:42:21 +00001363class ServerProxy:
1364 """uri [,options] -> a logical connection to an XML-RPC server
1365
1366 uri is the connection point on the server, given as
1367 scheme://host/target.
1368
1369 The standard implementation always supports the "http" scheme. If
1370 SSL socket support is available (Python 2.0), it also supports
1371 "https".
1372
1373 If the target part and the slash preceding it are both omitted,
1374 "/RPC2" is assumed.
1375
1376 The following options can be given as keyword arguments:
1377
1378 transport: a transport factory
1379 encoding: the request encoding (default is UTF-8)
1380
1381 All 8-bit strings passed to the server proxy are assumed to use
1382 the given encoding.
1383 """
1384
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001385 def __init__(self, uri, transport=None, encoding=None, verbose=0,
Skip Montanaro174dd222005-05-14 20:54:16 +00001386 allow_none=0, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001387 # establish a "logical" server connection
1388
1389 # get the url
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001390 import urllib.parse
1391 type, uri = urllib.parse.splittype(uri)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001392 if type not in ("http", "https"):
Collin Winterce36ad82007-08-30 01:19:48 +00001393 raise IOError("unsupported XML-RPC protocol")
Jeremy Hylton1afc1692008-06-18 20:49:58 +00001394 self.__host, self.__handler = urllib.parse.splithost(uri)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001395 if not self.__handler:
1396 self.__handler = "/RPC2"
1397
1398 if transport is None:
1399 if type == "https":
Skip Montanaro174dd222005-05-14 20:54:16 +00001400 transport = SafeTransport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001401 else:
Skip Montanaro174dd222005-05-14 20:54:16 +00001402 transport = Transport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001403 self.__transport = transport
1404
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001405 self.__encoding = encoding or 'utf-8'
Fredrik Lundhb9056332001-07-11 17:42:21 +00001406 self.__verbose = verbose
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001407 self.__allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +00001408
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001409 def __close(self):
1410 self.__transport.close()
1411
Fredrik Lundhb9056332001-07-11 17:42:21 +00001412 def __request(self, methodname, params):
1413 # call a method on the remote server
1414
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001415 request = dumps(params, methodname, encoding=self.__encoding,
Senthil Kumaranb3af08f2009-04-01 20:20:43 +00001416 allow_none=self.__allow_none).encode(self.__encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001417
1418 response = self.__transport.request(
1419 self.__host,
1420 self.__handler,
1421 request,
1422 verbose=self.__verbose
1423 )
1424
1425 if len(response) == 1:
1426 response = response[0]
1427
1428 return response
1429
1430 def __repr__(self):
1431 return (
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001432 "<ServerProxy for %s%s>" %
Fredrik Lundhb9056332001-07-11 17:42:21 +00001433 (self.__host, self.__handler)
1434 )
1435
1436 __str__ = __repr__
Raymond Hettingercc523fc2003-11-02 09:47:05 +00001437
Fredrik Lundhb9056332001-07-11 17:42:21 +00001438 def __getattr__(self, name):
1439 # magic method dispatcher
1440 return _Method(self.__request, name)
1441
1442 # note: to call a remote object with an non-standard name, use
1443 # result getattr(server, "strange-python-name")(args)
1444
Kristján Valur Jónsson985fc6a2009-07-01 10:01:31 +00001445 def __call__(self, attr):
1446 """A workaround to get special attributes on the ServerProxy
1447 without interfering with the magic __getattr__
1448 """
1449 if attr == "close":
1450 return self.__close
1451 elif attr == "transport":
1452 return self.__transport
1453 raise AttributeError("Attribute %r not found" % (attr,))
1454
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001455# compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001456
Fredrik Lundhb9056332001-07-11 17:42:21 +00001457Server = ServerProxy
1458
1459# --------------------------------------------------------------------
1460# test code
1461
1462if __name__ == "__main__":
1463
1464 # simple test program (from the XML-RPC specification)
1465
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001466 # server = ServerProxy("http://localhost:8000") # local server
Martin v. Löwis12237b32004-08-22 16:04:50 +00001467 server = ServerProxy("http://time.xmlrpc.com/RPC2")
Fredrik Lundhb9056332001-07-11 17:42:21 +00001468
Fredrik Lundhb9056332001-07-11 17:42:21 +00001469 try:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001470 print(server.currentTime.getCurrentTime())
Guido van Rossumb940e112007-01-10 16:19:56 +00001471 except Error as v:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001472 print("ERROR", v)
Martin v. Löwis12237b32004-08-22 16:04:50 +00001473
Jeremy Hylton5d8a88a2007-08-14 16:47:39 +00001474 # The server at xmlrpc.com doesn't seem to support multicall anymore.
Martin v. Löwis12237b32004-08-22 16:04:50 +00001475 multi = MultiCall(server)
1476 multi.currentTime.getCurrentTime()
1477 multi.currentTime.getCurrentTime()
1478 try:
1479 for response in multi():
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001480 print(response)
Guido van Rossumb940e112007-01-10 16:19:56 +00001481 except Error as v:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001482 print("ERROR", v)