| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # XML-RPC CLIENT LIBRARY | 
					
						
							|  |  |  | # $Id$ | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  | # an XML-RPC client interface for Python. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # the marshalling and response parser code can also be used to | 
					
						
							|  |  |  | # implement XML-RPC servers. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Notes: | 
					
						
							|  |  |  | # this version is designed to work with Python 1.5.2 or newer. | 
					
						
							|  |  |  | # unicode encoding support requires at least Python 1.6. | 
					
						
							|  |  |  | # experimental HTTPS requires Python 2.0 built with SSL sockets. | 
					
						
							|  |  |  | # expat parser support requires Python 2.0 with pyexpat support. | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | # History: | 
					
						
							|  |  |  | # 1999-01-14 fl  Created | 
					
						
							|  |  |  | # 1999-01-15 fl  Changed dateTime to use localtime | 
					
						
							|  |  |  | # 1999-01-16 fl  Added Binary/base64 element, default to RPC2 service | 
					
						
							|  |  |  | # 1999-01-19 fl  Fixed array data element (from Skip Montanaro) | 
					
						
							|  |  |  | # 1999-01-21 fl  Fixed dateTime constructor, etc. | 
					
						
							|  |  |  | # 1999-02-02 fl  Added fault handling, handle empty sequences, etc. | 
					
						
							|  |  |  | # 1999-02-10 fl  Fixed problem with empty responses (from Skip Montanaro) | 
					
						
							|  |  |  | # 1999-06-20 fl  Speed improvements, pluggable parsers/transports (0.9.8) | 
					
						
							|  |  |  | # 2000-11-28 fl  Changed boolean to check the truth value of its argument | 
					
						
							|  |  |  | # 2001-02-24 fl  Added encoding/Unicode/SafeTransport patches | 
					
						
							|  |  |  | # 2001-02-26 fl  Added compare support to wrappers (0.9.9/1.0b1) | 
					
						
							|  |  |  | # 2001-03-28 fl  Make sure response tuple is a singleton | 
					
						
							|  |  |  | # 2001-03-29 fl  Don't require empty params element (from Nicholas Riley) | 
					
						
							| 
									
										
										
										
											2001-08-23 20:04:33 +00:00
										 |  |  | # 2001-06-10 fl  Folded in _xmlrpclib accelerator support (1.0b2) | 
					
						
							|  |  |  | # 2001-08-20 fl  Base xmlrpclib.Error on built-in Exception (from Paul Prescod) | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  | # 2001-09-03 fl  Allow Transport subclass to override getparser | 
					
						
							|  |  |  | # 2001-09-10 fl  Lazy import of urllib, cgi, xmllib (20x import speedup) | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  | # 2001-10-01 fl  Remove containers from memo cache when done with them | 
					
						
							|  |  |  | # 2001-10-01 fl  Use faster escape method (80% dumps speedup) | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # 2001-10-02 fl  More dumps microtuning | 
					
						
							|  |  |  | # 2001-10-04 fl  Make sure import expat gets a parser (from Guido van Rossum) | 
					
						
							| 
									
										
										
										
											2001-10-10 15:56:34 +00:00
										 |  |  | # 2001-10-10 sm  Allow long ints to be passed as ints if they don't overflow | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # 2001-10-17 sm  Test for int and long overflow (allows use on 64-bit systems) | 
					
						
							| 
									
										
										
										
											2001-12-19 21:40:04 +00:00
										 |  |  | # 2001-11-12 fl  Use repr() to marshal doubles (from Paul Felix) | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # 2002-03-17 fl  Avoid buffered read when possible (from James Rucker) | 
					
						
							|  |  |  | # 2002-04-07 fl  Added pythondoc comments | 
					
						
							|  |  |  | # 2002-04-16 fl  Added __str__ methods to datetime/binary wrappers | 
					
						
							|  |  |  | # 2002-05-15 fl  Added error constants (from Andrew Kuchling) | 
					
						
							|  |  |  | # 2002-06-27 fl  Merged with Python CVS version | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | # | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # Copyright (c) 1999-2002 by Secret Labs AB. | 
					
						
							|  |  |  | # Copyright (c) 1999-2002 by Fredrik Lundh. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # info@pythonware.com | 
					
						
							|  |  |  | # http://www.pythonware.com | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # The XML-RPC client interface is | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # Copyright (c) 1999-2002 by Secret Labs AB | 
					
						
							|  |  |  | # Copyright (c) 1999-2002 by Fredrik Lundh | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # By obtaining, using, and/or copying this software and/or its | 
					
						
							|  |  |  | # associated documentation, you agree that you have read, understood, | 
					
						
							|  |  |  | # and will comply with the following terms and conditions: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Permission to use, copy, modify, and distribute this software and | 
					
						
							|  |  |  | # its associated documentation for any purpose and without fee is | 
					
						
							|  |  |  | # hereby granted, provided that the above copyright notice appears in | 
					
						
							|  |  |  | # all copies, and that both that copyright notice and this permission | 
					
						
							|  |  |  | # notice appear in supporting documentation, and that the name of | 
					
						
							|  |  |  | # Secret Labs AB or the author not be used in advertising or publicity | 
					
						
							|  |  |  | # pertaining to distribution of the software without specific, written | 
					
						
							|  |  |  | # prior permission. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | 
					
						
							|  |  |  | # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- | 
					
						
							|  |  |  | # ABILITY AND FITNESS.  IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR | 
					
						
							|  |  |  | # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY | 
					
						
							|  |  |  | # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | 
					
						
							|  |  |  | # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | 
					
						
							|  |  |  | # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | 
					
						
							|  |  |  | # OF THIS SOFTWARE. | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # things to look into some day: | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # TODO: sort out True/False/boolean issues for Python 2.3 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | An XML-RPC client interface for Python. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The marshalling and response parser code can also be used to | 
					
						
							|  |  |  | implement XML-RPC servers. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Exported exceptions: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |   Error          Base class for client errors | 
					
						
							|  |  |  |   ProtocolError  Indicates an HTTP protocol error | 
					
						
							|  |  |  |   ResponseError  Indicates a broken response package | 
					
						
							|  |  |  |   Fault          Indicates an XML-RPC fault package | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Exported classes: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |   ServerProxy    Represents a logical connection to an XML-RPC server | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |   Boolean        boolean wrapper to generate a "boolean" XML-RPC value | 
					
						
							|  |  |  |   DateTime       dateTime wrapper for an ISO 8601 string or time tuple or | 
					
						
							|  |  |  |                  localtime integer value to generate a "dateTime.iso8601" | 
					
						
							|  |  |  |                  XML-RPC value | 
					
						
							|  |  |  |   Binary         binary data wrapper | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |   SlowParser     Slow but safe standard parser (based on xmllib) | 
					
						
							|  |  |  |   Marshaller     Generate an XML-RPC params chunk from a Python data structure | 
					
						
							|  |  |  |   Unmarshaller   Unmarshal an XML-RPC response from incoming XML event message | 
					
						
							|  |  |  |   Transport      Handles an HTTP transaction to an XML-RPC server | 
					
						
							|  |  |  |   SafeTransport  Handles an HTTPS transaction to an XML-RPC server | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Exported constants: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |   True | 
					
						
							|  |  |  |   False | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Exported functions: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |   boolean        Convert any Python value to an XML-RPC boolean | 
					
						
							|  |  |  |   getparser      Create instance of the fastest available parser & attach | 
					
						
							|  |  |  |                  to an unmarshalling object | 
					
						
							|  |  |  |   dumps          Convert an argument tuple or a Fault instance to an XML-RPC | 
					
						
							|  |  |  |                  request (or response, if the methodresponse option is used). | 
					
						
							|  |  |  |   loads          Convert an XML-RPC packet to unmarshalled data plus a method | 
					
						
							|  |  |  |                  name (None if not present). | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-17 01:51:04 +00:00
										 |  |  | import re, string, time, operator | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | from types import * | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # Internal stuff | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | try: | 
					
						
							|  |  |  |     unicode | 
					
						
							|  |  |  | except NameError: | 
					
						
							|  |  |  |     unicode = None # unicode support not available | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search): | 
					
						
							|  |  |  |     # decode non-ascii string (if possible) | 
					
						
							|  |  |  |     if unicode and encoding and is8bit(data): | 
					
						
							|  |  |  |         data = unicode(data, encoding) | 
					
						
							|  |  |  |     return data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  | def escape(s, replace=string.replace): | 
					
						
							|  |  |  |     s = replace(s, "&", "&") | 
					
						
							|  |  |  |     s = replace(s, "<", "<") | 
					
						
							|  |  |  |     return replace(s, ">", ">",) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | if unicode: | 
					
						
							|  |  |  |     def _stringify(string): | 
					
						
							|  |  |  |         # convert to 7-bit ascii if possible | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return str(string) | 
					
						
							|  |  |  |         except UnicodeError: | 
					
						
							|  |  |  |             return string | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     def _stringify(string): | 
					
						
							|  |  |  |         return string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | __version__ = "1.0.1" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # xmlrpc integer limits | 
					
						
							|  |  |  | MAXINT =  2L**31-1 | 
					
						
							|  |  |  | MININT = -2L**31 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # Error constants (from Dan Libby's specification at | 
					
						
							|  |  |  | # http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Ranges of errors | 
					
						
							|  |  |  | PARSE_ERROR       = -32700 | 
					
						
							|  |  |  | SERVER_ERROR      = -32600 | 
					
						
							|  |  |  | APPLICATION_ERROR = -32500 | 
					
						
							|  |  |  | SYSTEM_ERROR      = -32400 | 
					
						
							|  |  |  | TRANSPORT_ERROR   = -32300 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Specific errors | 
					
						
							|  |  |  | NOT_WELLFORMED_ERROR  = -32700 | 
					
						
							|  |  |  | UNSUPPORTED_ENCODING  = -32701 | 
					
						
							|  |  |  | INVALID_ENCODING_CHAR = -32702 | 
					
						
							|  |  |  | INVALID_XMLRPC        = -32600 | 
					
						
							|  |  |  | METHOD_NOT_FOUND      = -32601 | 
					
						
							|  |  |  | INVALID_METHOD_PARAMS = -32602 | 
					
						
							|  |  |  | INTERNAL_ERROR        = -32603 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # Exceptions | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Base class for all kinds of client-side errors. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-23 20:04:33 +00:00
										 |  |  | class Error(Exception): | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """Base class for client errors.""" | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return repr(self) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Indicates an HTTP-level protocol error.  This is raised by the HTTP | 
					
						
							|  |  |  | # transport layer, if the server returns an error code other than 200 | 
					
						
							|  |  |  | # (OK). | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param url The target URL. | 
					
						
							|  |  |  | # @param errcode The HTTP error code. | 
					
						
							|  |  |  | # @param errmsg The HTTP error message. | 
					
						
							|  |  |  | # @param headers The HTTP header dictionary. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class ProtocolError(Error): | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """Indicates an HTTP protocol error.""" | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def __init__(self, url, errcode, errmsg, headers): | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |         Error.__init__(self) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self.url = url | 
					
						
							|  |  |  |         self.errcode = errcode | 
					
						
							|  |  |  |         self.errmsg = errmsg | 
					
						
							|  |  |  |         self.headers = headers | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return ( | 
					
						
							|  |  |  |             "<ProtocolError for %s: %s %s>" % | 
					
						
							|  |  |  |             (self.url, self.errcode, self.errmsg) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Indicates a broken XML-RPC response package.  This exception is | 
					
						
							|  |  |  | # raised by the unmarshalling layer, if the XML-RPC response is | 
					
						
							|  |  |  | # malformed. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class ResponseError(Error): | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     """Indicates a broken response package.""" | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Indicates an XML-RPC fault response package.  This exception is | 
					
						
							|  |  |  | # raised by the unmarshalling layer, if the XML-RPC response contains | 
					
						
							|  |  |  | # a fault string.  This exception can also used as a class, to | 
					
						
							|  |  |  | # generate a fault XML-RPC message. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param faultCode The XML-RPC fault code. | 
					
						
							|  |  |  | # @param faultString The XML-RPC fault string. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class Fault(Error): | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     """Indicates an XML-RPC fault package.""" | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def __init__(self, faultCode, faultString, **extra): | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |         Error.__init__(self) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self.faultCode = faultCode | 
					
						
							|  |  |  |         self.faultString = faultString | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return ( | 
					
						
							|  |  |  |             "<Fault %s: %s>" % | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |             (self.faultCode, repr(self.faultString)) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # Special values | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Wrapper for XML-RPC boolean values.  Use the xmlrpclib.True and | 
					
						
							|  |  |  | # xmlrpclib.False constants, or the xmlrpclib.boolean() function, to | 
					
						
							|  |  |  | # generate boolean XML-RPC values. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param value A boolean value.  Any true value is interpreted as True, | 
					
						
							|  |  |  | #              all other values are interpreted as False. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class Boolean: | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """Boolean-value wrapper.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Use True or False to generate a "boolean" XML-RPC value. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value = 0): | 
					
						
							|  |  |  |         self.value = operator.truth(value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def encode(self, out): | 
					
						
							|  |  |  |         out.write("<value><boolean>%d</boolean></value>\n" % self.value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __cmp__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, Boolean): | 
					
						
							|  |  |  |             other = other.value | 
					
						
							|  |  |  |         return cmp(self.value, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         if self.value: | 
					
						
							|  |  |  |             return "<Boolean True at %x>" % id(self) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return "<Boolean False at %x>" % id(self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __int__(self): | 
					
						
							|  |  |  |         return self.value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __nonzero__(self): | 
					
						
							|  |  |  |         return self.value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | True, False = Boolean(1), Boolean(0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Map true or false value to XML-RPC boolean values. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @def boolean(value) | 
					
						
							|  |  |  | # @param value A boolean value.  Any true value is mapped to True, | 
					
						
							|  |  |  | #              all other values are mapped to False. | 
					
						
							|  |  |  | # @return xmlrpclib.True or xmlrpclib.False. | 
					
						
							|  |  |  | # @see Boolean | 
					
						
							|  |  |  | # @see True | 
					
						
							|  |  |  | # @see False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def boolean(value, _truefalse=(False, True)): | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     """Convert any Python value to XML-RPC 'boolean'.""" | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     return _truefalse[operator.truth(value)] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## | 
					
						
							|  |  |  | # Wrapper for XML-RPC DateTime values.  This converts a time value to | 
					
						
							|  |  |  | # the format used by XML-RPC. | 
					
						
							|  |  |  | # <p> | 
					
						
							|  |  |  | # The value can be given as a string in the format | 
					
						
							|  |  |  | # "yyyymmddThh:mm:ss", as a 9-item time tuple (as returned by | 
					
						
							|  |  |  | # time.localtime()), or an integer value (as returned by time.time()). | 
					
						
							|  |  |  | # The wrapper uses time.localtime() to convert an integer to a time | 
					
						
							|  |  |  | # tuple. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param value The time, given as an ISO 8601 string, a time | 
					
						
							|  |  |  | #              tuple, or a integer time value. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class DateTime: | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     """DateTime wrapper for an ISO 8601 string or time tuple or
 | 
					
						
							|  |  |  |     localtime integer value to generate 'dateTime.iso8601' XML-RPC | 
					
						
							|  |  |  |     value. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, value=0): | 
					
						
							| 
									
										
										
										
											2001-08-23 20:04:33 +00:00
										 |  |  |         if not isinstance(value, StringType): | 
					
						
							|  |  |  |             if not isinstance(value, TupleType): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |                 if value == 0: | 
					
						
							|  |  |  |                     value = time.time() | 
					
						
							|  |  |  |                 value = time.localtime(value) | 
					
						
							|  |  |  |             value = time.strftime("%Y%m%dT%H:%M:%S", value) | 
					
						
							|  |  |  |         self.value = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __cmp__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, DateTime): | 
					
						
							|  |  |  |             other = other.value | 
					
						
							|  |  |  |         return cmp(self.value, other) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Get date/time value. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @return Date/time value, as an ISO 8601 string. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         return "<DateTime %s at %x>" % (repr(self.value), id(self)) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def decode(self, data): | 
					
						
							|  |  |  |         self.value = string.strip(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def encode(self, out): | 
					
						
							|  |  |  |         out.write("<value><dateTime.iso8601>") | 
					
						
							|  |  |  |         out.write(self.value) | 
					
						
							|  |  |  |         out.write("</dateTime.iso8601></value>\n") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | def _datetime(data): | 
					
						
							|  |  |  |     # decode xml element contents into a DateTime structure. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     value = DateTime() | 
					
						
							|  |  |  |     value.decode(data) | 
					
						
							|  |  |  |     return value | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Wrapper for binary data.  This can be used to transport any kind | 
					
						
							|  |  |  | # of binary data over XML-RPC, using BASE64 encoding. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param data An 8-bit string containing arbitrary data. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class Binary: | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """Wrapper for binary data.""" | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, data=None): | 
					
						
							|  |  |  |         self.data = data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Get buffer contents. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @return Buffer contents, as an 8-bit string. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __str__(self): | 
					
						
							|  |  |  |         return self.data or "" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def __cmp__(self, other): | 
					
						
							|  |  |  |         if isinstance(other, Binary): | 
					
						
							|  |  |  |             other = other.data | 
					
						
							|  |  |  |         return cmp(self.data, other) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def decode(self, data): | 
					
						
							|  |  |  |         import base64 | 
					
						
							|  |  |  |         self.data = base64.decodestring(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def encode(self, out): | 
					
						
							|  |  |  |         import base64, StringIO | 
					
						
							|  |  |  |         out.write("<value><base64>\n") | 
					
						
							|  |  |  |         base64.encode(StringIO.StringIO(self.data), out) | 
					
						
							|  |  |  |         out.write("</base64></value>\n") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | def _binary(data): | 
					
						
							|  |  |  |     # decode xml element contents into a Binary structure | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     value = Binary() | 
					
						
							|  |  |  |     value.decode(data) | 
					
						
							|  |  |  |     return value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WRAPPERS = DateTime, Binary, Boolean | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # XML parsers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     # optional xmlrpclib accelerator.  for more information on this | 
					
						
							|  |  |  |     # component, contact info@pythonware.com | 
					
						
							|  |  |  |     import _xmlrpclib | 
					
						
							|  |  |  |     FastParser = _xmlrpclib.Parser | 
					
						
							|  |  |  |     FastUnmarshaller = _xmlrpclib.Unmarshaller | 
					
						
							|  |  |  | except (AttributeError, ImportError): | 
					
						
							|  |  |  |     FastParser = FastUnmarshaller = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | try: | 
					
						
							|  |  |  |     import _xmlrpclib | 
					
						
							|  |  |  |     FastMarshaller = _xmlrpclib.Marshaller | 
					
						
							|  |  |  | except (AttributeError, ImportError): | 
					
						
							|  |  |  |     FastMarshaller = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # the SGMLOP parser is about 15x faster than Python's builtin | 
					
						
							|  |  |  | # XML parser.  SGMLOP sources can be downloaded from: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #     http://www.pythonware.com/products/xml/sgmlop.htm | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     import sgmlop | 
					
						
							|  |  |  |     if not hasattr(sgmlop, "XMLParser"): | 
					
						
							|  |  |  |         raise ImportError | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     SgmlopParser = None # sgmlop accelerator not available | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     class SgmlopParser: | 
					
						
							|  |  |  |         def __init__(self, target): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # setup callbacks | 
					
						
							|  |  |  |             self.finish_starttag = target.start | 
					
						
							|  |  |  |             self.finish_endtag = target.end | 
					
						
							|  |  |  |             self.handle_data = target.data | 
					
						
							|  |  |  |             self.handle_xml = target.xml | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # activate parser | 
					
						
							|  |  |  |             self.parser = sgmlop.XMLParser() | 
					
						
							|  |  |  |             self.parser.register(self) | 
					
						
							|  |  |  |             self.feed = self.parser.feed | 
					
						
							|  |  |  |             self.entity = { | 
					
						
							|  |  |  |                 "amp": "&", "gt": ">", "lt": "<", | 
					
						
							|  |  |  |                 "apos": "'", "quot": '"' | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def close(self): | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self.parser.close() | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 self.parser = self.feed = None # nuke circular reference | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def handle_proc(self, tag, attr): | 
					
						
							|  |  |  |             m = re.search("encoding\s*=\s*['\"]([^\"']+)[\"']", attr) | 
					
						
							|  |  |  |             if m: | 
					
						
							|  |  |  |                 self.handle_xml(m.group(1), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def handle_entityref(self, entity): | 
					
						
							|  |  |  |             # <string> entity | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self.handle_data(self.entity[entity]) | 
					
						
							|  |  |  |             except KeyError: | 
					
						
							|  |  |  |                 self.handle_data("&%s;" % entity) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | try: | 
					
						
							|  |  |  |     from xml.parsers import expat | 
					
						
							| 
									
										
										
										
											2001-10-02 18:33:11 +00:00
										 |  |  |     if not hasattr(expat, "ParserCreate"): | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         raise ImportError | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | except ImportError: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ExpatParser = None # expat not available | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | else: | 
					
						
							|  |  |  |     class ExpatParser: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         # fast expat parser for Python 2.0 and later.  this is about | 
					
						
							|  |  |  |         # 50% slower than sgmlop, on roundtrip testing | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         def __init__(self, target): | 
					
						
							|  |  |  |             self._parser = parser = expat.ParserCreate(None, None) | 
					
						
							|  |  |  |             self._target = target | 
					
						
							|  |  |  |             parser.StartElementHandler = target.start | 
					
						
							|  |  |  |             parser.EndElementHandler = target.end | 
					
						
							|  |  |  |             parser.CharacterDataHandler = target.data | 
					
						
							|  |  |  |             encoding = None | 
					
						
							|  |  |  |             if not parser.returns_unicode: | 
					
						
							|  |  |  |                 encoding = "utf-8" | 
					
						
							|  |  |  |             target.xml(encoding, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def feed(self, data): | 
					
						
							|  |  |  |             self._parser.Parse(data, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def close(self): | 
					
						
							|  |  |  |             self._parser.Parse("", 1) # end of data | 
					
						
							|  |  |  |             del self._target, self._parser # get rid of circular references | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  | class SlowParser: | 
					
						
							|  |  |  |     """Default XML parser (based on xmllib.XMLParser).""" | 
					
						
							|  |  |  |     # this is about 10 times slower than sgmlop, on roundtrip | 
					
						
							|  |  |  |     # testing. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def __init__(self, target): | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |         import xmllib # lazy subclassing (!) | 
					
						
							|  |  |  |         if xmllib.XMLParser not in SlowParser.__bases__: | 
					
						
							|  |  |  |             SlowParser.__bases__ = (xmllib.XMLParser,) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self.handle_xml = target.xml | 
					
						
							|  |  |  |         self.unknown_starttag = target.start | 
					
						
							|  |  |  |         self.handle_data = target.data | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         self.handle_cdata = target.data | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self.unknown_endtag = target.end | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             xmllib.XMLParser.__init__(self, accept_utf8=1) | 
					
						
							|  |  |  |         except TypeError: | 
					
						
							|  |  |  |             xmllib.XMLParser.__init__(self) # pre-2.0 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # XML-RPC marshalling and unmarshalling code | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # XML-RPC marshaller. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param encoding Default encoding for 8-bit strings.  The default | 
					
						
							|  |  |  | #     value is None (interpreted as UTF-8). | 
					
						
							|  |  |  | # @see dumps | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class Marshaller: | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """Generate an XML-RPC params chunk from a Python data structure.
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     Create a Marshaller instance for each set of parameters, and use | 
					
						
							|  |  |  |     the "dumps" method to convert your data (represented as a tuple) | 
					
						
							|  |  |  |     to an XML-RPC params chunk.  To write a fault response, pass a | 
					
						
							|  |  |  |     Fault instance instead.  You may prefer to use the "dumps" module | 
					
						
							|  |  |  |     function for this purpose. | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # by the way, if you don't understand what's going on in here, | 
					
						
							|  |  |  |     # that's perfectly ok. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, encoding=None): | 
					
						
							|  |  |  |         self.memo = {} | 
					
						
							|  |  |  |         self.data = None | 
					
						
							|  |  |  |         self.encoding = encoding | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dispatch = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def dumps(self, values): | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         out = [] | 
					
						
							|  |  |  |         write = out.append | 
					
						
							|  |  |  |         dump = self.__dump | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         if isinstance(values, Fault): | 
					
						
							|  |  |  |             # fault instance | 
					
						
							|  |  |  |             write("<fault>\n") | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             dump(vars(values), write) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             write("</fault>\n") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # parameter block | 
					
						
							| 
									
										
										
										
											2001-08-23 20:13:08 +00:00
										 |  |  |             # FIXME: the xml-rpc specification allows us to leave out | 
					
						
							|  |  |  |             # the entire <params> block if there are no parameters. | 
					
						
							|  |  |  |             # however, changing this may break older code (including | 
					
						
							|  |  |  |             # old versions of xmlrpclib.py), so this is better left as | 
					
						
							|  |  |  |             # is for now.  See @XMLRPC3 for more information. /F | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             write("<params>\n") | 
					
						
							|  |  |  |             for v in values: | 
					
						
							|  |  |  |                 write("<param>\n") | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |                 dump(v, write) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |                 write("</param>\n") | 
					
						
							|  |  |  |             write("</params>\n") | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         result = string.join(out, "") | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def __dump(self, value, write): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             f = self.dispatch[type(value)] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             raise TypeError, "cannot marshal %s objects" % type(value) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             f(self, value, write) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_int(self, value, write): | 
					
						
							| 
									
										
										
										
											2001-10-17 22:53:33 +00:00
										 |  |  |         # in case ints are > 32 bits | 
					
						
							|  |  |  |         if value > MAXINT or value < MININT: | 
					
						
							|  |  |  |             raise OverflowError, "int exceeds XML-RPC limits" | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         write("<value><int>") | 
					
						
							|  |  |  |         write(str(value)) | 
					
						
							|  |  |  |         write("</int></value>\n") | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     dispatch[IntType] = dump_int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_long(self, value, write): | 
					
						
							| 
									
										
										
										
											2001-10-17 22:53:33 +00:00
										 |  |  |         if value > MAXINT or value < MININT: | 
					
						
							|  |  |  |             raise OverflowError, "long int exceeds XML-RPC limits" | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         write("<value><int>") | 
					
						
							|  |  |  |         write(str(int(value))) | 
					
						
							|  |  |  |         write("</int></value>\n") | 
					
						
							| 
									
										
										
										
											2001-10-10 15:56:34 +00:00
										 |  |  |     dispatch[LongType] = dump_long | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_double(self, value, write): | 
					
						
							|  |  |  |         write("<value><double>") | 
					
						
							|  |  |  |         write(repr(value)) | 
					
						
							|  |  |  |         write("</double></value>\n") | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     dispatch[FloatType] = dump_double | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_string(self, value, write, escape=escape): | 
					
						
							|  |  |  |         write("<value><string>") | 
					
						
							|  |  |  |         write(escape(value)) | 
					
						
							|  |  |  |         write("</string></value>\n") | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     dispatch[StringType] = dump_string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if unicode: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         def dump_unicode(self, value, write, escape=escape): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             value = value.encode(self.encoding) | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             write("<value><string>") | 
					
						
							|  |  |  |             write(escape(value)) | 
					
						
							|  |  |  |             write("</string></value>\n") | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         dispatch[UnicodeType] = dump_unicode | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_array(self, value, write): | 
					
						
							|  |  |  |         i = id(value) | 
					
						
							|  |  |  |         if self.memo.has_key(i): | 
					
						
							|  |  |  |             raise TypeError, "cannot marshal recursive sequences" | 
					
						
							|  |  |  |         self.memo[i] = None | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |         dump = self.__dump | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         write("<value><array><data>\n") | 
					
						
							|  |  |  |         for v in value: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             dump(v, write) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         write("</data></array></value>\n") | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         del self.memo[i] | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     dispatch[TupleType] = dump_array | 
					
						
							|  |  |  |     dispatch[ListType] = dump_array | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_struct(self, value, write, escape=escape): | 
					
						
							|  |  |  |         i = id(value) | 
					
						
							|  |  |  |         if self.memo.has_key(i): | 
					
						
							|  |  |  |             raise TypeError, "cannot marshal recursive dictionaries" | 
					
						
							|  |  |  |         self.memo[i] = None | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |         dump = self.__dump | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         write("<value><struct>\n") | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         for k in value.keys(): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             write("<member>\n") | 
					
						
							|  |  |  |             if type(k) is not StringType: | 
					
						
							|  |  |  |                 raise TypeError, "dictionary key must be string" | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |             write("<name>%s</name>\n" % escape(k)) | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             dump(value[k], write) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             write("</member>\n") | 
					
						
							|  |  |  |         write("</struct></value>\n") | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         del self.memo[i] | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     dispatch[DictType] = dump_struct | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     def dump_instance(self, value, write): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         # check for special wrappers | 
					
						
							|  |  |  |         if value.__class__ in WRAPPERS: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             self.write = write | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             value.encode(self) | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             del self.write | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         else: | 
					
						
							|  |  |  |             # store instance attributes as a struct (really?) | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             self.dump_struct(value.__dict__, write) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     dispatch[InstanceType] = dump_instance | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # XML-RPC unmarshaller. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @see loads | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class Unmarshaller: | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """Unmarshal an XML-RPC response, based on incoming XML event
 | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |     messages (start, data, end).  Call close() to get the resulting | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     data structure. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |     Note that this reader is fairly tolerant, and gladly accepts bogus | 
					
						
							|  |  |  |     XML-RPC data without complaining (but not bogus XML). | 
					
						
							| 
									
										
										
										
											2001-09-04 18:55:03 +00:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # and again, if you don't understand what's going on in here, | 
					
						
							|  |  |  |     # that's perfectly ok. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self): | 
					
						
							|  |  |  |         self._type = None | 
					
						
							|  |  |  |         self._stack = [] | 
					
						
							|  |  |  |         self._marks = [] | 
					
						
							|  |  |  |         self._data = [] | 
					
						
							|  |  |  |         self._methodname = None | 
					
						
							|  |  |  |         self._encoding = "utf-8" | 
					
						
							|  |  |  |         self.append = self._stack.append | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         # return response tuple and target method | 
					
						
							|  |  |  |         if self._type is None or self._marks: | 
					
						
							|  |  |  |             raise ResponseError() | 
					
						
							|  |  |  |         if self._type == "fault": | 
					
						
							|  |  |  |             raise apply(Fault, (), self._stack[0]) | 
					
						
							|  |  |  |         return tuple(self._stack) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def getmethodname(self): | 
					
						
							|  |  |  |         return self._methodname | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # event handlers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def xml(self, encoding, standalone): | 
					
						
							|  |  |  |         self._encoding = encoding | 
					
						
							|  |  |  |         # FIXME: assert standalone == 1 ??? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def start(self, tag, attrs): | 
					
						
							|  |  |  |         # prepare to handle this element | 
					
						
							|  |  |  |         if tag == "array" or tag == "struct": | 
					
						
							|  |  |  |             self._marks.append(len(self._stack)) | 
					
						
							|  |  |  |         self._data = [] | 
					
						
							|  |  |  |         self._value = (tag == "value") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def data(self, text): | 
					
						
							|  |  |  |         self._data.append(text) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end(self, tag, join=string.join): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         # call the appropriate end tag handler | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             f = self.dispatch[tag] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             pass # unknown tag ? | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |             return f(self, join(self._data, "")) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # accelerator support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def end_dispatch(self, tag, data): | 
					
						
							|  |  |  |         # dispatch data | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             f = self.dispatch[tag] | 
					
						
							|  |  |  |         except KeyError: | 
					
						
							|  |  |  |             pass # unknown tag ? | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return f(self, data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # element decoders | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dispatch = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_boolean(self, data): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         if data == "0": | 
					
						
							|  |  |  |             self.append(False) | 
					
						
							|  |  |  |         elif data == "1": | 
					
						
							|  |  |  |             self.append(True) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             raise TypeError, "bad boolean value" | 
					
						
							|  |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["boolean"] = end_boolean | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_int(self, data): | 
					
						
							|  |  |  |         self.append(int(data)) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["i4"] = end_int | 
					
						
							|  |  |  |     dispatch["int"] = end_int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_double(self, data): | 
					
						
							|  |  |  |         self.append(float(data)) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["double"] = end_double | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_string(self, data): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         if self._encoding: | 
					
						
							|  |  |  |             data = _decode(data, self._encoding) | 
					
						
							|  |  |  |         self.append(_stringify(data)) | 
					
						
							|  |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["string"] = end_string | 
					
						
							|  |  |  |     dispatch["name"] = end_string # struct keys are always strings | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def end_array(self, data): | 
					
						
							| 
									
										
										
										
											2002-06-30 03:39:14 +00:00
										 |  |  |         mark = self._marks.pop() | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         # map arrays to Python lists | 
					
						
							|  |  |  |         self._stack[mark:] = [self._stack[mark:]] | 
					
						
							|  |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["array"] = end_array | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def end_struct(self, data): | 
					
						
							| 
									
										
										
										
											2002-06-30 03:39:14 +00:00
										 |  |  |         mark = self._marks.pop() | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         # map structs to Python dictionaries | 
					
						
							|  |  |  |         dict = {} | 
					
						
							|  |  |  |         items = self._stack[mark:] | 
					
						
							|  |  |  |         for i in range(0, len(items), 2): | 
					
						
							|  |  |  |             dict[_stringify(items[i])] = items[i+1] | 
					
						
							|  |  |  |         self._stack[mark:] = [dict] | 
					
						
							|  |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["struct"] = end_struct | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_base64(self, data): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         value = Binary() | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |         value.decode(data) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self.append(value) | 
					
						
							|  |  |  |         self._value = 0 | 
					
						
							|  |  |  |     dispatch["base64"] = end_base64 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_dateTime(self, data): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         value = DateTime() | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |         value.decode(data) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         self.append(value) | 
					
						
							|  |  |  |     dispatch["dateTime.iso8601"] = end_dateTime | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def end_value(self, data): | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         # if we stumble upon a value element with no internal | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         # elements, treat it as a string element | 
					
						
							|  |  |  |         if self._value: | 
					
						
							|  |  |  |             self.end_string(data) | 
					
						
							|  |  |  |     dispatch["value"] = end_value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def end_params(self, data): | 
					
						
							|  |  |  |         self._type = "params" | 
					
						
							|  |  |  |     dispatch["params"] = end_params | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def end_fault(self, data): | 
					
						
							|  |  |  |         self._type = "fault" | 
					
						
							|  |  |  |     dispatch["fault"] = end_fault | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-10-01 19:42:03 +00:00
										 |  |  |     def end_methodName(self, data): | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         if self._encoding: | 
					
						
							|  |  |  |             data = _decode(data, self._encoding) | 
					
						
							|  |  |  |         self._methodname = data | 
					
						
							|  |  |  |         self._type = "methodName" # no params | 
					
						
							|  |  |  |     dispatch["methodName"] = end_methodName | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # convenience functions | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Create a parser object, and connect it to an unmarshalling instance. | 
					
						
							|  |  |  | # This function picks the fastest available XML parser. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # return A (parser, unmarshaller) tuple. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | def getparser(): | 
					
						
							|  |  |  |     """getparser() -> parser, unmarshaller
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |     Create an instance of the fastest available parser, and attach it | 
					
						
							|  |  |  |     to an unmarshalling object.  Return both objects. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if FastParser and FastUnmarshaller: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         target = FastUnmarshaller(True, False, _binary, _datetime, Fault) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         parser = FastParser(target) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         target = Unmarshaller() | 
					
						
							|  |  |  |         if FastParser: | 
					
						
							|  |  |  |             parser = FastParser(target) | 
					
						
							|  |  |  |         elif SgmlopParser: | 
					
						
							|  |  |  |             parser = SgmlopParser(target) | 
					
						
							|  |  |  |         elif ExpatParser: | 
					
						
							|  |  |  |             parser = ExpatParser(target) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             parser = SlowParser(target) | 
					
						
							|  |  |  |     return parser, target | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Convert a Python tuple or a Fault instance to an XML-RPC packet. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @def dumps(params, **options) | 
					
						
							|  |  |  | # @param params A tuple or Fault instance. | 
					
						
							|  |  |  | # @keyparam methodname If given, create a methodCall request for | 
					
						
							|  |  |  | #     this method name. | 
					
						
							|  |  |  | # @keyparam methodresponse If given, create a methodResponse packet. | 
					
						
							|  |  |  | #     If used with a tuple, the tuple must be a singleton (that is, | 
					
						
							|  |  |  | #     it must contain exactly one element). | 
					
						
							|  |  |  | # @keyparam encoding The packet encoding. | 
					
						
							|  |  |  | # @return A string containing marshalled data. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | def dumps(params, methodname=None, methodresponse=None, encoding=None): | 
					
						
							|  |  |  |     """data [,options] -> marshalled data
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Convert an argument tuple or a Fault instance to an XML-RPC | 
					
						
							|  |  |  |     request (or response, if the methodresponse option is used). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |     In addition to the data object, the following options can be given | 
					
						
							|  |  |  |     as keyword arguments: | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         methodname: the method name for a methodCall packet | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         methodresponse: true to create a methodResponse packet. | 
					
						
							|  |  |  |         If this option is used with a tuple, the tuple must be | 
					
						
							|  |  |  |         a singleton (i.e. it can contain only one element). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         encoding: the packet encoding (default is UTF-8) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     All 8-bit strings in the data structure are assumed to use the | 
					
						
							|  |  |  |     packet encoding.  Unicode strings are automatically converted, | 
					
						
							| 
									
										
										
										
											2001-09-10 21:45:42 +00:00
										 |  |  |     where necessary. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assert isinstance(params, TupleType) or isinstance(params, Fault),\ | 
					
						
							|  |  |  |            "argument must be tuple or Fault instance" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if isinstance(params, Fault): | 
					
						
							|  |  |  |         methodresponse = 1 | 
					
						
							|  |  |  |     elif methodresponse and isinstance(params, TupleType): | 
					
						
							|  |  |  |         assert len(params) == 1, "response tuple must be a singleton" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     if not encoding: | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         encoding = "utf-8" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     if FastMarshaller: | 
					
						
							|  |  |  |         m = FastMarshaller(encoding) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         m = Marshaller(encoding) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     data = m.dumps(params) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if encoding != "utf-8": | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # standard XML-RPC wrappings | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     if methodname: | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         # a method call | 
					
						
							|  |  |  |         if not isinstance(methodname, StringType): | 
					
						
							|  |  |  |             methodname = methodname.encode(encoding) | 
					
						
							|  |  |  |         data = ( | 
					
						
							|  |  |  |             xmlheader, | 
					
						
							|  |  |  |             "<methodCall>\n" | 
					
						
							|  |  |  |             "<methodName>", methodname, "</methodName>\n", | 
					
						
							|  |  |  |             data, | 
					
						
							|  |  |  |             "</methodCall>\n" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |     elif methodresponse: | 
					
						
							|  |  |  |         # a method response, or a fault structure | 
					
						
							|  |  |  |         data = ( | 
					
						
							|  |  |  |             xmlheader, | 
					
						
							|  |  |  |             "<methodResponse>\n", | 
					
						
							|  |  |  |             data, | 
					
						
							|  |  |  |             "</methodResponse>\n" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return data # return as is | 
					
						
							|  |  |  |     return string.join(data, "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Convert an XML-RPC packet to a Python object.  If the XML-RPC packet | 
					
						
							|  |  |  | # represents a fault condition, this function raises a Fault exception. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @param data An XML-RPC packet, given as an 8-bit string. | 
					
						
							|  |  |  | # @return A tuple containing the the unpacked data, and the method name | 
					
						
							|  |  |  | #     (None if not present). | 
					
						
							|  |  |  | # @see Fault | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | def loads(data): | 
					
						
							|  |  |  |     """data -> unmarshalled data, method name
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Convert an XML-RPC packet to unmarshalled data plus a method | 
					
						
							|  |  |  |     name (None if not present). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     If the XML-RPC packet represents a fault condition, this function | 
					
						
							|  |  |  |     raises a Fault exception. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     import sys | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     p, u = getparser() | 
					
						
							|  |  |  |     p.feed(data) | 
					
						
							|  |  |  |     p.close() | 
					
						
							|  |  |  |     return u.close(), u.getmethodname() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # request dispatcher | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class _Method: | 
					
						
							|  |  |  |     # some magic to bind an XML-RPC method to an RPC server. | 
					
						
							|  |  |  |     # supports "nested" methods (e.g. examples.getStateName) | 
					
						
							|  |  |  |     def __init__(self, send, name): | 
					
						
							|  |  |  |         self.__send = send | 
					
						
							|  |  |  |         self.__name = name | 
					
						
							|  |  |  |     def __getattr__(self, name): | 
					
						
							|  |  |  |         return _Method(self.__send, "%s.%s" % (self.__name, name)) | 
					
						
							|  |  |  |     def __call__(self, *args): | 
					
						
							|  |  |  |         return self.__send(self.__name, args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Standard transport class for XML-RPC over HTTP. | 
					
						
							|  |  |  | # <p> | 
					
						
							|  |  |  | # You can create custom transports by subclassing this method, and | 
					
						
							|  |  |  | # overriding selected methods. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Transport: | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     """Handles an HTTP transaction to an XML-RPC server.""" | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # client identifier (may be overridden) | 
					
						
							|  |  |  |     user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Send a complete request, and parse the response. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param host Target host. | 
					
						
							|  |  |  |     # @param handler Target PRC handler. | 
					
						
							|  |  |  |     # @param request_body XML-RPC request body. | 
					
						
							|  |  |  |     # @param verbose Debugging flag. | 
					
						
							|  |  |  |     # @return Parsed response. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def request(self, host, handler, request_body, verbose=0): | 
					
						
							|  |  |  |         # issue XML-RPC request | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         h = self.make_connection(host) | 
					
						
							|  |  |  |         if verbose: | 
					
						
							|  |  |  |             h.set_debuglevel(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.send_request(h, handler, request_body) | 
					
						
							|  |  |  |         self.send_host(h, host) | 
					
						
							|  |  |  |         self.send_user_agent(h) | 
					
						
							|  |  |  |         self.send_content(h, request_body) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         errcode, errmsg, headers = h.getreply() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if errcode != 200: | 
					
						
							|  |  |  |             raise ProtocolError( | 
					
						
							|  |  |  |                 host + handler, | 
					
						
							|  |  |  |                 errcode, errmsg, | 
					
						
							|  |  |  |                 headers | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.verbose = verbose | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             sock = h._conn.sock | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             sock = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._parse_response(h.getfile(), sock) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ## | 
					
						
							|  |  |  |     # Create parser. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @return A 2-tuple containing a parser and a unmarshaller. | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     def getparser(self): | 
					
						
							|  |  |  |         # get parser and unmarshaller | 
					
						
							|  |  |  |         return getparser() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Connect to server. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param host Target host. | 
					
						
							|  |  |  |     # @return A connection handle. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def make_connection(self, host): | 
					
						
							|  |  |  |         # create a HTTP connection object from a host descriptor | 
					
						
							|  |  |  |         import httplib | 
					
						
							|  |  |  |         return httplib.HTTP(host) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Send request header. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param connection Connection handle. | 
					
						
							|  |  |  |     # @param handler Target RPC handler. | 
					
						
							|  |  |  |     # @param request_body XML-RPC body. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def send_request(self, connection, handler, request_body): | 
					
						
							|  |  |  |         connection.putrequest("POST", handler) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Send host name. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param connection Connection handle. | 
					
						
							|  |  |  |     # @param host Host name. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def send_host(self, connection, host): | 
					
						
							|  |  |  |         connection.putheader("Host", host) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Send user-agent identifier. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param connection Connection handle. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def send_user_agent(self, connection): | 
					
						
							|  |  |  |         connection.putheader("User-Agent", self.user_agent) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Send request body. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param connection Connection handle. | 
					
						
							|  |  |  |     # @param request_body XML-RPC request body. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def send_content(self, connection, request_body): | 
					
						
							|  |  |  |         connection.putheader("Content-Type", "text/xml") | 
					
						
							|  |  |  |         connection.putheader("Content-Length", str(len(request_body))) | 
					
						
							|  |  |  |         connection.endheaders() | 
					
						
							|  |  |  |         if request_body: | 
					
						
							|  |  |  |             connection.send(request_body) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     ## | 
					
						
							|  |  |  |     # Parse response. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param file Stream. | 
					
						
							|  |  |  |     # @return Response tuple and target method. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def parse_response(self, file): | 
					
						
							|  |  |  |         # compatibility interface | 
					
						
							|  |  |  |         return self._parse_response(file, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ## | 
					
						
							|  |  |  |     # Parse response (alternate interface).  This is similar to the | 
					
						
							|  |  |  |     # parse_response method, but also provides direct access to the | 
					
						
							|  |  |  |     # underlying socket object (where available). | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # @param file Stream. | 
					
						
							|  |  |  |     # @param sock Socket handle (or None, if the socket object | 
					
						
							|  |  |  |     #    could not be accessed). | 
					
						
							|  |  |  |     # @return Response tuple and target method. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _parse_response(self, file, sock): | 
					
						
							|  |  |  |         # read response from input file/socket, and parse it | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |         p, u = self.getparser() | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         while 1: | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |             if sock: | 
					
						
							|  |  |  |                 response = sock.recv(1024) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 response = file.read(1024) | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             if not response: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  |             if self.verbose: | 
					
						
							|  |  |  |                 print "body:", repr(response) | 
					
						
							|  |  |  |             p.feed(response) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |         file.close() | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         p.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return u.close() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Standard transport class for XML-RPC over HTTPS. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class SafeTransport(Transport): | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |     """Handles an HTTPS transaction to an XML-RPC server.""" | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  |     # FIXME: mostly untested | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |     def make_connection(self, host): | 
					
						
							|  |  |  |         # create a HTTPS connection object from a host descriptor | 
					
						
							|  |  |  |         # host may be a string, or a (host, x509-dict) tuple | 
					
						
							|  |  |  |         import httplib | 
					
						
							|  |  |  |         if isinstance(host, TupleType): | 
					
						
							|  |  |  |             host, x509 = host | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             x509 = {} | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             HTTPS = httplib.HTTPS | 
					
						
							|  |  |  |         except AttributeError: | 
					
						
							|  |  |  |             raise NotImplementedError,\ | 
					
						
							|  |  |  |                   "your version of httplib doesn't support HTTPS" | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             return apply(HTTPS, (host, None), x509) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def send_host(self, connection, host): | 
					
						
							|  |  |  |         if isinstance(host, TupleType): | 
					
						
							|  |  |  |             host, x509 = host | 
					
						
							|  |  |  |         connection.putheader("Host", host) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | ## | 
					
						
							|  |  |  | # Standard server proxy.  This class establishes a virtual connection | 
					
						
							|  |  |  | # to an XML-RPC server. | 
					
						
							|  |  |  | # <p> | 
					
						
							|  |  |  | # This class is available as ServerProxy and Server.  New code should | 
					
						
							|  |  |  | # use ServerProxy, to avoid confusion. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # @def ServerProxy(uri, **options) | 
					
						
							|  |  |  | # @param uri The connection point on the server. | 
					
						
							|  |  |  | # @keyparam transport A transport factory, compatible with the | 
					
						
							|  |  |  | #    standard transport class. | 
					
						
							|  |  |  | # @keyparam encoding The default encoding used for 8-bit strings | 
					
						
							|  |  |  | #    (default is UTF-8). | 
					
						
							|  |  |  | # @keyparam verbose Use a true value to enable debugging output. | 
					
						
							|  |  |  | #    (printed to standard output). | 
					
						
							|  |  |  | # @see Transport | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | class ServerProxy: | 
					
						
							|  |  |  |     """uri [,options] -> a logical connection to an XML-RPC server
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uri is the connection point on the server, given as | 
					
						
							|  |  |  |     scheme://host/target. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The standard implementation always supports the "http" scheme.  If | 
					
						
							|  |  |  |     SSL socket support is available (Python 2.0), it also supports | 
					
						
							|  |  |  |     "https". | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     If the target part and the slash preceding it are both omitted, | 
					
						
							|  |  |  |     "/RPC2" is assumed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The following options can be given as keyword arguments: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         transport: a transport factory | 
					
						
							|  |  |  |         encoding: the request encoding (default is UTF-8) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     All 8-bit strings passed to the server proxy are assumed to use | 
					
						
							|  |  |  |     the given encoding. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, uri, transport=None, encoding=None, verbose=0): | 
					
						
							|  |  |  |         # establish a "logical" server connection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # get the url | 
					
						
							| 
									
										
										
										
											2001-09-10 19:45:02 +00:00
										 |  |  |         import urllib | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |         type, uri = urllib.splittype(uri) | 
					
						
							|  |  |  |         if type not in ("http", "https"): | 
					
						
							|  |  |  |             raise IOError, "unsupported XML-RPC protocol" | 
					
						
							|  |  |  |         self.__host, self.__handler = urllib.splithost(uri) | 
					
						
							|  |  |  |         if not self.__handler: | 
					
						
							|  |  |  |             self.__handler = "/RPC2" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if transport is None: | 
					
						
							|  |  |  |             if type == "https": | 
					
						
							|  |  |  |                 transport = SafeTransport() | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 transport = Transport() | 
					
						
							|  |  |  |         self.__transport = transport | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.__encoding = encoding | 
					
						
							|  |  |  |         self.__verbose = verbose | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __request(self, methodname, params): | 
					
						
							|  |  |  |         # call a method on the remote server | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         request = dumps(params, methodname, encoding=self.__encoding) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         response = self.__transport.request( | 
					
						
							|  |  |  |             self.__host, | 
					
						
							|  |  |  |             self.__handler, | 
					
						
							|  |  |  |             request, | 
					
						
							|  |  |  |             verbose=self.__verbose | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if len(response) == 1: | 
					
						
							|  |  |  |             response = response[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return ( | 
					
						
							| 
									
										
										
										
											2001-08-23 20:04:33 +00:00
										 |  |  |             "<ServerProxy for %s%s>" % | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  |             (self.__host, self.__handler) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __str__ = __repr__ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __getattr__(self, name): | 
					
						
							|  |  |  |         # magic method dispatcher | 
					
						
							|  |  |  |         return _Method(self.__request, name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # note: to call a remote object with an non-standard name, use | 
					
						
							|  |  |  |     # result getattr(server, "strange-python-name")(args) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-23 20:04:33 +00:00
										 |  |  | # compatibility | 
					
						
							| 
									
										
										
										
											2002-06-27 21:36:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | Server = ServerProxy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -------------------------------------------------------------------- | 
					
						
							|  |  |  | # test code | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # simple test program (from the XML-RPC specification) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-23 20:04:33 +00:00
										 |  |  |     # server = ServerProxy("http://localhost:8000") # local server | 
					
						
							|  |  |  |     server = ServerProxy("http://betty.userland.com") | 
					
						
							| 
									
										
										
										
											2001-07-11 17:42:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     print server | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         print server.examples.getStateName(41) | 
					
						
							|  |  |  |     except Error, v: | 
					
						
							|  |  |  |         print "ERROR", v |