Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
xmlrpclib.py
Go to the documentation of this file.
1 #
2 # XML-RPC CLIENT LIBRARY
3 # $Id: xmlrpclib.py 5816 2003-05-28 07:38:37Z hellcatv $
4 #
5 # an XML-RPC client interface for Python.
6 #
7 # the marshalling and response parser code can also be used to
8 # implement XML-RPC servers.
9 #
10 # Notes:
11 # this version is designed to work with Python 1.5.2 or newer.
12 # unicode encoding support requires at least Python 1.6.
13 # experimental HTTPS requires Python 2.0 built with SSL sockets.
14 # expat parser support requires Python 2.0 with pyexpat support.
15 #
16 # History:
17 # 1999-01-14 fl Created
18 # 1999-01-15 fl Changed dateTime to use localtime
19 # 1999-01-16 fl Added Binary/base64 element, default to RPC2 service
20 # 1999-01-19 fl Fixed array data element (from Skip Montanaro)
21 # 1999-01-21 fl Fixed dateTime constructor, etc.
22 # 1999-02-02 fl Added fault handling, handle empty sequences, etc.
23 # 1999-02-10 fl Fixed problem with empty responses (from Skip Montanaro)
24 # 1999-06-20 fl Speed improvements, pluggable parsers/transports (0.9.8)
25 # 2000-11-28 fl Changed boolean to check the truth value of its argument
26 # 2001-02-24 fl Added encoding/Unicode/SafeTransport patches
27 # 2001-02-26 fl Added compare support to wrappers (0.9.9/1.0b1)
28 # 2001-03-28 fl Make sure response tuple is a singleton
29 # 2001-03-29 fl Don't require empty params element (from Nicholas Riley)
30 # 2001-06-10 fl Folded in _xmlrpclib accelerator support (1.0b2)
31 # 2001-08-20 fl Base xmlrpclib.Error on built-in Exception (from Paul Prescod)
32 # 2001-09-03 fl Allow Transport subclass to override getparser
33 # 2001-09-10 fl Lazy import of urllib, cgi, xmllib (20x import speedup)
34 # 2001-10-01 fl Remove containers from memo cache when done with them
35 # 2001-10-01 fl Use faster escape method (80% dumps speedup)
36 # 2001-10-10 sm Allow long ints to be passed as ints if they don't overflow
37 # 2001-10-17 sm test for int and long overflow (allows use on 64-bit systems)
38 # 2001-11-12 fl Use repr() to marshal doubles (from Paul Felix)
39 #
40 # Copyright (c) 1999-2001 by Secret Labs AB.
41 # Copyright (c) 1999-2001 by Fredrik Lundh.
42 #
43 # info@pythonware.com
44 # http://www.pythonware.com
45 #
46 # --------------------------------------------------------------------
47 # The XML-RPC client interface is
48 #
49 # Copyright (c) 1999-2001 by Secret Labs AB
50 # Copyright (c) 1999-2001 by Fredrik Lundh
51 #
52 # By obtaining, using, and/or copying this software and/or its
53 # associated documentation, you agree that you have read, understood,
54 # and will comply with the following terms and conditions:
55 #
56 # Permission to use, copy, modify, and distribute this software and
57 # its associated documentation for any purpose and without fee is
58 # hereby granted, provided that the above copyright notice appears in
59 # all copies, and that both that copyright notice and this permission
60 # notice appear in supporting documentation, and that the name of
61 # Secret Labs AB or the author not be used in advertising or publicity
62 # pertaining to distribution of the software without specific, written
63 # prior permission.
64 #
65 # SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
66 # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
67 # ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
68 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
69 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
70 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
71 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
72 # OF THIS SOFTWARE.
73 # --------------------------------------------------------------------
74 
75 #
76 # things to look into:
77 
78 # TODO: support basic authentication (see robin's patch)
79 # TODO: fix host tuple handling in the server constructor
80 # TODO: let transport verify schemes
81 # TODO: update documentation
82 # TODO: authentication plugins
83 
84 """
85 An XML-RPC client interface for Python.
86 
87 The marshalling and response parser code can also be used to
88 implement XML-RPC servers.
89 
90 Exported exceptions:
91 
92  Error Base class for client errors
93  ProtocolError Indicates an HTTP protocol error
94  ResponseError Indicates a broken response package
95  Fault Indicates an XML-RPC fault package
96 
97 Exported classes:
98 
99  ServerProxy Represents a logical connection to an XML-RPC server
100 
101  Boolean boolean wrapper to generate a "boolean" XML-RPC value
102  DateTime dateTime wrapper for an ISO 8601 string or time tuple or
103  localtime integer value to generate a "dateTime.iso8601"
104  XML-RPC value
105  Binary binary data wrapper
106 
107  SlowParser Slow but safe standard parser (based on xmllib)
108  Marshaller Generate an XML-RPC params chunk from a Python data structure
109  Unmarshaller Unmarshal an XML-RPC response from incoming XML event message
110  Transport Handles an HTTP transaction to an XML-RPC server
111  SafeTransport Handles an HTTPS transaction to an XML-RPC server
112 
113 Exported constants:
114 
115  True
116  False
117 
118 Exported functions:
119 
120  boolean Convert any Python value to an XML-RPC boolean
121  getparser Create instance of the fastest available parser & attach
122  to an unmarshalling object
123  dumps Convert an argument tuple or a Fault instance to an XML-RPC
124  request (or response, if the methodresponse option is used).
125  loads Convert an XML-RPC packet to unmarshalled data plus a method
126  name (None if not present).
127 """
128 
129 import re, string, time, operator
130 
131 from types import *
132 
133 try:
134  unicode
135 except NameError:
136  unicode = None # unicode support not available
137 
138 def _decode(data, encoding, is8bit=re.compile("[\x80-\xff]").search):
139  # decode non-ascii string (if possible)
140  if unicode and encoding and is8bit(data):
141  data = unicode(data, encoding)
142  return data
143 
144 def escape(s, replace=string.replace):
145  s = replace(s, "&", "&")
146  s = replace(s, "<", "&lt;")
147  return replace(s, ">", "&gt;",)
148 
149 MAXINT = 2L**31-1
150 MININT = -2L**31
151 
152 if unicode:
153  def _stringify(string):
154  # convert to 7-bit ascii if possible
155  try:
156  return str(string)
157  except UnicodeError:
158  return string
159 else:
160  def _stringify(string):
161  return string
162 
163 __version__ = "1.0.0"
164 
165 # --------------------------------------------------------------------
166 # Exceptions
167 
168 class Error(Exception):
169  """Base class for client errors."""
170  def __str__(self):
171  return repr(self)
172 
174  """Indicates an HTTP protocol error."""
175  def __init__(self, url, errcode, errmsg, headers):
176  Error.__init__(self)
177  self.url = url
178  self.errcode = errcode
179  self.errmsg = errmsg
180  self.headers = headers
181  def __repr__(self):
182  return (
183  "<ProtocolError for %s: %s %s>" %
184  (self.url, self.errcode, self.errmsg)
185  )
186 
188  """Indicates a broken response package."""
189  pass
190 
191 class Fault(Error):
192  """Indicates an XML-RPC fault package."""
193  def __init__(self, faultCode, faultString, **extra):
194  Error.__init__(self)
195  self.faultCode = faultCode
196  self.faultString = faultString
197  def __repr__(self):
198  return (
199  "<Fault %s: %s>" %
200  (self.faultCode, repr(self.faultString))
201  )
202 
203 # --------------------------------------------------------------------
204 # Special values
205 
206 class Boolean:
207  """Boolean-value wrapper.
208 
209  Use True or False to generate a "boolean" XML-RPC value.
210  """
211 
212  def __init__(self, value = 0):
213  self.value = operator.truth(value)
214 
215  def encode(self, out):
216  out.write("<value><boolean>%d</boolean></value>\n" % self.value)
217 
218  def __cmp__(self, other):
219  if isinstance(other, Boolean):
220  other = other.value
221  return cmp(self.value, other)
222 
223  def __repr__(self):
224  if self.value:
225  return "<Boolean True at %x>" % id(self)
226  else:
227  return "<Boolean False at %x>" % id(self)
228 
229  def __int__(self):
230  return self.value
231 
232  def __nonzero__(self):
233  return self.value
234 
235 True, False = Boolean(1), Boolean(0)
236 
237 def boolean(value, truefalse=(False, True)):
238  """Convert any Python value to XML-RPC 'boolean'."""
239  return truefalse[operator.truth(value)]
240 
241 class DateTime:
242  """DateTime wrapper for an ISO 8601 string or time tuple or
243  localtime integer value to generate 'dateTime.iso8601' XML-RPC
244  value.
245  """
246 
247  def __init__(self, value=0):
248  if not isinstance(value, StringType):
249  if not isinstance(value, TupleType):
250  if value == 0:
251  value = time.time()
252  value = time.localtime(value)
253  value = time.strftime("%Y%m%dT%H:%M:%S", value)
254  self.value = value
255 
256  def __cmp__(self, other):
257  if isinstance(other, DateTime):
258  other = other.value
259  return cmp(self.value, other)
260 
261  def __repr__(self):
262  return "<DateTime %s at %x>" % (self.value, id(self))
263 
264  def decode(self, data):
265  self.value = string.strip(data)
266 
267  def encode(self, out):
268  out.write("<value><dateTime.iso8601>")
269  out.write(self.value)
270  out.write("</dateTime.iso8601></value>\n")
271 
272 def datetime(data):
273  value = DateTime()
274  value.decode(data)
275  return value
276 
277 class Binary:
278  """Wrapper for binary data."""
279 
280  def __init__(self, data=None):
281  self.data = data
282 
283  def __cmp__(self, other):
284  if isinstance(other, Binary):
285  other = other.data
286  return cmp(self.data, other)
287 
288  def decode(self, data):
289  import base64
290  self.data = base64.decodestring(data)
291 
292  def encode(self, out):
293  import base64, StringIO
294  out.write("<value><base64>\n")
296  out.write("</base64></value>\n")
297 
298 def binary(data):
299  value = Binary()
300  value.decode(data)
301  return value
302 
303 WRAPPERS = DateTime, Binary, Boolean
304 
305 # --------------------------------------------------------------------
306 # XML parsers
307 
308 try:
309  # optional xmlrpclib accelerator. for more information on this
310  # component, contact info@pythonware.com
311  import _xmlrpclib
312  FastParser = _xmlrpclib.Parser
313  FastUnmarshaller = _xmlrpclib.Unmarshaller
314 except (AttributeError, ImportError):
315  FastParser = FastUnmarshaller = None
316 
317 #
318 # the SGMLOP parser is about 15x faster than Python's builtin
319 # XML parser. SGMLOP sources can be downloaded from:
320 #
321 # http://www.pythonware.com/products/xml/sgmlop.htm
322 #
323 
324 try:
325  import sgmlop
326  if not hasattr(sgmlop, "XMLParser"):
327  raise ImportError
328 except ImportError:
329  SgmlopParser = None # sgmlop accelerator not available
330 else:
332  def __init__(self, target):
333 
334  # setup callbacks
335  self.finish_starttag = target.start
336  self.finish_endtag = target.end
337  self.handle_data = target.data
338  self.handle_xml = target.xml
339 
340  # activate parser
341  self.parser = sgmlop.XMLParser()
342  self.parser.register(self)
343  self.feed = self.parser.feed
344  self.entity = {
345  "amp": "&", "gt": ">", "lt": "<",
346  "apos": "'", "quot": '"'
347  }
348 
349  def close(self):
350  try:
351  self.parser.close()
352  finally:
353  self.parser = self.feed = None # nuke circular reference
354 
355  def handle_proc(self, tag, attr):
356  import re
357  m = re.search("encoding\s*=\s*['\"]([^\"']+)[\"']", attr)
358  if m:
359  self.handle_xml(m.group(1), 1)
360 
361  def handle_entityref(self, entity):
362  # <string> entity
363  try:
364  self.handle_data(self.entity[entity])
365  except KeyError:
366  self.handle_data("&%s;" % entity)
367 
368 try:
369  from xml.parsers import expat
370  if not hasattr(expat, "ParserCreate"):
371  raise ImportError, "ParserCreate"
372 except ImportError:
373  ExpatParser = None
374 else:
375  class ExpatParser:
376  # fast expat parser for Python 2.0. this is about 50%
377  # slower than sgmlop, on roundtrip testing
378  def __init__(self, target):
379  self._parser = parser = expat.ParserCreate(None, None)
380  self._target = target
381  parser.StartElementHandler = target.start
382  parser.EndElementHandler = target.end
383  parser.CharacterDataHandler = target.data
384  encoding = None
385  if not parser.returns_unicode:
386  encoding = "utf-8"
387  target.xml(encoding, None)
388 
389  def feed(self, data):
390  self._parser.Parse(data, 0)
391 
392  def close(self):
393  self._parser.Parse("", 1) # end of data
394  del self._target, self._parser # get rid of circular references
395 
397  """Default XML parser (based on xmllib.XMLParser)."""
398  # this is about 10 times slower than sgmlop, on roundtrip
399  # testing.
400  def __init__(self, target):
401  import xmllib # lazy subclassing (!)
402  if xmllib.XMLParser not in SlowParser.__bases__:
403  SlowParser.__bases__ = (xmllib.XMLParser,)
404  self.handle_xml = target.xml
405  self.unknown_starttag = target.start
406  self.handle_data = target.data
407  self.unknown_endtag = target.end
408  try:
409  xmllib.XMLParser.__init__(self, accept_utf8=1)
410  except TypeError:
411  xmllib.XMLParser.__init__(self) # pre-2.0
412 
413 # --------------------------------------------------------------------
414 # XML-RPC marshalling and unmarshalling code
415 
417  """Generate an XML-RPC params chunk from a Python data structure.
418 
419  Create a Marshaller instance for each set of parameters, and use
420  the "dumps" method to convert your data (represented as a tuple)
421  to an XML-RPC params chunk. To write a fault response, pass a
422  Fault instance instead. You may prefer to use the "dumps" module
423  function for this purpose.
424  """
425 
426  # by the way, if you don't understand what's going on in here,
427  # that's perfectly ok.
428 
429  def __init__(self, encoding=None):
430  self.memo = {}
431  self.data = None
432  self.encoding = encoding
433 
434  dispatch = {}
435 
436  def dumps(self, values):
437  self.__out = []
438  self.write = write = self.__out.append
439  if isinstance(values, Fault):
440  # fault instance
441  write("<fault>\n")
442  self.__dump(vars(values))
443  write("</fault>\n")
444  else:
445  # parameter block
446  # FIXME: the xml-rpc specification allows us to leave out
447  # the entire <params> block if there are no parameters.
448  # however, changing this may break older code (including
449  # old versions of xmlrpclib.py), so this is better left as
450  # is for now. See @XMLRPC3 for more information. /F
451  write("<params>\n")
452  for v in values:
453  write("<param>\n")
454  self.__dump(v)
455  write("</param>\n")
456  write("</params>\n")
457  result = string.join(self.__out, "")
458  del self.__out, self.write # don't need this any more
459  return result
460 
461  def __dump(self, value):
462  try:
463  f = self.dispatch[type(value)]
464  except KeyError:
465  raise TypeError, "cannot marshal %s objects" % type(value)
466  else:
467  f(self, value)
468 
469  def dump_int(self, value):
470  # in case ints are > 32 bits
471  if value > MAXINT or value < MININT:
472  raise OverflowError, "int exceeds XML-RPC limits"
473  self.write("<value><int>%s</int></value>\n" % value)
474  dispatch[IntType] = dump_int
475 
476  def dump_long(self, value):
477  # in case ints are > 32 bits
478  if value > MAXINT or value < MININT:
479  raise OverflowError, "long int exceeds XML-RPC limits"
480  self.write("<value><int>%s</int></value>\n" % int(value))
481  dispatch[LongType] = dump_long
482 
483  def dump_double(self, value):
484  self.write("<value><double>%s</double></value>\n" % repr(value))
485  dispatch[FloatType] = dump_double
486 
487  def dump_string(self, value, escape=escape):
488  self.write("<value><string>%s</string></value>\n" % escape(value))
489  dispatch[StringType] = dump_string
490 
491  if unicode:
492  def dump_unicode(self, value, escape=escape):
493  value = value.encode(self.encoding)
494  self.write("<value><string>%s</string></value>\n" % escape(value))
495  dispatch[UnicodeType] = dump_unicode
496 
497  def opencontainer(self, value):
498  if value:
499  i = id(value)
500  if self.memo.has_key(i):
501  raise TypeError, "cannot marshal recursive data structures"
502  self.memo[i] = None
503 
504  def closecontainer(self, value):
505  if value:
506  del self.memo[id(value)]
507 
508  def dump_array(self, value):
509  self.opencontainer(value)
510  write = self.write
511  dump = self.__dump
512  write("<value><array><data>\n")
513  for v in value:
514  dump(v)
515  write("</data></array></value>\n")
516  self.closecontainer(value)
517  dispatch[TupleType] = dump_array
518  dispatch[ListType] = dump_array
519 
520  def dump_struct(self, value, escape=escape):
521  self.opencontainer(value)
522  write = self.write
523  dump = self.__dump
524  write("<value><struct>\n")
525  for k, v in value.items():
526  write("<member>\n")
527  if type(k) is not StringType:
528  raise TypeError, "dictionary key must be string"
529  write("<name>%s</name>\n" % escape(k))
530  dump(v)
531  write("</member>\n")
532  write("</struct></value>\n")
533  self.closecontainer(value)
534  dispatch[DictType] = dump_struct
535 
536  def dump_instance(self, value):
537  # check for special wrappers
538  if value.__class__ in WRAPPERS:
539  value.encode(self)
540  else:
541  # store instance attributes as a struct (really?)
542  self.dump_struct(value.__dict__)
543  dispatch[InstanceType] = dump_instance
544 
546  """Unmarshal an XML-RPC response, based on incoming XML event
547  messages (start, data, end). Call close() to get the resulting
548  data structure.
549 
550  Note that this reader is fairly tolerant, and gladly accepts bogus
551  XML-RPC data without complaining (but not bogus XML).
552  """
553 
554  # and again, if you don't understand what's going on in here,
555  # that's perfectly ok.
556 
557  def __init__(self):
558  self._type = None
559  self._stack = []
560  self._marks = []
561  self._data = []
562  self._methodname = None
563  self._encoding = "utf-8"
564  self.append = self._stack.append
565 
566  def close(self):
567  # return response tuple and target method
568  if self._type is None or self._marks:
569  raise ResponseError()
570  if self._type == "fault":
571  raise apply(Fault, (), self._stack[0])
572  return tuple(self._stack)
573 
574  def getmethodname(self):
575  return self._methodname
576 
577  #
578  # event handlers
579 
580  def xml(self, encoding, standalone):
581  self._encoding = encoding
582  # FIXME: assert standalone == 1 ???
583 
584  def start(self, tag, attrs):
585  # prepare to handle this element
586  if tag == "array" or tag == "struct":
587  self._marks.append(len(self._stack))
588  self._data = []
589  self._value = (tag == "value")
590 
591  def data(self, text):
592  self._data.append(text)
593 
594  def end(self, tag, join=string.join):
595  # call the appropriate end tag handler
596  try:
597  f = self.dispatch[tag]
598  except KeyError:
599  pass # unknown tag ?
600  else:
601  return f(self, join(self._data, ""))
602 
603  #
604  # accelerator support
605 
606  def end_dispatch(self, tag, data):
607  # dispatch data
608  try:
609  f = self.dispatch[tag]
610  except KeyError:
611  pass # unknown tag ?
612  else:
613  return f(self, data)
614 
615  #
616  # element decoders
617 
618  dispatch = {}
619 
620  def end_boolean(self, data):
621  if data == "0":
622  self.append(False)
623  elif data == "1":
624  self.append(True)
625  else:
626  raise TypeError, "bad boolean value"
627  self._value = 0
628  dispatch["boolean"] = end_boolean
629 
630  def end_int(self, data):
631  self.append(int(data))
632  self._value = 0
633  dispatch["i4"] = end_int
634  dispatch["int"] = end_int
635 
636  def end_double(self, data):
637  self.append(float(data))
638  self._value = 0
639  dispatch["double"] = end_double
640 
641  def end_string(self, data):
642  if self._encoding:
643  data = _decode(data, self._encoding)
644  self.append(_stringify(data))
645  self._value = 0
646  dispatch["string"] = end_string
647  dispatch["name"] = end_string # struct keys are always strings
648 
649  def end_array(self, data):
650  mark = self._marks[-1]
651  del self._marks[-1]
652  # map arrays to Python lists
653  self._stack[mark:] = [self._stack[mark:]]
654  self._value = 0
655  dispatch["array"] = end_array
656 
657  def end_struct(self, data):
658  mark = self._marks[-1]
659  del self._marks[-1]
660  # map structs to Python dictionaries
661  dict = {}
662  items = self._stack[mark:]
663  for i in range(0, len(items), 2):
664  dict[_stringify(items[i])] = items[i+1]
665  self._stack[mark:] = [dict]
666  self._value = 0
667  dispatch["struct"] = end_struct
668 
669  def end_base64(self, data):
670  value = Binary()
671  value.decode(data)
672  self.append(value)
673  self._value = 0
674  dispatch["base64"] = end_base64
675 
676  def end_dateTime(self, data):
677  value = DateTime()
678  value.decode(data)
679  self.append(value)
680  dispatch["dateTime.iso8601"] = end_dateTime
681 
682  def end_value(self, data):
683  # if we stumble upon an value element with no internal
684  # elements, treat it as a string element
685  if self._value:
686  self.end_string(data)
687  dispatch["value"] = end_value
688 
689  def end_params(self, data):
690  self._type = "params"
691  dispatch["params"] = end_params
692 
693  def end_fault(self, data):
694  self._type = "fault"
695  dispatch["fault"] = end_fault
696 
697  def end_methodName(self, data):
698  if self._encoding:
699  data = _decode(data, self._encoding)
700  self._methodname = data
701  self._type = "methodName" # no params
702  dispatch["methodName"] = end_methodName
703 
704 
705 # --------------------------------------------------------------------
706 # convenience functions
707 
708 def getparser():
709  """getparser() -> parser, unmarshaller
710 
711  Create an instance of the fastest available parser, and attach it
712  to an unmarshalling object. Return both objects.
713  """
714  if FastParser and FastUnmarshaller:
715  target = FastUnmarshaller(True, False, binary, datetime)
716  parser = FastParser(target)
717  else:
718  target = Unmarshaller()
719  if FastParser:
720  parser = FastParser(target)
721  elif SgmlopParser:
722  parser = SgmlopParser(target)
723  elif ExpatParser:
724  parser = ExpatParser(target)
725  else:
726  parser = SlowParser(target)
727  return parser, target
728 
729 def dumps(params, methodname=None, methodresponse=None, encoding=None):
730  """data [,options] -> marshalled data
731 
732  Convert an argument tuple or a Fault instance to an XML-RPC
733  request (or response, if the methodresponse option is used).
734 
735  In addition to the data object, the following options can be given
736  as keyword arguments:
737 
738  methodname: the method name for a methodCall packet
739 
740  methodresponse: true to create a methodResponse packet.
741  If this option is used with a tuple, the tuple must be
742  a singleton (i.e. it can contain only one element).
743 
744  encoding: the packet encoding (default is UTF-8)
745 
746  All 8-bit strings in the data structure are assumed to use the
747  packet encoding. Unicode strings are automatically converted,
748  where necessary.
749  """
750 
751  assert isinstance(params, TupleType) or isinstance(params, Fault),\
752  "argument must be tuple or Fault instance"
753 
754  if isinstance(params, Fault):
755  methodresponse = 1
756  elif methodresponse and isinstance(params, TupleType):
757  assert len(params) == 1, "response tuple must be a singleton"
758 
759  if not encoding:
760  encoding = "utf-8"
761 
762  m = Marshaller(encoding)
763  data = m.dumps(params)
764 
765  if encoding != "utf-8":
766  xmlheader = "<?xml version='1.0' encoding=%s?>\n" % repr(encoding)
767  else:
768  xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
769 
770  # standard XML-RPC wrappings
771  if methodname:
772  # a method call
773  if not isinstance(methodname, StringType):
774  methodname = methodname.encode(encoding)
775  data = (
776  xmlheader,
777  "<methodCall>\n"
778  "<methodName>", methodname, "</methodName>\n",
779  data,
780  "</methodCall>\n"
781  )
782  elif methodresponse:
783  # a method response, or a fault structure
784  data = (
785  xmlheader,
786  "<methodResponse>\n",
787  data,
788  "</methodResponse>\n"
789  )
790  else:
791  return data # return as is
792  return string.join(data, "")
793 
794 def loads(data):
795  """data -> unmarshalled data, method name
796 
797  Convert an XML-RPC packet to unmarshalled data plus a method
798  name (None if not present).
799 
800  If the XML-RPC packet represents a fault condition, this function
801  raises a Fault exception.
802  """
803  p, u = getparser()
804  p.feed(data)
805  p.close()
806  return u.close(), u.getmethodname()
807 
808 
809 # --------------------------------------------------------------------
810 # request dispatcher
811 
812 class _Method:
813  # some magic to bind an XML-RPC method to an RPC server.
814  # supports "nested" methods (e.g. examples.getStateName)
815  def __init__(self, send, name):
816  self.__send = send
817  self.__name = name
818  def __getattr__(self, name):
819  return _Method(self.__send, "%s.%s" % (self.__name, name))
820  def __call__(self, *args):
821  return self.__send(self.__name, args)
822 
823 
824 class Transport:
825  """Handles an HTTP transaction to an XML-RPC server."""
826 
827  # client identifier (may be overridden)
828  user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
829 
830  def request(self, host, handler, request_body, verbose=0):
831  # issue XML-RPC request
832 
833  h = self.make_connection(host)
834  if verbose:
835  h.set_debuglevel(1)
836 
837  self.send_request(h, handler, request_body)
838  self.send_host(h, host)
839  self.send_user_agent(h)
840  self.send_content(h, request_body)
841 
842  errcode, errmsg, headers = h.getreply()
843 
844  if errcode != 200:
845  raise ProtocolError(
846  host + handler,
847  errcode, errmsg,
848  headers
849  )
850 
851  self.verbose = verbose
852 
853  return self.parse_response(h.getfile())
854 
855  def getparser(self):
856  # get parser and unmarshaller
857  return getparser()
858 
859  def make_connection(self, host):
860  # create a HTTP connection object from a host descriptor
861  import httplib
862  return httplib.HTTP(host)
863 
864  def send_request(self, connection, handler, request_body):
865  connection.putrequest("POST", handler)
866 
867  def send_host(self, connection, host):
868  connection.putheader("Host", host)
869 
870  def send_user_agent(self, connection):
871  connection.putheader("User-Agent", self.user_agent)
872 
873  def send_content(self, connection, request_body):
874  connection.putheader("Content-Type", "text/xml")
875  connection.putheader("Content-Length", str(len(request_body)))
876  connection.endheaders()
877  if request_body:
878  connection.send(request_body)
879 
880  def parse_response(self, f):
881  # read response from input file, and parse it
882 
883  p, u = self.getparser()
884 
885  while 1:
886  response = f.read(1024)
887  if not response:
888  break
889  if self.verbose:
890  print "body:", repr(response)
891  p.feed(response)
892 
893  f.close()
894  p.close()
895 
896  return u.close()
897 
899  """Handles an HTTPS transaction to an XML-RPC server."""
900 
901  def make_connection(self, host):
902  # create a HTTPS connection object from a host descriptor
903  # host may be a string, or a (host, x509-dict) tuple
904  import httplib
905  if isinstance(host, TupleType):
906  host, x509 = host
907  else:
908  x509 = {}
909  try:
910  HTTPS = httplib.HTTPS
911  except AttributeError:
912  raise NotImplementedError,\
913  "your version of httplib doesn't support HTTPS"
914  else:
915  return apply(HTTPS, (host, None), x509)
916 
917  def send_host(self, connection, host):
918  if isinstance(host, TupleType):
919  host, x509 = host
920  connection.putheader("Host", host)
921 
923  """uri [,options] -> a logical connection to an XML-RPC server
924 
925  uri is the connection point on the server, given as
926  scheme://host/target.
927 
928  The standard implementation always supports the "http" scheme. If
929  SSL socket support is available (Python 2.0), it also supports
930  "https".
931 
932  If the target part and the slash preceding it are both omitted,
933  "/RPC2" is assumed.
934 
935  The following options can be given as keyword arguments:
936 
937  transport: a transport factory
938  encoding: the request encoding (default is UTF-8)
939 
940  All 8-bit strings passed to the server proxy are assumed to use
941  the given encoding.
942  """
943 
944  def __init__(self, uri, transport=None, encoding=None, verbose=0):
945  # establish a "logical" server connection
946 
947  # get the url
948  import urllib
949  type, uri = urllib.splittype(uri)
950  if type not in ("http", "https"):
951  raise IOError, "unsupported XML-RPC protocol"
952  self.__host, self.__handler = urllib.splithost(uri)
953  if not self.__handler:
954  self.__handler = "/RPC2"
955 
956  if transport is None:
957  if type == "https":
958  transport = SafeTransport()
959  else:
960  transport = Transport()
961  self.__transport = transport
962 
963  self.__encoding = encoding
964  self.__verbose = verbose
965 
966  def __request(self, methodname, params):
967  # call a method on the remote server
968 
969  request = dumps(params, methodname, encoding=self.__encoding)
970 
971  response = self.__transport.request(
972  self.__host,
973  self.__handler,
974  request,
975  verbose=self.__verbose
976  )
977 
978  if len(response) == 1:
979  response = response[0]
980 
981  return response
982 
983  def __repr__(self):
984  return (
985  "<ServerProxy for %s%s>" %
986  (self.__host, self.__handler)
987  )
988 
989  __str__ = __repr__
990 
991  def __getattr__(self, name):
992  # magic method dispatcher
993  return _Method(self.__request, name)
994 
995  # note: to call a remote object with an non-standard name, use
996  # result getattr(server, "strange-python-name")(args)
997 
998 # compatibility
999 Server = ServerProxy
1000 
1001 # --------------------------------------------------------------------
1002 # test code
1003 
1004 if __name__ == "__main__":
1005 
1006  # simple test program (from the XML-RPC specification)
1007 
1008  # server = ServerProxy("http://localhost:8000") # local server
1009  server = ServerProxy("http://betty.userland.com")
1010 
1011  print server
1012 
1013  try:
1014  print server.examples.getStateName(41)
1015  except Error, v:
1016  print "ERROR", v