blob: 72866f1cf813f1681a1c927bd76500e2474ee673 [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 Boolean boolean wrapper to generate a "boolean" XML-RPC value
112 DateTime dateTime wrapper for an ISO 8601 string or time tuple or
113 localtime integer value to generate a "dateTime.iso8601"
114 XML-RPC value
115 Binary binary data wrapper
Fred Drake1b410792001-09-04 18:55:03 +0000116
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000117 SlowParser Slow but safe standard parser (based on xmllib)
118 Marshaller Generate an XML-RPC params chunk from a Python data structure
119 Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
120 Transport Handles an HTTP transaction to an XML-RPC server
121 SafeTransport Handles an HTTPS transaction to an XML-RPC server
Fred Drake1b410792001-09-04 18:55:03 +0000122
123Exported constants:
124
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000125 True
126 False
Fred Drake1b410792001-09-04 18:55:03 +0000127
128Exported functions:
129
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000130 boolean Convert any Python value to an XML-RPC boolean
131 getparser Create instance of the fastest available parser & attach
132 to an unmarshalling object
133 dumps Convert an argument tuple or a Fault instance to an XML-RPC
134 request (or response, if the methodresponse option is used).
135 loads Convert an XML-RPC packet to unmarshalled data plus a method
136 name (None if not present).
Fred Drake1b410792001-09-04 18:55:03 +0000137"""
138
Fred Drake2a2d9702001-10-17 01:51:04 +0000139import re, string, time, operator
Fredrik Lundh1538c232001-10-01 19:42:03 +0000140
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000141from types import *
Fredrik Lundhb9056332001-07-11 17:42:21 +0000142
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000143# --------------------------------------------------------------------
144# Internal stuff
145
Fredrik Lundhb9056332001-07-11 17:42:21 +0000146try:
147 unicode
148except NameError:
149 unicode = None # unicode support not available
150
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000151try:
Fred Drakeba613c32005-02-10 18:33:30 +0000152 import datetime
153except ImportError:
154 datetime = None
155
156try:
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000157 _bool_is_builtin = False.__class__.__name__ == "bool"
158except NameError:
159 _bool_is_builtin = 0
160
Fredrik Lundhb9056332001-07-11 17:42:21 +0000161def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
162 # decode non-ascii string (if possible)
163 if unicode and encoding and is8bit(data):
164 data = unicode(data, encoding)
165 return data
166
Fredrik Lundh1538c232001-10-01 19:42:03 +0000167def escape(s, replace=string.replace):
168 s = replace(s, "&", "&")
169 s = replace(s, "<", "&lt;")
170 return replace(s, ">", "&gt;",)
171
Fredrik Lundhb9056332001-07-11 17:42:21 +0000172if unicode:
173 def _stringify(string):
174 # convert to 7-bit ascii if possible
175 try:
Fred Drake22c07062005-02-11 17:59:08 +0000176 return string.encode("ascii")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000177 except UnicodeError:
178 return string
179else:
180 def _stringify(string):
181 return string
182
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000183__version__ = "1.0.1"
184
185# xmlrpc integer limits
186MAXINT = 2L**31-1
187MININT = -2L**31
188
189# --------------------------------------------------------------------
190# Error constants (from Dan Libby's specification at
191# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
192
193# Ranges of errors
194PARSE_ERROR = -32700
195SERVER_ERROR = -32600
196APPLICATION_ERROR = -32500
197SYSTEM_ERROR = -32400
198TRANSPORT_ERROR = -32300
199
200# Specific errors
201NOT_WELLFORMED_ERROR = -32700
202UNSUPPORTED_ENCODING = -32701
203INVALID_ENCODING_CHAR = -32702
204INVALID_XMLRPC = -32600
205METHOD_NOT_FOUND = -32601
206INVALID_METHOD_PARAMS = -32602
207INTERNAL_ERROR = -32603
Fredrik Lundhb9056332001-07-11 17:42:21 +0000208
209# --------------------------------------------------------------------
210# Exceptions
211
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000212##
213# Base class for all kinds of client-side errors.
214
Fredrik Lundh78eedce2001-08-23 20:04:33 +0000215class Error(Exception):
Fred Drake1b410792001-09-04 18:55:03 +0000216 """Base class for client errors."""
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000217 def __str__(self):
218 return repr(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000219
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000220##
221# Indicates an HTTP-level protocol error. This is raised by the HTTP
222# transport layer, if the server returns an error code other than 200
223# (OK).
224#
225# @param url The target URL.
226# @param errcode The HTTP error code.
227# @param errmsg The HTTP error message.
228# @param headers The HTTP header dictionary.
229
Fredrik Lundhb9056332001-07-11 17:42:21 +0000230class ProtocolError(Error):
Fred Drake1b410792001-09-04 18:55:03 +0000231 """Indicates an HTTP protocol error."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000232 def __init__(self, url, errcode, errmsg, headers):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000233 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000234 self.url = url
235 self.errcode = errcode
236 self.errmsg = errmsg
237 self.headers = headers
238 def __repr__(self):
239 return (
240 "<ProtocolError for %s: %s %s>" %
241 (self.url, self.errcode, self.errmsg)
242 )
243
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000244##
245# Indicates a broken XML-RPC response package. This exception is
246# raised by the unmarshalling layer, if the XML-RPC response is
247# malformed.
248
Fredrik Lundhb9056332001-07-11 17:42:21 +0000249class ResponseError(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000250 """Indicates a broken response package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000251 pass
252
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000253##
254# Indicates an XML-RPC fault response package. This exception is
255# raised by the unmarshalling layer, if the XML-RPC response contains
256# a fault string. This exception can also used as a class, to
257# generate a fault XML-RPC message.
258#
259# @param faultCode The XML-RPC fault code.
260# @param faultString The XML-RPC fault string.
261
Fredrik Lundhb9056332001-07-11 17:42:21 +0000262class Fault(Error):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000263 """Indicates an XML-RPC fault package."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000264 def __init__(self, faultCode, faultString, **extra):
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000265 Error.__init__(self)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000266 self.faultCode = faultCode
267 self.faultString = faultString
268 def __repr__(self):
269 return (
270 "<Fault %s: %s>" %
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000271 (self.faultCode, repr(self.faultString))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000272 )
273
274# --------------------------------------------------------------------
275# Special values
276
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000277##
278# Wrapper for XML-RPC boolean values. Use the xmlrpclib.True and
279# xmlrpclib.False constants, or the xmlrpclib.boolean() function, to
280# generate boolean XML-RPC values.
281#
282# @param value A boolean value. Any true value is interpreted as True,
283# all other values are interpreted as False.
284
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000285boolean = Boolean = bool
286# to avoid breaking code which references xmlrpclib.{True,False}
287True, False = True, False
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000288
289##
290# Wrapper for XML-RPC DateTime values. This converts a time value to
291# the format used by XML-RPC.
292# <p>
293# The value can be given as a string in the format
294# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
295# time.localtime()), or an integer value (as returned by time.time()).
296# The wrapper uses time.localtime() to convert an integer to a time
297# tuple.
298#
299# @param value The time, given as an ISO 8601 string, a time
300# tuple, or a integer time value.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000301
Fredrik Lundhb9056332001-07-11 17:42:21 +0000302class DateTime:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000303 """DateTime wrapper for an ISO 8601 string or time tuple or
304 localtime integer value to generate 'dateTime.iso8601' XML-RPC
305 value.
306 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000307
308 def __init__(self, value=0):
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000309 if not isinstance(value, StringType):
Fred Drakeba613c32005-02-10 18:33:30 +0000310 if datetime and isinstance(value, datetime.datetime):
311 self.value = value.strftime("%Y%m%dT%H:%M:%S")
312 return
Skip Montanaro174dd222005-05-14 20:54:16 +0000313 if datetime and isinstance(value, datetime.date):
314 self.value = value.strftime("%Y%m%dT%H:%M:%S")
315 return
316 if datetime and isinstance(value, datetime.time):
317 today = datetime.datetime.now().strftime("%Y%m%d")
318 self.value = value.strftime(today+"T%H:%M:%S")
319 return
320 if not isinstance(value, (TupleType, time.struct_time)):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000321 if value == 0:
322 value = time.time()
323 value = time.localtime(value)
324 value = time.strftime("%Y%m%dT%H:%M:%S", value)
325 self.value = value
326
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000327 def __eq__(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000328 if isinstance(other, DateTime):
329 other = other.value
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000330 return self.value == other
331
332 def __ne__(self, other):
333 if isinstance(other, DateTime):
334 other = other.value
335 return self.value != other
Fredrik Lundhb9056332001-07-11 17:42:21 +0000336
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000337 ##
338 # Get date/time value.
339 #
340 # @return Date/time value, as an ISO 8601 string.
341
342 def __str__(self):
343 return self.value
344
Fredrik Lundhb9056332001-07-11 17:42:21 +0000345 def __repr__(self):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000346 return "<DateTime %s at %x>" % (repr(self.value), id(self))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000347
348 def decode(self, data):
Andrew M. Kuchlingbdb39012005-12-04 19:11:17 +0000349 data = str(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000350 self.value = string.strip(data)
351
352 def encode(self, out):
353 out.write("<value><dateTime.iso8601>")
354 out.write(self.value)
355 out.write("</dateTime.iso8601></value>\n")
356
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000357def _datetime(data):
358 # decode xml element contents into a DateTime structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000359 value = DateTime()
360 value.decode(data)
361 return value
362
Skip Montanaro174dd222005-05-14 20:54:16 +0000363def _datetime_type(data):
364 t = time.strptime(data, "%Y%m%dT%H:%M:%S")
365 return datetime.datetime(*tuple(t)[:6])
366
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000367##
368# Wrapper for binary data. This can be used to transport any kind
369# of binary data over XML-RPC, using BASE64 encoding.
370#
371# @param data An 8-bit string containing arbitrary data.
372
Skip Montanarobfcbfa72003-04-24 19:51:31 +0000373import base64
374try:
375 import cStringIO as StringIO
376except ImportError:
377 import StringIO
378
Fredrik Lundhb9056332001-07-11 17:42:21 +0000379class Binary:
Fred Drake1b410792001-09-04 18:55:03 +0000380 """Wrapper for binary data."""
Fredrik Lundhb9056332001-07-11 17:42:21 +0000381
382 def __init__(self, data=None):
383 self.data = data
384
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000385 ##
386 # Get buffer contents.
387 #
388 # @return Buffer contents, as an 8-bit string.
389
390 def __str__(self):
391 return self.data or ""
392
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000393 def __eq__(self, other):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000394 if isinstance(other, Binary):
395 other = other.data
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000396 return self.data == other
397
398 def __ne__(self, other):
399 if isinstance(other, Binary):
400 other = other.data
401 return self.data != other
Fredrik Lundhb9056332001-07-11 17:42:21 +0000402
403 def decode(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000404 self.data = base64.decodestring(data)
405
406 def encode(self, out):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000407 out.write("<value><base64>\n")
408 base64.encode(StringIO.StringIO(self.data), out)
409 out.write("</base64></value>\n")
410
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000411def _binary(data):
412 # decode xml element contents into a Binary structure
Fredrik Lundhb9056332001-07-11 17:42:21 +0000413 value = Binary()
414 value.decode(data)
415 return value
416
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000417WRAPPERS = (DateTime, Binary)
418if not _bool_is_builtin:
419 WRAPPERS = WRAPPERS + (Boolean,)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000420
421# --------------------------------------------------------------------
422# XML parsers
423
424try:
Fredrik Lundh7069c312004-10-13 06:48:37 +0000425 # optional xmlrpclib accelerator
Fredrik Lundhb9056332001-07-11 17:42:21 +0000426 import _xmlrpclib
427 FastParser = _xmlrpclib.Parser
428 FastUnmarshaller = _xmlrpclib.Unmarshaller
429except (AttributeError, ImportError):
430 FastParser = FastUnmarshaller = None
431
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000432try:
433 import _xmlrpclib
434 FastMarshaller = _xmlrpclib.Marshaller
435except (AttributeError, ImportError):
436 FastMarshaller = None
437
Fredrik Lundhb9056332001-07-11 17:42:21 +0000438#
439# the SGMLOP parser is about 15x faster than Python's builtin
440# XML parser. SGMLOP sources can be downloaded from:
441#
442# http://www.pythonware.com/products/xml/sgmlop.htm
443#
444
445try:
446 import sgmlop
447 if not hasattr(sgmlop, "XMLParser"):
448 raise ImportError
449except ImportError:
450 SgmlopParser = None # sgmlop accelerator not available
451else:
452 class SgmlopParser:
453 def __init__(self, target):
454
455 # setup callbacks
456 self.finish_starttag = target.start
457 self.finish_endtag = target.end
458 self.handle_data = target.data
459 self.handle_xml = target.xml
460
461 # activate parser
462 self.parser = sgmlop.XMLParser()
463 self.parser.register(self)
464 self.feed = self.parser.feed
465 self.entity = {
466 "amp": "&", "gt": ">", "lt": "<",
467 "apos": "'", "quot": '"'
468 }
469
470 def close(self):
471 try:
472 self.parser.close()
473 finally:
474 self.parser = self.feed = None # nuke circular reference
475
476 def handle_proc(self, tag, attr):
477 m = re.search("encoding\s*=\s*['\"]([^\"']+)[\"']", attr)
478 if m:
479 self.handle_xml(m.group(1), 1)
480
481 def handle_entityref(self, entity):
482 # <string> entity
483 try:
484 self.handle_data(self.entity[entity])
485 except KeyError:
486 self.handle_data("&%s;" % entity)
487
488try:
489 from xml.parsers import expat
Guido van Rossumb8551342001-10-02 18:33:11 +0000490 if not hasattr(expat, "ParserCreate"):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000491 raise ImportError
Fredrik Lundhb9056332001-07-11 17:42:21 +0000492except ImportError:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000493 ExpatParser = None # expat not available
Fredrik Lundhb9056332001-07-11 17:42:21 +0000494else:
495 class ExpatParser:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000496 # fast expat parser for Python 2.0 and later. this is about
497 # 50% slower than sgmlop, on roundtrip testing
Fredrik Lundhb9056332001-07-11 17:42:21 +0000498 def __init__(self, target):
499 self._parser = parser = expat.ParserCreate(None, None)
500 self._target = target
501 parser.StartElementHandler = target.start
502 parser.EndElementHandler = target.end
503 parser.CharacterDataHandler = target.data
504 encoding = None
505 if not parser.returns_unicode:
506 encoding = "utf-8"
507 target.xml(encoding, None)
508
509 def feed(self, data):
510 self._parser.Parse(data, 0)
511
512 def close(self):
513 self._parser.Parse("", 1) # end of data
514 del self._target, self._parser # get rid of circular references
515
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000516class SlowParser:
517 """Default XML parser (based on xmllib.XMLParser)."""
518 # this is about 10 times slower than sgmlop, on roundtrip
519 # testing.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000520 def __init__(self, target):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000521 import xmllib # lazy subclassing (!)
522 if xmllib.XMLParser not in SlowParser.__bases__:
523 SlowParser.__bases__ = (xmllib.XMLParser,)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000524 self.handle_xml = target.xml
525 self.unknown_starttag = target.start
526 self.handle_data = target.data
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000527 self.handle_cdata = target.data
Fredrik Lundhb9056332001-07-11 17:42:21 +0000528 self.unknown_endtag = target.end
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000529 try:
530 xmllib.XMLParser.__init__(self, accept_utf8=1)
531 except TypeError:
532 xmllib.XMLParser.__init__(self) # pre-2.0
Fredrik Lundhb9056332001-07-11 17:42:21 +0000533
534# --------------------------------------------------------------------
535# XML-RPC marshalling and unmarshalling code
536
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000537##
538# XML-RPC marshaller.
539#
540# @param encoding Default encoding for 8-bit strings. The default
541# value is None (interpreted as UTF-8).
542# @see dumps
543
Fredrik Lundhb9056332001-07-11 17:42:21 +0000544class Marshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000545 """Generate an XML-RPC params chunk from a Python data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000546
Fredrik Lundhc4c062f2001-09-10 19:45:02 +0000547 Create a Marshaller instance for each set of parameters, and use
548 the "dumps" method to convert your data (represented as a tuple)
549 to an XML-RPC params chunk. To write a fault response, pass a
550 Fault instance instead. You may prefer to use the "dumps" module
551 function for this purpose.
Fred Drake1b410792001-09-04 18:55:03 +0000552 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000553
554 # by the way, if you don't understand what's going on in here,
555 # that's perfectly ok.
556
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000557 def __init__(self, encoding=None, allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000558 self.memo = {}
559 self.data = None
560 self.encoding = encoding
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000561 self.allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +0000562
Fredrik Lundhb9056332001-07-11 17:42:21 +0000563 dispatch = {}
564
565 def dumps(self, values):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000566 out = []
567 write = out.append
568 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000569 if isinstance(values, Fault):
570 # fault instance
571 write("<fault>\n")
Martin v. Löwis541342f2003-07-12 07:53:04 +0000572 dump({'faultCode': values.faultCode,
573 'faultString': values.faultString},
574 write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000575 write("</fault>\n")
576 else:
577 # parameter block
Fredrik Lundhc266bb02001-08-23 20:13:08 +0000578 # FIXME: the xml-rpc specification allows us to leave out
579 # the entire <params> block if there are no parameters.
580 # however, changing this may break older code (including
581 # old versions of xmlrpclib.py), so this is better left as
582 # is for now. See @XMLRPC3 for more information. /F
Fredrik Lundhb9056332001-07-11 17:42:21 +0000583 write("<params>\n")
584 for v in values:
585 write("<param>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000586 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000587 write("</param>\n")
588 write("</params>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000589 result = string.join(out, "")
Fredrik Lundhb9056332001-07-11 17:42:21 +0000590 return result
591
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000592 def __dump(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000593 try:
594 f = self.dispatch[type(value)]
595 except KeyError:
596 raise TypeError, "cannot marshal %s objects" % type(value)
597 else:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000598 f(self, value, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000599
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000600 def dump_nil (self, value, write):
601 if not self.allow_none:
602 raise TypeError, "cannot marshal None unless allow_none is enabled"
603 write("<value><nil/></value>")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000604 dispatch[NoneType] = dump_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000605
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000606 def dump_int(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000607 # in case ints are > 32 bits
608 if value > MAXINT or value < MININT:
609 raise OverflowError, "int exceeds XML-RPC limits"
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000610 write("<value><int>")
611 write(str(value))
612 write("</int></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000613 dispatch[IntType] = dump_int
Fredrik Lundhb9056332001-07-11 17:42:21 +0000614
Skip Montanaro9a7c96a2003-01-22 18:17:25 +0000615 if _bool_is_builtin:
616 def dump_bool(self, value, write):
617 write("<value><boolean>")
618 write(value and "1" or "0")
619 write("</boolean></value>\n")
620 dispatch[bool] = dump_bool
621
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000622 def dump_long(self, value, write):
Skip Montanaro5449e082001-10-17 22:53:33 +0000623 if value > MAXINT or value < MININT:
624 raise OverflowError, "long int exceeds XML-RPC limits"
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000625 write("<value><int>")
626 write(str(int(value)))
627 write("</int></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000628 dispatch[LongType] = dump_long
Skip Montanaro5e9c71b2001-10-10 15:56:34 +0000629
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000630 def dump_double(self, value, write):
631 write("<value><double>")
632 write(repr(value))
633 write("</double></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000634 dispatch[FloatType] = dump_double
Fredrik Lundhb9056332001-07-11 17:42:21 +0000635
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000636 def dump_string(self, value, write, escape=escape):
637 write("<value><string>")
638 write(escape(value))
639 write("</string></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000640 dispatch[StringType] = dump_string
Fredrik Lundhb9056332001-07-11 17:42:21 +0000641
642 if unicode:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000643 def dump_unicode(self, value, write, escape=escape):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000644 value = value.encode(self.encoding)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000645 write("<value><string>")
646 write(escape(value))
647 write("</string></value>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000648 dispatch[UnicodeType] = dump_unicode
Fredrik Lundhb9056332001-07-11 17:42:21 +0000649
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000650 def dump_array(self, value, write):
651 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000652 if i in self.memo:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000653 raise TypeError, "cannot marshal recursive sequences"
654 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000655 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000656 write("<value><array><data>\n")
657 for v in value:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000658 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000659 write("</data></array></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000660 del self.memo[i]
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000661 dispatch[TupleType] = dump_array
662 dispatch[ListType] = dump_array
Fredrik Lundhb9056332001-07-11 17:42:21 +0000663
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000664 def dump_struct(self, value, write, escape=escape):
665 i = id(value)
Guido van Rossume2b70bc2006-08-18 22:13:04 +0000666 if i in self.memo:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000667 raise TypeError, "cannot marshal recursive dictionaries"
668 self.memo[i] = None
Fredrik Lundh1538c232001-10-01 19:42:03 +0000669 dump = self.__dump
Fredrik Lundhb9056332001-07-11 17:42:21 +0000670 write("<value><struct>\n")
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000671 for k, v in value.items():
Fredrik Lundhb9056332001-07-11 17:42:21 +0000672 write("<member>\n")
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000673 if type(k) is not StringType:
674 if unicode and type(k) is UnicodeType:
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000675 k = k.encode(self.encoding)
676 else:
677 raise TypeError, "dictionary key must be string"
Fredrik Lundh1538c232001-10-01 19:42:03 +0000678 write("<name>%s</name>\n" % escape(k))
Andrew M. Kuchling5962f452004-06-05 12:35:58 +0000679 dump(v, write)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000680 write("</member>\n")
681 write("</struct></value>\n")
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000682 del self.memo[i]
Raymond Hettingerfe59dc12005-02-07 15:28:45 +0000683 dispatch[DictType] = dump_struct
Fredrik Lundhb9056332001-07-11 17:42:21 +0000684
Fred Drakeba613c32005-02-10 18:33:30 +0000685 if datetime:
686 def dump_datetime(self, value, write):
687 write("<value><dateTime.iso8601>")
688 write(value.strftime("%Y%m%dT%H:%M:%S"))
689 write("</dateTime.iso8601></value>\n")
690 dispatch[datetime.datetime] = dump_datetime
691
Skip Montanaro174dd222005-05-14 20:54:16 +0000692 def dump_date(self, value, write):
693 write("<value><dateTime.iso8601>")
694 write(value.strftime("%Y%m%dT00:00:00"))
695 write("</dateTime.iso8601></value>\n")
696 dispatch[datetime.date] = dump_date
697
698 def dump_time(self, value, write):
699 write("<value><dateTime.iso8601>")
700 write(datetime.datetime.now().date().strftime("%Y%m%dT"))
701 write(value.strftime("%H:%M:%S"))
702 write("</dateTime.iso8601></value>\n")
703 dispatch[datetime.time] = dump_time
704
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000705 def dump_instance(self, value, write):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000706 # check for special wrappers
707 if value.__class__ in WRAPPERS:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000708 self.write = write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000709 value.encode(self)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000710 del self.write
Fredrik Lundhb9056332001-07-11 17:42:21 +0000711 else:
712 # store instance attributes as a struct (really?)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000713 self.dump_struct(value.__dict__, write)
Guido van Rossume4dea982006-04-21 13:45:00 +0000714 dispatch[DateTime] = dump_instance
715 dispatch[Binary] = dump_instance
Fredrik Lundhb9056332001-07-11 17:42:21 +0000716
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000717##
718# XML-RPC unmarshaller.
719#
720# @see loads
721
Fredrik Lundhb9056332001-07-11 17:42:21 +0000722class Unmarshaller:
Fred Drake1b410792001-09-04 18:55:03 +0000723 """Unmarshal an XML-RPC response, based on incoming XML event
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000724 messages (start, data, end). Call close() to get the resulting
Fred Drake1b410792001-09-04 18:55:03 +0000725 data structure.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000726
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000727 Note that this reader is fairly tolerant, and gladly accepts bogus
728 XML-RPC data without complaining (but not bogus XML).
Fred Drake1b410792001-09-04 18:55:03 +0000729 """
Fredrik Lundhb9056332001-07-11 17:42:21 +0000730
731 # and again, if you don't understand what's going on in here,
732 # that's perfectly ok.
733
Skip Montanaro174dd222005-05-14 20:54:16 +0000734 def __init__(self, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000735 self._type = None
736 self._stack = []
737 self._marks = []
738 self._data = []
739 self._methodname = None
740 self._encoding = "utf-8"
741 self.append = self._stack.append
Skip Montanaro174dd222005-05-14 20:54:16 +0000742 self._use_datetime = use_datetime
743 if use_datetime and not datetime:
744 raise ValueError, "the datetime module is not available"
Fredrik Lundhb9056332001-07-11 17:42:21 +0000745
746 def close(self):
747 # return response tuple and target method
748 if self._type is None or self._marks:
749 raise ResponseError()
750 if self._type == "fault":
Guido van Rossum68468eb2003-02-27 20:14:51 +0000751 raise Fault(**self._stack[0])
Fredrik Lundhb9056332001-07-11 17:42:21 +0000752 return tuple(self._stack)
753
754 def getmethodname(self):
755 return self._methodname
756
757 #
758 # event handlers
759
760 def xml(self, encoding, standalone):
761 self._encoding = encoding
762 # FIXME: assert standalone == 1 ???
763
764 def start(self, tag, attrs):
765 # prepare to handle this element
766 if tag == "array" or tag == "struct":
767 self._marks.append(len(self._stack))
768 self._data = []
769 self._value = (tag == "value")
770
771 def data(self, text):
772 self._data.append(text)
773
Fredrik Lundh1538c232001-10-01 19:42:03 +0000774 def end(self, tag, join=string.join):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000775 # call the appropriate end tag handler
776 try:
777 f = self.dispatch[tag]
778 except KeyError:
779 pass # unknown tag ?
780 else:
Fredrik Lundh1538c232001-10-01 19:42:03 +0000781 return f(self, join(self._data, ""))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000782
783 #
784 # accelerator support
785
786 def end_dispatch(self, tag, data):
787 # dispatch data
788 try:
789 f = self.dispatch[tag]
790 except KeyError:
791 pass # unknown tag ?
792 else:
793 return f(self, data)
794
795 #
796 # element decoders
797
798 dispatch = {}
799
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +0000800 def end_nil (self, data):
801 self.append(None)
802 self._value = 0
803 dispatch["nil"] = end_nil
Tim Petersc2659cf2003-05-12 20:19:37 +0000804
Fredrik Lundh1538c232001-10-01 19:42:03 +0000805 def end_boolean(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000806 if data == "0":
807 self.append(False)
808 elif data == "1":
809 self.append(True)
810 else:
811 raise TypeError, "bad boolean value"
812 self._value = 0
813 dispatch["boolean"] = end_boolean
814
Fredrik Lundh1538c232001-10-01 19:42:03 +0000815 def end_int(self, data):
816 self.append(int(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000817 self._value = 0
818 dispatch["i4"] = end_int
819 dispatch["int"] = end_int
820
Fredrik Lundh1538c232001-10-01 19:42:03 +0000821 def end_double(self, data):
822 self.append(float(data))
Fredrik Lundhb9056332001-07-11 17:42:21 +0000823 self._value = 0
824 dispatch["double"] = end_double
825
Fredrik Lundh1538c232001-10-01 19:42:03 +0000826 def end_string(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000827 if self._encoding:
828 data = _decode(data, self._encoding)
829 self.append(_stringify(data))
830 self._value = 0
831 dispatch["string"] = end_string
832 dispatch["name"] = end_string # struct keys are always strings
833
834 def end_array(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000835 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000836 # map arrays to Python lists
837 self._stack[mark:] = [self._stack[mark:]]
838 self._value = 0
839 dispatch["array"] = end_array
840
841 def end_struct(self, data):
Raymond Hettinger46ac8eb2002-06-30 03:39:14 +0000842 mark = self._marks.pop()
Fredrik Lundhb9056332001-07-11 17:42:21 +0000843 # map structs to Python dictionaries
844 dict = {}
845 items = self._stack[mark:]
846 for i in range(0, len(items), 2):
847 dict[_stringify(items[i])] = items[i+1]
848 self._stack[mark:] = [dict]
849 self._value = 0
850 dispatch["struct"] = end_struct
851
Fredrik Lundh1538c232001-10-01 19:42:03 +0000852 def end_base64(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000853 value = Binary()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000854 value.decode(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000855 self.append(value)
856 self._value = 0
857 dispatch["base64"] = end_base64
858
Fredrik Lundh1538c232001-10-01 19:42:03 +0000859 def end_dateTime(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000860 value = DateTime()
Fredrik Lundh1538c232001-10-01 19:42:03 +0000861 value.decode(data)
Skip Montanaro174dd222005-05-14 20:54:16 +0000862 if self._use_datetime:
863 value = _datetime_type(data)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000864 self.append(value)
865 dispatch["dateTime.iso8601"] = end_dateTime
866
867 def end_value(self, data):
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000868 # if we stumble upon a value element with no internal
Fredrik Lundhb9056332001-07-11 17:42:21 +0000869 # elements, treat it as a string element
870 if self._value:
871 self.end_string(data)
872 dispatch["value"] = end_value
873
874 def end_params(self, data):
875 self._type = "params"
876 dispatch["params"] = end_params
877
878 def end_fault(self, data):
879 self._type = "fault"
880 dispatch["fault"] = end_fault
881
Fredrik Lundh1538c232001-10-01 19:42:03 +0000882 def end_methodName(self, data):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000883 if self._encoding:
884 data = _decode(data, self._encoding)
885 self._methodname = data
886 self._type = "methodName" # no params
887 dispatch["methodName"] = end_methodName
888
Martin v. Löwis45394c22003-10-31 13:49:36 +0000889## Multicall support
890#
Fredrik Lundhb9056332001-07-11 17:42:21 +0000891
Martin v. Löwis45394c22003-10-31 13:49:36 +0000892class _MultiCallMethod:
893 # some lesser magic to store calls made to a MultiCall object
894 # for batch execution
895 def __init__(self, call_list, name):
896 self.__call_list = call_list
897 self.__name = name
898 def __getattr__(self, name):
899 return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
900 def __call__(self, *args):
901 self.__call_list.append((self.__name, args))
902
Martin v. Löwis12237b32004-08-22 16:04:50 +0000903class MultiCallIterator:
Martin v. Löwis45394c22003-10-31 13:49:36 +0000904 """Iterates over the results of a multicall. Exceptions are
905 thrown in response to xmlrpc faults."""
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000906
Martin v. Löwis12237b32004-08-22 16:04:50 +0000907 def __init__(self, results):
908 self.results = results
909
910 def __getitem__(self, i):
911 item = self.results[i]
912 if type(item) == type({}):
913 raise Fault(item['faultCode'], item['faultString'])
914 elif type(item) == type([]):
915 return item[0]
Martin v. Löwis45394c22003-10-31 13:49:36 +0000916 else:
917 raise ValueError,\
918 "unexpected type in multicall result"
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000919
Martin v. Löwis45394c22003-10-31 13:49:36 +0000920class MultiCall:
921 """server -> a object used to boxcar method calls
922
923 server should be a ServerProxy object.
924
925 Methods can be added to the MultiCall using normal
926 method call syntax e.g.:
927
928 multicall = MultiCall(server_proxy)
929 multicall.add(2,3)
930 multicall.get_address("Guido")
931
932 To execute the multicall, call the MultiCall object e.g.:
933
934 add_result, address = multicall()
935 """
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000936
Martin v. Löwis45394c22003-10-31 13:49:36 +0000937 def __init__(self, server):
938 self.__server = server
939 self.__call_list = []
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000940
Martin v. Löwis45394c22003-10-31 13:49:36 +0000941 def __repr__(self):
942 return "<MultiCall at %x>" % id(self)
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000943
Martin v. Löwis45394c22003-10-31 13:49:36 +0000944 __str__ = __repr__
945
946 def __getattr__(self, name):
947 return _MultiCallMethod(self.__call_list, name)
948
949 def __call__(self):
950 marshalled_list = []
951 for name, args in self.__call_list:
952 marshalled_list.append({'methodName' : name, 'params' : args})
953
954 return MultiCallIterator(self.__server.system.multicall(marshalled_list))
Raymond Hettingercc523fc2003-11-02 09:47:05 +0000955
Fredrik Lundhb9056332001-07-11 17:42:21 +0000956# --------------------------------------------------------------------
957# convenience functions
958
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000959##
960# Create a parser object, and connect it to an unmarshalling instance.
961# This function picks the fastest available XML parser.
962#
963# return A (parser, unmarshaller) tuple.
964
Skip Montanaro174dd222005-05-14 20:54:16 +0000965def getparser(use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +0000966 """getparser() -> parser, unmarshaller
967
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +0000968 Create an instance of the fastest available parser, and attach it
969 to an unmarshalling object. Return both objects.
Fredrik Lundhb9056332001-07-11 17:42:21 +0000970 """
Skip Montanaro174dd222005-05-14 20:54:16 +0000971 if use_datetime and not datetime:
972 raise ValueError, "the datetime module is not available"
Fredrik Lundhb9056332001-07-11 17:42:21 +0000973 if FastParser and FastUnmarshaller:
Skip Montanaro174dd222005-05-14 20:54:16 +0000974 if use_datetime:
975 mkdatetime = _datetime_type
976 else:
977 mkdatetime = _datetime
978 target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000979 parser = FastParser(target)
980 else:
Skip Montanaro174dd222005-05-14 20:54:16 +0000981 target = Unmarshaller(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +0000982 if FastParser:
983 parser = FastParser(target)
984 elif SgmlopParser:
985 parser = SgmlopParser(target)
986 elif ExpatParser:
987 parser = ExpatParser(target)
988 else:
989 parser = SlowParser(target)
990 return parser, target
991
Fredrik Lundh3d9addd2002-06-27 21:36:21 +0000992##
993# Convert a Python tuple or a Fault instance to an XML-RPC packet.
994#
995# @def dumps(params, **options)
996# @param params A tuple or Fault instance.
997# @keyparam methodname If given, create a methodCall request for
998# this method name.
999# @keyparam methodresponse If given, create a methodResponse packet.
1000# If used with a tuple, the tuple must be a singleton (that is,
1001# it must contain exactly one element).
1002# @keyparam encoding The packet encoding.
1003# @return A string containing marshalled data.
1004
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001005def dumps(params, methodname=None, methodresponse=None, encoding=None,
1006 allow_none=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001007 """data [,options] -> marshalled data
1008
1009 Convert an argument tuple or a Fault instance to an XML-RPC
1010 request (or response, if the methodresponse option is used).
1011
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +00001012 In addition to the data object, the following options can be given
1013 as keyword arguments:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001014
1015 methodname: the method name for a methodCall packet
1016
1017 methodresponse: true to create a methodResponse packet.
1018 If this option is used with a tuple, the tuple must be
1019 a singleton (i.e. it can contain only one element).
1020
1021 encoding: the packet encoding (default is UTF-8)
1022
1023 All 8-bit strings in the data structure are assumed to use the
1024 packet encoding. Unicode strings are automatically converted,
Fredrik Lundhb0e8e9b2001-09-10 21:45:42 +00001025 where necessary.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001026 """
1027
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001028 assert isinstance(params, TupleType) or isinstance(params, Fault),\
Fredrik Lundhb9056332001-07-11 17:42:21 +00001029 "argument must be tuple or Fault instance"
1030
1031 if isinstance(params, Fault):
1032 methodresponse = 1
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001033 elif methodresponse and isinstance(params, TupleType):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001034 assert len(params) == 1, "response tuple must be a singleton"
1035
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001036 if not encoding:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001037 encoding = "utf-8"
1038
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001039 if FastMarshaller:
1040 m = FastMarshaller(encoding)
1041 else:
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001042 m = Marshaller(encoding, allow_none)
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001043
Fredrik Lundhb9056332001-07-11 17:42:21 +00001044 data = m.dumps(params)
1045
1046 if encoding != "utf-8":
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001047 xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001048 else:
1049 xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
1050
1051 # standard XML-RPC wrappings
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001052 if methodname:
Fredrik Lundhb9056332001-07-11 17:42:21 +00001053 # a method call
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001054 if not isinstance(methodname, StringType):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001055 methodname = methodname.encode(encoding)
1056 data = (
1057 xmlheader,
1058 "<methodCall>\n"
1059 "<methodName>", methodname, "</methodName>\n",
1060 data,
1061 "</methodCall>\n"
1062 )
1063 elif methodresponse:
1064 # a method response, or a fault structure
1065 data = (
1066 xmlheader,
1067 "<methodResponse>\n",
1068 data,
1069 "</methodResponse>\n"
1070 )
1071 else:
1072 return data # return as is
1073 return string.join(data, "")
1074
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001075##
1076# Convert an XML-RPC packet to a Python object. If the XML-RPC packet
1077# represents a fault condition, this function raises a Fault exception.
1078#
1079# @param data An XML-RPC packet, given as an 8-bit string.
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +00001080# @return A tuple containing the unpacked data, and the method name
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001081# (None if not present).
1082# @see Fault
1083
Skip Montanaro174dd222005-05-14 20:54:16 +00001084def loads(data, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001085 """data -> unmarshalled data, method name
1086
1087 Convert an XML-RPC packet to unmarshalled data plus a method
1088 name (None if not present).
1089
1090 If the XML-RPC packet represents a fault condition, this function
1091 raises a Fault exception.
1092 """
Skip Montanaro174dd222005-05-14 20:54:16 +00001093 p, u = getparser(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001094 p.feed(data)
1095 p.close()
1096 return u.close(), u.getmethodname()
1097
1098
1099# --------------------------------------------------------------------
1100# request dispatcher
1101
1102class _Method:
1103 # some magic to bind an XML-RPC method to an RPC server.
1104 # supports "nested" methods (e.g. examples.getStateName)
1105 def __init__(self, send, name):
1106 self.__send = send
1107 self.__name = name
1108 def __getattr__(self, name):
1109 return _Method(self.__send, "%s.%s" % (self.__name, name))
1110 def __call__(self, *args):
1111 return self.__send(self.__name, args)
1112
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001113##
1114# Standard transport class for XML-RPC over HTTP.
1115# <p>
1116# You can create custom transports by subclassing this method, and
1117# overriding selected methods.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001118
1119class Transport:
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001120 """Handles an HTTP transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001121
1122 # client identifier (may be overridden)
1123 user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
1124
Skip Montanaro174dd222005-05-14 20:54:16 +00001125 def __init__(self, use_datetime=0):
1126 self._use_datetime = use_datetime
1127
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001128 ##
1129 # Send a complete request, and parse the response.
1130 #
1131 # @param host Target host.
1132 # @param handler Target PRC handler.
1133 # @param request_body XML-RPC request body.
1134 # @param verbose Debugging flag.
1135 # @return Parsed response.
1136
Fredrik Lundhb9056332001-07-11 17:42:21 +00001137 def request(self, host, handler, request_body, verbose=0):
1138 # issue XML-RPC request
1139
1140 h = self.make_connection(host)
1141 if verbose:
1142 h.set_debuglevel(1)
1143
1144 self.send_request(h, handler, request_body)
1145 self.send_host(h, host)
1146 self.send_user_agent(h)
1147 self.send_content(h, request_body)
1148
1149 errcode, errmsg, headers = h.getreply()
1150
1151 if errcode != 200:
1152 raise ProtocolError(
1153 host + handler,
1154 errcode, errmsg,
1155 headers
1156 )
1157
1158 self.verbose = verbose
1159
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001160 try:
1161 sock = h._conn.sock
1162 except AttributeError:
1163 sock = None
1164
1165 return self._parse_response(h.getfile(), sock)
1166
1167 ##
1168 # Create parser.
1169 #
1170 # @return A 2-tuple containing a parser and a unmarshaller.
Fredrik Lundhb9056332001-07-11 17:42:21 +00001171
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001172 def getparser(self):
1173 # get parser and unmarshaller
Skip Montanaro174dd222005-05-14 20:54:16 +00001174 return getparser(use_datetime=self._use_datetime)
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001175
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001176 ##
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001177 # Get authorization info from host parameter
1178 # Host may be a string, or a (host, x509-dict) tuple; if a string,
1179 # it is checked for a "user:pw@host" format, and a "Basic
1180 # Authentication" header is added if appropriate.
1181 #
1182 # @param host Host descriptor (URL or (URL, x509 info) tuple).
1183 # @return A 3-tuple containing (actual host, extra headers,
1184 # x509 info). The header and x509 fields may be None.
1185
1186 def get_host_info(self, host):
1187
1188 x509 = {}
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001189 if isinstance(host, TupleType):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001190 host, x509 = host
1191
1192 import urllib
1193 auth, host = urllib.splituser(host)
1194
1195 if auth:
1196 import base64
Fredrik Lundh768c98b2002-11-01 17:14:16 +00001197 auth = base64.encodestring(urllib.unquote(auth))
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001198 auth = string.join(string.split(auth), "") # get rid of whitespace
1199 extra_headers = [
1200 ("Authorization", "Basic " + auth)
1201 ]
1202 else:
1203 extra_headers = None
1204
1205 return host, extra_headers, x509
1206
1207 ##
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001208 # Connect to server.
1209 #
1210 # @param host Target host.
1211 # @return A connection handle.
1212
Fredrik Lundhb9056332001-07-11 17:42:21 +00001213 def make_connection(self, host):
1214 # create a HTTP connection object from a host descriptor
1215 import httplib
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001216 host, extra_headers, x509 = self.get_host_info(host)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001217 return httplib.HTTP(host)
1218
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001219 ##
1220 # Send request header.
1221 #
1222 # @param connection Connection handle.
1223 # @param handler Target RPC handler.
1224 # @param request_body XML-RPC body.
1225
Fredrik Lundhb9056332001-07-11 17:42:21 +00001226 def send_request(self, connection, handler, request_body):
1227 connection.putrequest("POST", handler)
1228
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001229 ##
1230 # Send host name.
1231 #
1232 # @param connection Connection handle.
1233 # @param host Host name.
1234
Fredrik Lundhb9056332001-07-11 17:42:21 +00001235 def send_host(self, connection, host):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001236 host, extra_headers, x509 = self.get_host_info(host)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001237 connection.putheader("Host", host)
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001238 if extra_headers:
Raymond Hettingerfe59dc12005-02-07 15:28:45 +00001239 if isinstance(extra_headers, DictType):
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001240 extra_headers = extra_headers.items()
1241 for key, value in extra_headers:
1242 connection.putheader(key, value)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001243
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001244 ##
1245 # Send user-agent identifier.
1246 #
1247 # @param connection Connection handle.
1248
Fredrik Lundhb9056332001-07-11 17:42:21 +00001249 def send_user_agent(self, connection):
1250 connection.putheader("User-Agent", self.user_agent)
1251
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001252 ##
1253 # Send request body.
1254 #
1255 # @param connection Connection handle.
1256 # @param request_body XML-RPC request body.
1257
Fredrik Lundhb9056332001-07-11 17:42:21 +00001258 def send_content(self, connection, request_body):
1259 connection.putheader("Content-Type", "text/xml")
1260 connection.putheader("Content-Length", str(len(request_body)))
1261 connection.endheaders()
1262 if request_body:
1263 connection.send(request_body)
1264
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001265 ##
1266 # Parse response.
1267 #
1268 # @param file Stream.
1269 # @return Response tuple and target method.
1270
1271 def parse_response(self, file):
1272 # compatibility interface
1273 return self._parse_response(file, None)
1274
1275 ##
1276 # Parse response (alternate interface). This is similar to the
1277 # parse_response method, but also provides direct access to the
1278 # underlying socket object (where available).
1279 #
1280 # @param file Stream.
1281 # @param sock Socket handle (or None, if the socket object
1282 # could not be accessed).
1283 # @return Response tuple and target method.
1284
1285 def _parse_response(self, file, sock):
1286 # read response from input file/socket, and parse it
Fredrik Lundhb9056332001-07-11 17:42:21 +00001287
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001288 p, u = self.getparser()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001289
1290 while 1:
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001291 if sock:
1292 response = sock.recv(1024)
1293 else:
1294 response = file.read(1024)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001295 if not response:
1296 break
1297 if self.verbose:
1298 print "body:", repr(response)
1299 p.feed(response)
1300
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001301 file.close()
Fredrik Lundhb9056332001-07-11 17:42:21 +00001302 p.close()
1303
1304 return u.close()
1305
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001306##
1307# Standard transport class for XML-RPC over HTTPS.
1308
Fredrik Lundhb9056332001-07-11 17:42:21 +00001309class SafeTransport(Transport):
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001310 """Handles an HTTPS transaction to an XML-RPC server."""
Fredrik Lundhb9056332001-07-11 17:42:21 +00001311
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001312 # FIXME: mostly untested
1313
Fredrik Lundhb9056332001-07-11 17:42:21 +00001314 def make_connection(self, host):
1315 # create a HTTPS connection object from a host descriptor
1316 # host may be a string, or a (host, x509-dict) tuple
1317 import httplib
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001318 host, extra_headers, x509 = self.get_host_info(host)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001319 try:
1320 HTTPS = httplib.HTTPS
1321 except AttributeError:
Fredrik Lundh1303c7c2002-10-22 18:23:00 +00001322 raise NotImplementedError(
1323 "your version of httplib doesn't support HTTPS"
1324 )
Fredrik Lundhb9056332001-07-11 17:42:21 +00001325 else:
Guido van Rossum68468eb2003-02-27 20:14:51 +00001326 return HTTPS(host, None, **(x509 or {}))
Fredrik Lundhb9056332001-07-11 17:42:21 +00001327
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001328##
1329# Standard server proxy. This class establishes a virtual connection
1330# to an XML-RPC server.
1331# <p>
1332# This class is available as ServerProxy and Server. New code should
1333# use ServerProxy, to avoid confusion.
1334#
1335# @def ServerProxy(uri, **options)
1336# @param uri The connection point on the server.
1337# @keyparam transport A transport factory, compatible with the
1338# standard transport class.
1339# @keyparam encoding The default encoding used for 8-bit strings
1340# (default is UTF-8).
1341# @keyparam verbose Use a true value to enable debugging output.
1342# (printed to standard output).
1343# @see Transport
1344
Fredrik Lundhb9056332001-07-11 17:42:21 +00001345class ServerProxy:
1346 """uri [,options] -> a logical connection to an XML-RPC server
1347
1348 uri is the connection point on the server, given as
1349 scheme://host/target.
1350
1351 The standard implementation always supports the "http" scheme. If
1352 SSL socket support is available (Python 2.0), it also supports
1353 "https".
1354
1355 If the target part and the slash preceding it are both omitted,
1356 "/RPC2" is assumed.
1357
1358 The following options can be given as keyword arguments:
1359
1360 transport: a transport factory
1361 encoding: the request encoding (default is UTF-8)
1362
1363 All 8-bit strings passed to the server proxy are assumed to use
1364 the given encoding.
1365 """
1366
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001367 def __init__(self, uri, transport=None, encoding=None, verbose=0,
Skip Montanaro174dd222005-05-14 20:54:16 +00001368 allow_none=0, use_datetime=0):
Fredrik Lundhb9056332001-07-11 17:42:21 +00001369 # establish a "logical" server connection
1370
1371 # get the url
Fredrik Lundhc4c062f2001-09-10 19:45:02 +00001372 import urllib
Fredrik Lundhb9056332001-07-11 17:42:21 +00001373 type, uri = urllib.splittype(uri)
1374 if type not in ("http", "https"):
1375 raise IOError, "unsupported XML-RPC protocol"
1376 self.__host, self.__handler = urllib.splithost(uri)
1377 if not self.__handler:
1378 self.__handler = "/RPC2"
1379
1380 if transport is None:
1381 if type == "https":
Skip Montanaro174dd222005-05-14 20:54:16 +00001382 transport = SafeTransport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001383 else:
Skip Montanaro174dd222005-05-14 20:54:16 +00001384 transport = Transport(use_datetime=use_datetime)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001385 self.__transport = transport
1386
1387 self.__encoding = encoding
1388 self.__verbose = verbose
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001389 self.__allow_none = allow_none
Tim Petersc2659cf2003-05-12 20:19:37 +00001390
Fredrik Lundhb9056332001-07-11 17:42:21 +00001391 def __request(self, methodname, params):
1392 # call a method on the remote server
1393
Andrew M. Kuchlinga4c2b742003-04-25 00:26:51 +00001394 request = dumps(params, methodname, encoding=self.__encoding,
1395 allow_none=self.__allow_none)
Fredrik Lundhb9056332001-07-11 17:42:21 +00001396
1397 response = self.__transport.request(
1398 self.__host,
1399 self.__handler,
1400 request,
1401 verbose=self.__verbose
1402 )
1403
1404 if len(response) == 1:
1405 response = response[0]
1406
1407 return response
1408
1409 def __repr__(self):
1410 return (
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001411 "<ServerProxy for %s%s>" %
Fredrik Lundhb9056332001-07-11 17:42:21 +00001412 (self.__host, self.__handler)
1413 )
1414
1415 __str__ = __repr__
Raymond Hettingercc523fc2003-11-02 09:47:05 +00001416
Fredrik Lundhb9056332001-07-11 17:42:21 +00001417 def __getattr__(self, name):
1418 # magic method dispatcher
1419 return _Method(self.__request, name)
1420
1421 # note: to call a remote object with an non-standard name, use
1422 # result getattr(server, "strange-python-name")(args)
1423
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001424# compatibility
Fredrik Lundh3d9addd2002-06-27 21:36:21 +00001425
Fredrik Lundhb9056332001-07-11 17:42:21 +00001426Server = ServerProxy
1427
1428# --------------------------------------------------------------------
1429# test code
1430
1431if __name__ == "__main__":
1432
1433 # simple test program (from the XML-RPC specification)
1434
Fredrik Lundh78eedce2001-08-23 20:04:33 +00001435 # server = ServerProxy("http://localhost:8000") # local server
Martin v. Löwis12237b32004-08-22 16:04:50 +00001436 server = ServerProxy("http://time.xmlrpc.com/RPC2")
Fredrik Lundhb9056332001-07-11 17:42:21 +00001437
1438 print server
1439
1440 try:
Martin v. Löwis12237b32004-08-22 16:04:50 +00001441 print server.currentTime.getCurrentTime()
1442 except Error, v:
1443 print "ERROR", v
1444
1445 multi = MultiCall(server)
1446 multi.currentTime.getCurrentTime()
1447 multi.currentTime.getCurrentTime()
1448 try:
1449 for response in multi():
1450 print response
Fredrik Lundhb9056332001-07-11 17:42:21 +00001451 except Error, v:
1452 print "ERROR", v