10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# XML-RPC CLIENT LIBRARY
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# $Id$
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# an XML-RPC client interface for Python.
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# the marshalling and response parser code can also be used to
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# implement XML-RPC servers.
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Notes:
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# this version is designed to work with Python 2.1 or newer.
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# History:
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-01-14 fl  Created
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-01-15 fl  Changed dateTime to use localtime
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-01-16 fl  Added Binary/base64 element, default to RPC2 service
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-01-19 fl  Fixed array data element (from Skip Montanaro)
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-01-21 fl  Fixed dateTime constructor, etc.
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-02-02 fl  Added fault handling, handle empty sequences, etc.
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-02-10 fl  Fixed problem with empty responses (from Skip Montanaro)
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 1999-06-20 fl  Speed improvements, pluggable parsers/transports (0.9.8)
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2000-11-28 fl  Changed boolean to check the truth value of its argument
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-02-24 fl  Added encoding/Unicode/SafeTransport patches
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-02-26 fl  Added compare support to wrappers (0.9.9/1.0b1)
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-03-28 fl  Make sure response tuple is a singleton
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-03-29 fl  Don't require empty params element (from Nicholas Riley)
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-06-10 fl  Folded in _xmlrpclib accelerator support (1.0b2)
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-08-20 fl  Base xmlrpclib.Error on built-in Exception (from Paul Prescod)
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-09-03 fl  Allow Transport subclass to override getparser
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-09-10 fl  Lazy import of urllib, cgi, xmllib (20x import speedup)
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-10-01 fl  Remove containers from memo cache when done with them
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-10-01 fl  Use faster escape method (80% dumps speedup)
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-10-02 fl  More dumps microtuning
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-10-04 fl  Make sure import expat gets a parser (from Guido van Rossum)
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-10-10 sm  Allow long ints to be passed as ints if they don't overflow
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-10-17 sm  Test for int and long overflow (allows use on 64-bit systems)
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2001-11-12 fl  Use repr() to marshal doubles (from Paul Felix)
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2002-03-17 fl  Avoid buffered read when possible (from James Rucker)
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2002-04-07 fl  Added pythondoc comments
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2002-04-16 fl  Added __str__ methods to datetime/binary wrappers
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2002-05-15 fl  Added error constants (from Andrew Kuchling)
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2002-06-27 fl  Merged with Python CVS version
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2002-10-22 fl  Added basic authentication (based on code from Phillip Eby)
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-01-22 sm  Add support for the bool type
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-02-27 gvr Remove apply calls
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-04-24 sm  Use cStringIO if available
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-04-25 ak  Add support for nil
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-06-15 gn  Add support for time.struct_time
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-07-12 gp  Correct marshalling of Faults
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2003-10-31 mvl Add multicall support
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# 2004-08-20 mvl Bump minimum supported Python version to 2.1
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Copyright (c) 1999-2002 by Secret Labs AB.
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Copyright (c) 1999-2002 by Fredrik Lundh.
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# info@pythonware.com
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# http://www.pythonware.com
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# The XML-RPC client interface is
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Copyright (c) 1999-2002 by Secret Labs AB
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Copyright (c) 1999-2002 by Fredrik Lundh
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# By obtaining, using, and/or copying this software and/or its
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# associated documentation, you agree that you have read, understood,
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# and will comply with the following terms and conditions:
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Permission to use, copy, modify, and distribute this software and
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# its associated documentation for any purpose and without fee is
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# hereby granted, provided that the above copyright notice appears in
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# all copies, and that both that copyright notice and this permission
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# notice appear in supporting documentation, and that the name of
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Secret Labs AB or the author not be used in advertising or publicity
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# pertaining to distribution of the software without specific, written
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# prior permission.
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# OF THIS SOFTWARE.
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# things to look into some day:
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# TODO: sort out True/False/boolean issues for Python 2.3
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiAn XML-RPC client interface for Python.
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiThe marshalling and response parser code can also be used to
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimplement XML-RPC servers.
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiExported exceptions:
1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Error          Base class for client errors
1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ProtocolError  Indicates an HTTP protocol error
1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ResponseError  Indicates a broken response package
1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Fault          Indicates an XML-RPC fault package
1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiExported classes:
1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  ServerProxy    Represents a logical connection to an XML-RPC server
1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  MultiCall      Executor of boxcared xmlrpc requests
1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Boolean        boolean wrapper to generate a "boolean" XML-RPC value
1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  DateTime       dateTime wrapper for an ISO 8601 string or time tuple or
1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 localtime integer value to generate a "dateTime.iso8601"
1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 XML-RPC value
1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Binary         binary data wrapper
1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  SlowParser     Slow but safe standard parser (based on xmllib)
1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Marshaller     Generate an XML-RPC params chunk from a Python data structure
1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Unmarshaller   Unmarshal an XML-RPC response from incoming XML event message
1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  Transport      Handles an HTTP transaction to an XML-RPC server
1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  SafeTransport  Handles an HTTPS transaction to an XML-RPC server
1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiExported constants:
1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  True
1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  False
1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiExported functions:
1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  boolean        Convert any Python value to an XML-RPC boolean
1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  getparser      Create instance of the fastest available parser & attach
1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 to an unmarshalling object
1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  dumps          Convert an argument tuple or a Fault instance to an XML-RPC
1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 request (or response, if the methodresponse option is used).
1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi  loads          Convert an XML-RPC packet to unmarshalled data plus a method
1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 name (None if not present).
1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi"""
1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport re, string, time, operator
1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom types import *
1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport socket
1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport errno
1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport httplib
1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import gzip
1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept ImportError:
1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gzip = None #python can be built without zlib/gzip support
1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Internal stuff
1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    unicode
1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept NameError:
1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    unicode = None # unicode support not available
1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import datetime
1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept ImportError:
1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    datetime = None
1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    _bool_is_builtin = False.__class__.__name__ == "bool"
1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept NameError:
1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    _bool_is_builtin = 0
1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # decode non-ascii string (if possible)
1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if unicode and encoding and is8bit(data):
1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        data = unicode(data, encoding)
1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return data
1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef escape(s, replace=string.replace):
1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    s = replace(s, "&", "&")
1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    s = replace(s, "<", "&lt;")
1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return replace(s, ">", "&gt;",)
1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif unicode:
1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _stringify(string):
1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # convert to 7-bit ascii if possible
1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return string.encode("ascii")
1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except UnicodeError:
1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return string
1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yielse:
1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def _stringify(string):
1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return string
1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi__version__ = "1.0.1"
1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# xmlrpc integer limits
1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMAXINT =  2L**31-1
1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMININT = -2L**31
1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Error constants (from Dan Libby's specification at
1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Ranges of errors
2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiPARSE_ERROR       = -32700
2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSERVER_ERROR      = -32600
2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiAPPLICATION_ERROR = -32500
2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiSYSTEM_ERROR      = -32400
2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiTRANSPORT_ERROR   = -32300
2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Specific errors
2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiNOT_WELLFORMED_ERROR  = -32700
2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiUNSUPPORTED_ENCODING  = -32701
2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiINVALID_ENCODING_CHAR = -32702
2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiINVALID_XMLRPC        = -32600
2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiMETHOD_NOT_FOUND      = -32601
2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiINVALID_METHOD_PARAMS = -32602
2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiINTERNAL_ERROR        = -32603
2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Exceptions
2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Base class for all kinds of client-side errors.
2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass Error(Exception):
2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Base class for client errors."""
2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __str__(self):
2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return repr(self)
2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Indicates an HTTP-level protocol error.  This is raised by the HTTP
2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# transport layer, if the server returns an error code other than 200
2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# (OK).
2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param url The target URL.
2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param errcode The HTTP error code.
2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param errmsg The HTTP error message.
2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param headers The HTTP header dictionary.
2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass ProtocolError(Error):
2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Indicates an HTTP protocol error."""
2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, url, errcode, errmsg, headers):
2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Error.__init__(self)
2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.url = url
2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.errcode = errcode
2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.errmsg = errmsg
2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.headers = headers
2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __repr__(self):
2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return (
2470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "<ProtocolError for %s: %s %s>" %
2480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            (self.url, self.errcode, self.errmsg)
2490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
2500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
2520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Indicates a broken XML-RPC response package.  This exception is
2530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# raised by the unmarshalling layer, if the XML-RPC response is
2540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# malformed.
2550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass ResponseError(Error):
2570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Indicates a broken response package."""
2580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    pass
2590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
2610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Indicates an XML-RPC fault response package.  This exception is
2620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# raised by the unmarshalling layer, if the XML-RPC response contains
2630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# a fault string.  This exception can also used as a class, to
2640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# generate a fault XML-RPC message.
2650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
2660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param faultCode The XML-RPC fault code.
2670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param faultString The XML-RPC fault string.
2680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass Fault(Error):
2700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Indicates an XML-RPC fault package."""
2710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, faultCode, faultString, **extra):
2720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Error.__init__(self)
2730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.faultCode = faultCode
2740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.faultString = faultString
2750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __repr__(self):
2760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return (
2770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "<Fault %s: %s>" %
2780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            (self.faultCode, repr(self.faultString))
2790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
2800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
2820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Special values
2830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
2850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Wrapper for XML-RPC boolean values.  Use the xmlrpclib.True and
2860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# xmlrpclib.False constants, or the xmlrpclib.boolean() function, to
2870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# generate boolean XML-RPC values.
2880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
2890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param value A boolean value.  Any true value is interpreted as True,
2900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#              all other values are interpreted as False.
2910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom sys import modules
2930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yimod_dict = modules[__name__].__dict__
2940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif _bool_is_builtin:
2950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    boolean = Boolean = bool
2960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # to avoid breaking code which references xmlrpclib.{True,False}
2970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    mod_dict['True'] = True
2980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    mod_dict['False'] = False
2990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yielse:
3000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    class Boolean:
3010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """Boolean-value wrapper.
3020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Use True or False to generate a "boolean" XML-RPC value.
3040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """
3050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def __init__(self, value = 0):
3070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.value = operator.truth(value)
3080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def encode(self, out):
3100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            out.write("<value><boolean>%d</boolean></value>\n" % self.value)
3110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def __cmp__(self, other):
3130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if isinstance(other, Boolean):
3140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                other = other.value
3150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return cmp(self.value, other)
3160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def __repr__(self):
3180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if self.value:
3190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                return "<Boolean True at %x>" % id(self)
3200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            else:
3210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                return "<Boolean False at %x>" % id(self)
3220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def __int__(self):
3240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self.value
3250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def __nonzero__(self):
3270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self.value
3280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    mod_dict['True'] = Boolean(1)
3300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    mod_dict['False'] = Boolean(0)
3310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
3330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Map true or false value to XML-RPC boolean values.
3340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
3350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @def boolean(value)
3360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param value A boolean value.  Any true value is mapped to True,
3370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #              all other values are mapped to False.
3380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return xmlrpclib.True or xmlrpclib.False.
3390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @see Boolean
3400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @see True
3410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @see False
3420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def boolean(value, _truefalse=(False, True)):
3440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """Convert any Python value to XML-RPC 'boolean'."""
3450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return _truefalse[operator.truth(value)]
3460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidel modules, mod_dict
3480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
3500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Wrapper for XML-RPC DateTime values.  This converts a time value to
3510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# the format used by XML-RPC.
3520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# <p>
3530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# The value can be given as a string in the format
3540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by
3550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# time.localtime()), or an integer value (as returned by time.time()).
3560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# The wrapper uses time.localtime() to convert an integer to a time
3570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# tuple.
3580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
3590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param value The time, given as an ISO 8601 string, a time
3600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#              tuple, or a integer time value.
3610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _strftime(value):
3630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if datetime:
3640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(value, datetime.datetime):
3650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return "%04d%02d%02dT%02d:%02d:%02d" % (
3660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                value.year, value.month, value.day,
3670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                value.hour, value.minute, value.second)
3680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if not isinstance(value, (TupleType, time.struct_time)):
3700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if value == 0:
3710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            value = time.time()
3720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value = time.localtime(value)
3730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return "%04d%02d%02dT%02d:%02d:%02d" % value[:6]
3750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass DateTime:
3770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """DateTime wrapper for an ISO 8601 string or time tuple or
3780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    localtime integer value to generate 'dateTime.iso8601' XML-RPC
3790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    value.
3800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
3810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, value=0):
3830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(value, StringType):
3840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.value = value
3850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
3860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.value = _strftime(value)
3870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def make_comparable(self, other):
3890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(other, DateTime):
3900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            s = self.value
3910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            o = other.value
3920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif datetime and isinstance(other, datetime.datetime):
3930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            s = self.value
3940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            o = other.strftime("%Y%m%dT%H:%M:%S")
3950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif isinstance(other, (str, unicode)):
3960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            s = self.value
3970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            o = other
3980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif hasattr(other, "timetuple"):
3990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            s = self.timetuple()
4000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            o = other.timetuple()
4010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
4020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            otype = (hasattr(other, "__class__")
4030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                     and other.__class__.__name__
4040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                     or type(other))
4050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise TypeError("Can't compare %s and %s" %
4060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                            (self.__class__.__name__, otype))
4070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s, o
4080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __lt__(self, other):
4100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s < o
4120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __le__(self, other):
4140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s <= o
4160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __gt__(self, other):
4180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s > o
4200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __ge__(self, other):
4220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s >= o
4240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __eq__(self, other):
4260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s == o
4280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __ne__(self, other):
4300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return s != o
4320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def timetuple(self):
4340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return time.strptime(self.value, "%Y%m%dT%H:%M:%S")
4350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __cmp__(self, other):
4370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        s, o = self.make_comparable(other)
4380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return cmp(s, o)
4390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
4410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Get date/time value.
4420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
4430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return Date/time value, as an ISO 8601 string.
4440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __str__(self):
4460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return self.value
4470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __repr__(self):
4490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return "<DateTime %s at %x>" % (repr(self.value), id(self))
4500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def decode(self, data):
4520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        data = str(data)
4530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.value = string.strip(data)
4540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def encode(self, out):
4560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out.write("<value><dateTime.iso8601>")
4570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out.write(self.value)
4580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out.write("</dateTime.iso8601></value>\n")
4590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _datetime(data):
4610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # decode xml element contents into a DateTime structure.
4620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    value = DateTime()
4630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    value.decode(data)
4640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return value
4650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _datetime_type(data):
4670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    t = time.strptime(data, "%Y%m%dT%H:%M:%S")
4680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return datetime.datetime(*tuple(t)[:6])
4690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
4710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Wrapper for binary data.  This can be used to transport any kind
4720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# of binary data over XML-RPC, using BASE64 encoding.
4730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
4740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param data An 8-bit string containing arbitrary data.
4750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport base64
4770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
4780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import cStringIO as StringIO
4790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept ImportError:
4800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import StringIO
4810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass Binary:
4830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Wrapper for binary data."""
4840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, data=None):
4860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.data = data
4870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
4890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Get buffer contents.
4900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
4910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return Buffer contents, as an 8-bit string.
4920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __str__(self):
4940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return self.data or ""
4950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __cmp__(self, other):
4970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(other, Binary):
4980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            other = other.data
4990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return cmp(self.data, other)
5000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def decode(self, data):
5020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.data = base64.decodestring(data)
5030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def encode(self, out):
5050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out.write("<value><base64>\n")
5060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        base64.encode(StringIO.StringIO(self.data), out)
5070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out.write("</base64></value>\n")
5080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef _binary(data):
5100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # decode xml element contents into a Binary structure
5110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    value = Binary()
5120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    value.decode(data)
5130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return value
5140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiWRAPPERS = (DateTime, Binary)
5160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif not _bool_is_builtin:
5170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    WRAPPERS = WRAPPERS + (Boolean,)
5180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
5200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# XML parsers
5210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
5230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # optional xmlrpclib accelerator
5240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import _xmlrpclib
5250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    FastParser = _xmlrpclib.Parser
5260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    FastUnmarshaller = _xmlrpclib.Unmarshaller
5270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept (AttributeError, ImportError):
5280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    FastParser = FastUnmarshaller = None
5290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
5310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import _xmlrpclib
5320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    FastMarshaller = _xmlrpclib.Marshaller
5330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept (AttributeError, ImportError):
5340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    FastMarshaller = None
5350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
5370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    from xml.parsers import expat
5380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if not hasattr(expat, "ParserCreate"):
5390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise ImportError
5400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept ImportError:
5410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ExpatParser = None # expat not available
5420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yielse:
5430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    class ExpatParser:
5440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # fast expat parser for Python 2.0 and later.
5450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def __init__(self, target):
5460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._parser = parser = expat.ParserCreate(None, None)
5470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._target = target
5480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            parser.StartElementHandler = target.start
5490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            parser.EndElementHandler = target.end
5500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            parser.CharacterDataHandler = target.data
5510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            encoding = None
5520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if not parser.returns_unicode:
5530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                encoding = "utf-8"
5540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            target.xml(encoding, None)
5550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def feed(self, data):
5570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._parser.Parse(data, 0)
5580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def close(self):
5600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._parser.Parse("", 1) # end of data
5610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            del self._target, self._parser # get rid of circular references
5620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass SlowParser:
5640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Default XML parser (based on xmllib.XMLParser)."""
5650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # this is the slowest parser.
5660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, target):
5670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        import xmllib # lazy subclassing (!)
5680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if xmllib.XMLParser not in SlowParser.__bases__:
5690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            SlowParser.__bases__ = (xmllib.XMLParser,)
5700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.handle_xml = target.xml
5710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.unknown_starttag = target.start
5720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.handle_data = target.data
5730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.handle_cdata = target.data
5740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.unknown_endtag = target.end
5750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
5760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            xmllib.XMLParser.__init__(self, accept_utf8=1)
5770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except TypeError:
5780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            xmllib.XMLParser.__init__(self) # pre-2.0
5790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
5810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# XML-RPC marshalling and unmarshalling code
5820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
5840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# XML-RPC marshaller.
5850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
5860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param encoding Default encoding for 8-bit strings.  The default
5870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#     value is None (interpreted as UTF-8).
5880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @see dumps
5890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass Marshaller:
5910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Generate an XML-RPC params chunk from a Python data structure.
5920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Create a Marshaller instance for each set of parameters, and use
5940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    the "dumps" method to convert your data (represented as a tuple)
5950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    to an XML-RPC params chunk.  To write a fault response, pass a
5960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Fault instance instead.  You may prefer to use the "dumps" module
5970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    function for this purpose.
5980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
5990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # by the way, if you don't understand what's going on in here,
6010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # that's perfectly ok.
6020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, encoding=None, allow_none=0):
6040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.memo = {}
6050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.data = None
6060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.encoding = encoding
6070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.allow_none = allow_none
6080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch = {}
6100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dumps(self, values):
6120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        out = []
6130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write = out.append
6140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dump = self.__dump
6150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(values, Fault):
6160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # fault instance
6170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<fault>\n")
6180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dump({'faultCode': values.faultCode,
6190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                  'faultString': values.faultString},
6200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 write)
6210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("</fault>\n")
6220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
6230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # parameter block
6240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # FIXME: the xml-rpc specification allows us to leave out
6250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # the entire <params> block if there are no parameters.
6260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # however, changing this may break older code (including
6270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # old versions of xmlrpclib.py), so this is better left as
6280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # is for now.  See @XMLRPC3 for more information. /F
6290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<params>\n")
6300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for v in values:
6310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                write("<param>\n")
6320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                dump(v, write)
6330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                write("</param>\n")
6340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("</params>\n")
6350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        result = string.join(out, "")
6360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return result
6370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __dump(self, value, write):
6390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
6400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            f = self.dispatch[type(value)]
6410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except KeyError:
6420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # check if this object can be marshalled as a structure
6430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            try:
6440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                value.__dict__
6450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except:
6460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                raise TypeError, "cannot marshal %s objects" % type(value)
6470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # check if this class is a sub-class of a basic type,
6480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # because we don't know how to marshal these types
6490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # (e.g. a string sub-class)
6500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for type_ in type(value).__mro__:
6510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if type_ in self.dispatch.keys():
6520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    raise TypeError, "cannot marshal %s objects" % type(value)
6530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            f = self.dispatch[InstanceType]
6540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f(self, value, write)
6550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_nil (self, value, write):
6570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not self.allow_none:
6580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise TypeError, "cannot marshal None unless allow_none is enabled"
6590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><nil/></value>")
6600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[NoneType] = dump_nil
6610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_int(self, value, write):
6630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # in case ints are > 32 bits
6640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if value > MAXINT or value < MININT:
6650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise OverflowError, "int exceeds XML-RPC limits"
6660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><int>")
6670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write(str(value))
6680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("</int></value>\n")
6690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[IntType] = dump_int
6700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if _bool_is_builtin:
6720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def dump_bool(self, value, write):
6730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<value><boolean>")
6740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write(value and "1" or "0")
6750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("</boolean></value>\n")
6760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dispatch[bool] = dump_bool
6770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_long(self, value, write):
6790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if value > MAXINT or value < MININT:
6800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise OverflowError, "long int exceeds XML-RPC limits"
6810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><int>")
6820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write(str(int(value)))
6830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("</int></value>\n")
6840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[LongType] = dump_long
6850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_double(self, value, write):
6870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><double>")
6880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write(repr(value))
6890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("</double></value>\n")
6900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[FloatType] = dump_double
6910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_string(self, value, write, escape=escape):
6930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><string>")
6940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write(escape(value))
6950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("</string></value>\n")
6960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[StringType] = dump_string
6970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if unicode:
6990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def dump_unicode(self, value, write, escape=escape):
7000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            value = value.encode(self.encoding)
7010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<value><string>")
7020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write(escape(value))
7030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("</string></value>\n")
7040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dispatch[UnicodeType] = dump_unicode
7050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_array(self, value, write):
7070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        i = id(value)
7080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if i in self.memo:
7090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise TypeError, "cannot marshal recursive sequences"
7100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.memo[i] = None
7110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dump = self.__dump
7120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><array><data>\n")
7130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for v in value:
7140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dump(v, write)
7150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("</data></array></value>\n")
7160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del self.memo[i]
7170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[TupleType] = dump_array
7180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[ListType] = dump_array
7190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_struct(self, value, write, escape=escape):
7210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        i = id(value)
7220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if i in self.memo:
7230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise TypeError, "cannot marshal recursive dictionaries"
7240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.memo[i] = None
7250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dump = self.__dump
7260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("<value><struct>\n")
7270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for k, v in value.items():
7280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<member>\n")
7290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if type(k) is not StringType:
7300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if unicode and type(k) is UnicodeType:
7310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    k = k.encode(self.encoding)
7320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                else:
7330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    raise TypeError, "dictionary key must be string"
7340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<name>%s</name>\n" % escape(k))
7350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dump(v, write)
7360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("</member>\n")
7370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        write("</struct></value>\n")
7380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del self.memo[i]
7390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[DictType] = dump_struct
7400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if datetime:
7420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def dump_datetime(self, value, write):
7430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("<value><dateTime.iso8601>")
7440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write(_strftime(value))
7450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            write("</dateTime.iso8601></value>\n")
7460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dispatch[datetime.datetime] = dump_datetime
7470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def dump_instance(self, value, write):
7490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # check for special wrappers
7500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if value.__class__ in WRAPPERS:
7510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.write = write
7520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            value.encode(self)
7530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            del self.write
7540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
7550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # store instance attributes as a struct (really?)
7560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.dump_struct(value.__dict__, write)
7570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch[InstanceType] = dump_instance
7580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
7600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# XML-RPC unmarshaller.
7610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
7620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @see loads
7630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass Unmarshaller:
7650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Unmarshal an XML-RPC response, based on incoming XML event
7660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    messages (start, data, end).  Call close() to get the resulting
7670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    data structure.
7680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Note that this reader is fairly tolerant, and gladly accepts bogus
7700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    XML-RPC data without complaining (but not bogus XML).
7710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
7720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # and again, if you don't understand what's going on in here,
7740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # that's perfectly ok.
7750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, use_datetime=0):
7770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._type = None
7780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._stack = []
7790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._marks = []
7800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._data = []
7810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._methodname = None
7820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._encoding = "utf-8"
7830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append = self._stack.append
7840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._use_datetime = use_datetime
7850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if use_datetime and not datetime:
7860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise ValueError, "the datetime module is not available"
7870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def close(self):
7890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # return response tuple and target method
7900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._type is None or self._marks:
7910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise ResponseError()
7920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._type == "fault":
7930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise Fault(**self._stack[0])
7940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return tuple(self._stack)
7950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def getmethodname(self):
7970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return self._methodname
7980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
8000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # event handlers
8010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def xml(self, encoding, standalone):
8030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._encoding = encoding
8040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # FIXME: assert standalone == 1 ???
8050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def start(self, tag, attrs):
8070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # prepare to handle this element
8080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if tag == "array" or tag == "struct":
8090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._marks.append(len(self._stack))
8100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._data = []
8110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = (tag == "value")
8120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def data(self, text):
8140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._data.append(text)
8150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end(self, tag, join=string.join):
8170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # call the appropriate end tag handler
8180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
8190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            f = self.dispatch[tag]
8200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except KeyError:
8210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass # unknown tag ?
8220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
8230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return f(self, join(self._data, ""))
8240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
8260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # accelerator support
8270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_dispatch(self, tag, data):
8290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # dispatch data
8300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
8310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            f = self.dispatch[tag]
8320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except KeyError:
8330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass # unknown tag ?
8340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
8350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return f(self, data)
8360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
8380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # element decoders
8390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch = {}
8410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_nil (self, data):
8430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append(None)
8440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["nil"] = end_nil
8460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_boolean(self, data):
8480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if data == "0":
8490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.append(False)
8500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif data == "1":
8510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.append(True)
8520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
8530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise TypeError, "bad boolean value"
8540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["boolean"] = end_boolean
8560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_int(self, data):
8580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append(int(data))
8590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["i4"] = end_int
8610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["i8"] = end_int
8620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["int"] = end_int
8630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_double(self, data):
8650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append(float(data))
8660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["double"] = end_double
8680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_string(self, data):
8700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._encoding:
8710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data = _decode(data, self._encoding)
8720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append(_stringify(data))
8730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["string"] = end_string
8750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["name"] = end_string # struct keys are always strings
8760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_array(self, data):
8780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        mark = self._marks.pop()
8790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # map arrays to Python lists
8800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._stack[mark:] = [self._stack[mark:]]
8810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["array"] = end_array
8830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_struct(self, data):
8850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        mark = self._marks.pop()
8860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # map structs to Python dictionaries
8870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        dict = {}
8880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        items = self._stack[mark:]
8890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for i in range(0, len(items), 2):
8900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dict[_stringify(items[i])] = items[i+1]
8910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._stack[mark:] = [dict]
8920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
8930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["struct"] = end_struct
8940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
8950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_base64(self, data):
8960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value = Binary()
8970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value.decode(data)
8980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append(value)
8990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._value = 0
9000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["base64"] = end_base64
9010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_dateTime(self, data):
9030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value = DateTime()
9040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        value.decode(data)
9050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._use_datetime:
9060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            value = _datetime_type(data)
9070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.append(value)
9080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["dateTime.iso8601"] = end_dateTime
9090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_value(self, data):
9110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # if we stumble upon a value element with no internal
9120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # elements, treat it as a string element
9130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._value:
9140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.end_string(data)
9150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["value"] = end_value
9160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_params(self, data):
9180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._type = "params"
9190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["params"] = end_params
9200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_fault(self, data):
9220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._type = "fault"
9230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["fault"] = end_fault
9240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def end_methodName(self, data):
9260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._encoding:
9270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data = _decode(data, self._encoding)
9280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._methodname = data
9290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._type = "methodName" # no params
9300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    dispatch["methodName"] = end_methodName
9310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi## Multicall support
9330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
9340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass _MultiCallMethod:
9360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # some lesser magic to store calls made to a MultiCall object
9370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # for batch execution
9380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, call_list, name):
9390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__call_list = call_list
9400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__name = name
9410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __getattr__(self, name):
9420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return _MultiCallMethod(self.__call_list, "%s.%s" % (self.__name, name))
9430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __call__(self, *args):
9440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__call_list.append((self.__name, args))
9450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass MultiCallIterator:
9470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Iterates over the results of a multicall. Exceptions are
9480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    raised in response to xmlrpc faults."""
9490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, results):
9510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.results = results
9520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __getitem__(self, i):
9540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        item = self.results[i]
9550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if type(item) == type({}):
9560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise Fault(item['faultCode'], item['faultString'])
9570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif type(item) == type([]):
9580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return item[0]
9590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
9600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise ValueError,\
9610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                  "unexpected type in multicall result"
9620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass MultiCall:
9640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """server -> a object used to boxcar method calls
9650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    server should be a ServerProxy object.
9670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Methods can be added to the MultiCall using normal
9690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    method call syntax e.g.:
9700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multicall = MultiCall(server_proxy)
9720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multicall.add(2,3)
9730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multicall.get_address("Guido")
9740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    To execute the multicall, call the MultiCall object e.g.:
9760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    add_result, address = multicall()
9780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
9790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, server):
9810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__server = server
9820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__call_list = []
9830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __repr__(self):
9850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return "<MultiCall at %x>" % id(self)
9860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    __str__ = __repr__
9880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __getattr__(self, name):
9900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return _MultiCallMethod(self.__call_list, name)
9910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __call__(self):
9930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        marshalled_list = []
9940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for name, args in self.__call_list:
9950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            marshalled_list.append({'methodName' : name, 'params' : args})
9960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return MultiCallIterator(self.__server.system.multicall(marshalled_list))
9980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
9990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
10000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# convenience functions
10010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
10030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Create a parser object, and connect it to an unmarshalling instance.
10040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# This function picks the fastest available XML parser.
10050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
10060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# return A (parser, unmarshaller) tuple.
10070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef getparser(use_datetime=0):
10090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """getparser() -> parser, unmarshaller
10100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Create an instance of the fastest available parser, and attach it
10120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    to an unmarshalling object.  Return both objects.
10130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
10140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if use_datetime and not datetime:
10150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise ValueError, "the datetime module is not available"
10160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if FastParser and FastUnmarshaller:
10170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if use_datetime:
10180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            mkdatetime = _datetime_type
10190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
10200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            mkdatetime = _datetime
10210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        target = FastUnmarshaller(True, False, _binary, mkdatetime, Fault)
10220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        parser = FastParser(target)
10230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    else:
10240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        target = Unmarshaller(use_datetime=use_datetime)
10250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if FastParser:
10260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            parser = FastParser(target)
10270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif ExpatParser:
10280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            parser = ExpatParser(target)
10290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
10300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            parser = SlowParser(target)
10310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return parser, target
10320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
10340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Convert a Python tuple or a Fault instance to an XML-RPC packet.
10350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
10360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @def dumps(params, **options)
10370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param params A tuple or Fault instance.
10380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @keyparam methodname If given, create a methodCall request for
10390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#     this method name.
10400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @keyparam methodresponse If given, create a methodResponse packet.
10410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#     If used with a tuple, the tuple must be a singleton (that is,
10420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#     it must contain exactly one element).
10430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @keyparam encoding The packet encoding.
10440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @return A string containing marshalled data.
10450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef dumps(params, methodname=None, methodresponse=None, encoding=None,
10470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi          allow_none=0):
10480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """data [,options] -> marshalled data
10490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Convert an argument tuple or a Fault instance to an XML-RPC
10510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    request (or response, if the methodresponse option is used).
10520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    In addition to the data object, the following options can be given
10540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    as keyword arguments:
10550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        methodname: the method name for a methodCall packet
10570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        methodresponse: true to create a methodResponse packet.
10590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        If this option is used with a tuple, the tuple must be
10600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a singleton (i.e. it can contain only one element).
10610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        encoding: the packet encoding (default is UTF-8)
10630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    All 8-bit strings in the data structure are assumed to use the
10650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    packet encoding.  Unicode strings are automatically converted,
10660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    where necessary.
10670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
10680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    assert isinstance(params, TupleType) or isinstance(params, Fault),\
10700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           "argument must be tuple or Fault instance"
10710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if isinstance(params, Fault):
10730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        methodresponse = 1
10740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    elif methodresponse and isinstance(params, TupleType):
10750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assert len(params) == 1, "response tuple must be a singleton"
10760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if not encoding:
10780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        encoding = "utf-8"
10790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if FastMarshaller:
10810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = FastMarshaller(encoding)
10820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    else:
10830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        m = Marshaller(encoding, allow_none)
10840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    data = m.dumps(params)
10860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if encoding != "utf-8":
10880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
10890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    else:
10900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
10910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
10920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # standard XML-RPC wrappings
10930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if methodname:
10940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # a method call
10950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not isinstance(methodname, StringType):
10960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            methodname = methodname.encode(encoding)
10970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        data = (
10980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            xmlheader,
10990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "<methodCall>\n"
11000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "<methodName>", methodname, "</methodName>\n",
11010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data,
11020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "</methodCall>\n"
11030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
11040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    elif methodresponse:
11050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # a method response, or a fault structure
11060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        data = (
11070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            xmlheader,
11080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "<methodResponse>\n",
11090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data,
11100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "</methodResponse>\n"
11110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
11120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    else:
11130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return data # return as is
11140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return string.join(data, "")
11150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
11170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Convert an XML-RPC packet to a Python object.  If the XML-RPC packet
11180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# represents a fault condition, this function raises a Fault exception.
11190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
11200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param data An XML-RPC packet, given as an 8-bit string.
11210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @return A tuple containing the unpacked data, and the method name
11220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#     (None if not present).
11230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @see Fault
11240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef loads(data, use_datetime=0):
11260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """data -> unmarshalled data, method name
11270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Convert an XML-RPC packet to unmarshalled data plus a method
11290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    name (None if not present).
11300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    If the XML-RPC packet represents a fault condition, this function
11320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    raises a Fault exception.
11330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
11340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    p, u = getparser(use_datetime=use_datetime)
11350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    p.feed(data)
11360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    p.close()
11370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return u.close(), u.getmethodname()
11380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
11400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Encode a string using the gzip content encoding such as specified by the
11410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Content-Encoding: gzip
11420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# in the HTTP header, as described in RFC 1952
11430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
11440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param data the unencoded data
11450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @return the encoded data
11460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef gzip_encode(data):
11480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """data -> gzip encoded data
11490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Encode data using the gzip content encoding as described in RFC 1952
11510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
11520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if not gzip:
11530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise NotImplementedError
11540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    f = StringIO.StringIO()
11550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gzf = gzip.GzipFile(mode="wb", fileobj=f, compresslevel=1)
11560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gzf.write(data)
11570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gzf.close()
11580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    encoded = f.getvalue()
11590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    f.close()
11600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return encoded
11610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
11630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Decode a string using the gzip content encoding such as specified by the
11640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Content-Encoding: gzip
11650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# in the HTTP header, as described in RFC 1952
11660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
11670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param data The encoded data
11680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @return the unencoded data
11690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @raises ValueError if data is not correctly coded.
11700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef gzip_decode(data):
11720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """gzip encoded data -> unencoded data
11730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    Decode data using the gzip content encoding as described in RFC 1952
11750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
11760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    if not gzip:
11770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise NotImplementedError
11780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    f = StringIO.StringIO(data)
11790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gzf = gzip.GzipFile(mode="rb", fileobj=f)
11800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
11810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        decoded = gzf.read()
11820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    except IOError:
11830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise ValueError("invalid data")
11840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    f.close()
11850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gzf.close()
11860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    return decoded
11870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
11890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Return a decoded file-like object for the gzip encoding
11900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# as described in RFC 1952.
11910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
11920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param response A stream supporting a read() method
11930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @return a file-like object that the decoded data can be read() from
11940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
11950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass GzipDecodedResponse(gzip.GzipFile if gzip else object):
11960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """a file-like object to decode a response encoded with the gzip
11970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    method, as described in RFC 1952.
11980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
11990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, response):
12000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #response doesn't support tell() and read(), required by
12010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #GzipFile
12020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not gzip:
12030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise NotImplementedError
12040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.stringio = StringIO.StringIO(response.read())
12050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
12060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def close(self):
12080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gzip.GzipFile.close(self)
12090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.stringio.close()
12100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
12130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# request dispatcher
12140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass _Method:
12160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # some magic to bind an XML-RPC method to an RPC server.
12170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # supports "nested" methods (e.g. examples.getStateName)
12180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, send, name):
12190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__send = send
12200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__name = name
12210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __getattr__(self, name):
12220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return _Method(self.__send, "%s.%s" % (self.__name, name))
12230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __call__(self, *args):
12240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return self.__send(self.__name, args)
12250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
12270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Standard transport class for XML-RPC over HTTP.
12280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# <p>
12290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# You can create custom transports by subclassing this method, and
12300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# overriding selected methods.
12310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass Transport:
12330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Handles an HTTP transaction to an XML-RPC server."""
12340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # client identifier (may be overridden)
12360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
12370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #if true, we'll request gzip encoding
12390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    accept_gzip_encoding = True
12400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # if positive, encode request using gzip if it exceeds this threshold
12420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # note that many server will get confused, so only use it if you know
12430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # that they can decode such a request
12440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    encode_threshold = None #None = don't encode
12450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, use_datetime=0):
12470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._use_datetime = use_datetime
12480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._connection = (None, None)
12490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._extra_headers = []
12500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
12510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Send a complete request, and parse the response.
12520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Retry request if a cached connection has disconnected.
12530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
12540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param host Target host.
12550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param handler Target PRC handler.
12560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param request_body XML-RPC request body.
12570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param verbose Debugging flag.
12580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return Parsed response.
12590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def request(self, host, handler, request_body, verbose=0):
12610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #retry request once if cached connection has gone cold
12620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for i in (0, 1):
12630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            try:
12640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                return self.single_request(host, handler, request_body, verbose)
12650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except socket.error, e:
12660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if i or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
12670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    raise
12680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            except httplib.BadStatusLine: #close after we sent request
12690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if i:
12700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    raise
12710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
12730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Send a complete request, and parse the response.
12740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
12750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param host Target host.
12760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param handler Target PRC handler.
12770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param request_body XML-RPC request body.
12780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param verbose Debugging flag.
12790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return Parsed response.
12800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def single_request(self, host, handler, request_body, verbose=0):
12820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # issue XML-RPC request
12830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        h = self.make_connection(host)
12850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if verbose:
12860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            h.set_debuglevel(1)
12870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
12890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.send_request(h, handler, request_body)
12900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.send_host(h, host)
12910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.send_user_agent(h)
12920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.send_content(h, request_body)
12930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
12940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            response = h.getresponse(buffering=True)
12950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if response.status == 200:
12960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.verbose = verbose
12970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                return self.parse_response(response)
12980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except Fault:
12990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise
13000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except Exception:
13010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # All unexpected errors leave connection in
13020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # a strange state, so we clear it.
13030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.close()
13040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise
13050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #discard any response data and raise exception
13070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if (response.getheader("content-length", 0)):
13080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            response.read()
13090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise ProtocolError(
13100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            host + handler,
13110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            response.status, response.reason,
13120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            response.msg,
13130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
13140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
13160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Create parser.
13170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
13180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return A 2-tuple containing a parser and a unmarshaller.
13190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def getparser(self):
13210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # get parser and unmarshaller
13220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return getparser(use_datetime=self._use_datetime)
13230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
13250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Get authorization info from host parameter
13260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Host may be a string, or a (host, x509-dict) tuple; if a string,
13270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # it is checked for a "user:pw@host" format, and a "Basic
13280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Authentication" header is added if appropriate.
13290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
13300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param host Host descriptor (URL or (URL, x509 info) tuple).
13310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return A 3-tuple containing (actual host, extra headers,
13320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #     x509 info).  The header and x509 fields may be None.
13330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def get_host_info(self, host):
13350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        x509 = {}
13370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(host, TupleType):
13380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            host, x509 = host
13390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        import urllib
13410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        auth, host = urllib.splituser(host)
13420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if auth:
13440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            import base64
13450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            auth = base64.encodestring(urllib.unquote(auth))
13460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            auth = string.join(string.split(auth), "") # get rid of whitespace
13470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            extra_headers = [
13480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ("Authorization", "Basic " + auth)
13490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ]
13500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
13510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            extra_headers = None
13520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return host, extra_headers, x509
13540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
13560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Connect to server.
13570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
13580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param host Target host.
13590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return A connection handle.
13600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def make_connection(self, host):
13620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #return an existing connection if possible.  This allows
13630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #HTTP/1.1 keep-alive.
13640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._connection and host == self._connection[0]:
13650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self._connection[1]
13660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # create a HTTP connection object from a host descriptor
13680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        chost, self._extra_headers, x509 = self.get_host_info(host)
13690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #store the host argument along with the connection object
13700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self._connection = host, httplib.HTTPConnection(chost)
13710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return self._connection[1]
13720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
13740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Clear any cached connection object.
13750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Used in the event of socket errors.
13760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
13770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def close(self):
13780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._connection[1]:
13790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._connection[1].close()
13800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._connection = (None, None)
13810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
13830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Send request header.
13840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
13850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param connection Connection handle.
13860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param handler Target RPC handler.
13870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param request_body XML-RPC body.
13880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def send_request(self, connection, handler, request_body):
13900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if (self.accept_gzip_encoding and gzip):
13910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            connection.putrequest("POST", handler, skip_accept_encoding=True)
13920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            connection.putheader("Accept-Encoding", "gzip")
13930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
13940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            connection.putrequest("POST", handler)
13950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
13960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
13970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Send host name.
13980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
13990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param connection Connection handle.
14000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param host Host name.
14010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
14020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Note: This function doesn't actually add the "Host"
14030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # header anymore, it is done as part of the connection.putrequest() in
14040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # send_request() above.
14050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def send_host(self, connection, host):
14070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        extra_headers = self._extra_headers
14080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if extra_headers:
14090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if isinstance(extra_headers, DictType):
14100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                extra_headers = extra_headers.items()
14110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for key, value in extra_headers:
14120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                connection.putheader(key, value)
14130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
14150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Send user-agent identifier.
14160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
14170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param connection Connection handle.
14180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def send_user_agent(self, connection):
14200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        connection.putheader("User-Agent", self.user_agent)
14210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
14230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Send request body.
14240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
14250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param connection Connection handle.
14260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param request_body XML-RPC request body.
14270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def send_content(self, connection, request_body):
14290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        connection.putheader("Content-Type", "text/xml")
14300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #optionally encode the request
14320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if (self.encode_threshold is not None and
14330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.encode_threshold < len(request_body) and
14340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            gzip):
14350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            connection.putheader("Content-Encoding", "gzip")
14360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            request_body = gzip_encode(request_body)
14370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        connection.putheader("Content-Length", str(len(request_body)))
14390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        connection.endheaders(request_body)
14400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    ##
14420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Parse response.
14430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    #
14440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @param file Stream.
14450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # @return Response tuple and target method.
14460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def parse_response(self, response):
14480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # read response data from httpresponse, and parse it
14490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Check for new http response object, else it is a file object
14510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if hasattr(response,'getheader'):
14520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if response.getheader("Content-Encoding", "") == "gzip":
14530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                stream = GzipDecodedResponse(response)
14540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            else:
14550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                stream = response
14560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
14570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            stream = response
14580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        p, u = self.getparser()
14600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        while 1:
14620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            data = stream.read(1024)
14630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if not data:
14640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                break
14650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if self.verbose:
14660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                print "body:", repr(data)
14670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            p.feed(data)
14680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if stream is not response:
14700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            stream.close()
14710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        p.close()
14720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return u.close()
14740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
14760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Standard transport class for XML-RPC over HTTPS.
14770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass SafeTransport(Transport):
14790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """Handles an HTTPS transaction to an XML-RPC server."""
14800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # FIXME: mostly untested
14820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def make_connection(self, host):
14840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if self._connection and host == self._connection[0]:
14850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self._connection[1]
14860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # create a HTTPS connection object from a host descriptor
14870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # host may be a string, or a (host, x509-dict) tuple
14880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
14890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            HTTPS = httplib.HTTPSConnection
14900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        except AttributeError:
14910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise NotImplementedError(
14920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                "your version of httplib doesn't support HTTPS"
14930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                )
14940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
14950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            chost, self._extra_headers, x509 = self.get_host_info(host)
14960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self._connection = host, HTTPS(chost, None, **(x509 or {}))
14970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self._connection[1]
14980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
14990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi##
15000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Standard server proxy.  This class establishes a virtual connection
15010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# to an XML-RPC server.
15020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# <p>
15030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# This class is available as ServerProxy and Server.  New code should
15040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# use ServerProxy, to avoid confusion.
15050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#
15060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @def ServerProxy(uri, **options)
15070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @param uri The connection point on the server.
15080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @keyparam transport A transport factory, compatible with the
15090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#    standard transport class.
15100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @keyparam encoding The default encoding used for 8-bit strings
15110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#    (default is UTF-8).
15120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @keyparam verbose Use a true value to enable debugging output.
15130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi#    (printed to standard output).
15140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# @see Transport
15150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass ServerProxy:
15170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """uri [,options] -> a logical connection to an XML-RPC server
15180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    uri is the connection point on the server, given as
15200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    scheme://host/target.
15210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    The standard implementation always supports the "http" scheme.  If
15230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    SSL socket support is available (Python 2.0), it also supports
15240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    "https".
15250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    If the target part and the slash preceding it are both omitted,
15270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    "/RPC2" is assumed.
15280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    The following options can be given as keyword arguments:
15300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        transport: a transport factory
15320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        encoding: the request encoding (default is UTF-8)
15330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    All 8-bit strings passed to the server proxy are assumed to use
15350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    the given encoding.
15360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    """
15370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, uri, transport=None, encoding=None, verbose=0,
15390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                 allow_none=0, use_datetime=0):
15400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # establish a "logical" server connection
15410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if isinstance(uri, unicode):
15430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            uri = uri.encode('ISO-8859-1')
15440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # get the url
15460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        import urllib
15470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        type, uri = urllib.splittype(uri)
15480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if type not in ("http", "https"):
15490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            raise IOError, "unsupported XML-RPC protocol"
15500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__host, self.__handler = urllib.splithost(uri)
15510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not self.__handler:
15520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.__handler = "/RPC2"
15530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if transport is None:
15550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if type == "https":
15560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                transport = SafeTransport(use_datetime=use_datetime)
15570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            else:
15580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                transport = Transport(use_datetime=use_datetime)
15590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__transport = transport
15600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__encoding = encoding
15620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__verbose = verbose
15630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__allow_none = allow_none
15640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __close(self):
15660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.__transport.close()
15670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __request(self, methodname, params):
15690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # call a method on the remote server
15700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        request = dumps(params, methodname, encoding=self.__encoding,
15720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                        allow_none=self.__allow_none)
15730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        response = self.__transport.request(
15750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.__host,
15760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.__handler,
15770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            request,
15780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            verbose=self.__verbose
15790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
15800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if len(response) == 1:
15820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            response = response[0]
15830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return response
15850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __repr__(self):
15870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return (
15880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            "<ServerProxy for %s%s>" %
15890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            (self.__host, self.__handler)
15900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            )
15910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    __str__ = __repr__
15930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __getattr__(self, name):
15950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # magic method dispatcher
15960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        return _Method(self.__request, name)
15970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
15980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # note: to call a remote object with an non-standard name, use
15990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # result getattr(server, "strange-python-name")(args)
16000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __call__(self, attr):
16020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """A workaround to get special attributes on the ServerProxy
16030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi           without interfering with the magic __getattr__
16040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        """
16050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if attr == "close":
16060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self.__close
16070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        elif attr == "transport":
16080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            return self.__transport
16090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        raise AttributeError("Attribute %r not found" % (attr,))
16100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# compatibility
16120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill YiServer = ServerProxy
16140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# --------------------------------------------------------------------
16160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# test code
16170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif __name__ == "__main__":
16190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # simple test program (from the XML-RPC specification)
16210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # server = ServerProxy("http://localhost:8000") # local server
16230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    server = ServerProxy("http://time.xmlrpc.com/RPC2")
16240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    print server
16260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
16280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print server.currentTime.getCurrentTime()
16290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    except Error, v:
16300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "ERROR", v
16310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
16320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multi = MultiCall(server)
16330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multi.currentTime.getCurrentTime()
16340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    multi.currentTime.getCurrentTime()
16350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
16360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for response in multi():
16370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            print response
16380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    except Error, v:
16390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        print "ERROR", v
1640