[Python-checkins] python/dist/src/Lib xmlrpclib.py,1.18,1.19

effbot@users.sourceforge.net effbot@users.sourceforge.net
Thu, 27 Jun 2002 14:36:23 -0700


Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv28316/Lib

Modified Files:
	xmlrpclib.py 
Log Message:


merged with SLAB codebase (version 1.0.1)

Index: xmlrpclib.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/xmlrpclib.py,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -d -r1.18 -r1.19
*** xmlrpclib.py	2 Jun 2002 03:04:52 -0000	1.18
--- xmlrpclib.py	27 Jun 2002 21:36:21 -0000	1.19
***************
*** 34,43 ****
  # 2001-10-01 fl  Remove containers from memo cache when done with them
  # 2001-10-01 fl  Use faster escape method (80% dumps speedup)
  # 2001-10-10 sm  Allow long ints to be passed as ints if they don't overflow
! # 2001-10-17 sm  test for int and long overflow (allows use on 64-bit systems)
  # 2001-11-12 fl  Use repr() to marshal doubles (from Paul Felix)
  #
! # Copyright (c) 1999-2001 by Secret Labs AB.
! # Copyright (c) 1999-2001 by Fredrik Lundh.
  #
  # info@pythonware.com
--- 34,50 ----
  # 2001-10-01 fl  Remove containers from memo cache when done with them
  # 2001-10-01 fl  Use faster escape method (80% dumps speedup)
+ # 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 sm  Allow long ints to be passed as ints if they don't overflow
! # 2001-10-17 sm  Test for int and long overflow (allows use on 64-bit systems)
  # 2001-11-12 fl  Use repr() to marshal doubles (from Paul Felix)
+ # 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
  #
! # Copyright (c) 1999-2002 by Secret Labs AB.
! # Copyright (c) 1999-2002 by Fredrik Lundh.
  #
  # info@pythonware.com
***************
*** 47,52 ****
  # The XML-RPC client interface is
  #
! # Copyright (c) 1999-2001 by Secret Labs AB
! # Copyright (c) 1999-2001 by Fredrik Lundh
  #
  # By obtaining, using, and/or copying this software and/or its
--- 54,59 ----
  # The XML-RPC client interface is
  #
! # Copyright (c) 1999-2002 by Secret Labs AB
! # Copyright (c) 1999-2002 by Fredrik Lundh
  #
  # By obtaining, using, and/or copying this software and/or its
***************
*** 74,84 ****
  
  #
! # things to look into:
  
! # TODO: support basic authentication (see robin's patch)
! # TODO: fix host tuple handling in the server constructor
! # TODO: let transport verify schemes
! # TODO: update documentation
! # TODO: authentication plugins
  
  """
--- 81,87 ----
  
  #
! # things to look into some day:
  
! # TODO: sort out True/False/boolean issues for Python 2.3
  
  """
***************
*** 131,134 ****
--- 134,140 ----
  from types import *
  
+ # --------------------------------------------------------------------
+ # Internal stuff
+ 
  try:
      unicode
***************
*** 147,153 ****
      return replace(s, ">", ">",)
  
- MAXINT =  2L**31-1
- MININT = -2L**31
- 
  if unicode:
      def _stringify(string):
--- 153,156 ----
***************
*** 161,169 ****
          return string
  
! __version__ = "1.0.0"
  
  # --------------------------------------------------------------------
  # Exceptions
  
  class Error(Exception):
      """Base class for client errors."""
--- 164,199 ----
          return string
  
! __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
  
  # --------------------------------------------------------------------
  # Exceptions
  
+ ##
+ # Base class for all kinds of client-side errors.
+ 
  class Error(Exception):
      """Base class for client errors."""
***************
*** 171,174 ****
--- 201,214 ----
          return repr(self)
  
+ ##
+ # 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.
+ 
  class ProtocolError(Error):
      """Indicates an HTTP protocol error."""
***************
*** 185,192 ****
--- 225,246 ----
              )
  
+ ##
+ # Indicates a broken XML-RPC response package.  This exception is
+ # raised by the unmarshalling layer, if the XML-RPC response is
+ # malformed.
+ 
  class ResponseError(Error):
      """Indicates a broken response package."""
      pass
  
+ ##
+ # 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.
+ 
  class Fault(Error):
      """Indicates an XML-RPC fault package."""
***************
*** 204,207 ****
--- 258,269 ----
  # Special values
  
+ ##
+ # 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.
+ 
  class Boolean:
      """Boolean-value wrapper.
***************
*** 235,241 ****
  True, False = Boolean(1), Boolean(0)
  
! def boolean(value, truefalse=(False, True)):
      """Convert any Python value to XML-RPC 'boolean'."""
!     return truefalse[operator.truth(value)]
  
  class DateTime:
--- 297,327 ----
  True, False = Boolean(1), Boolean(0)
  
! ##
! # 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)):
      """Convert any Python value to XML-RPC 'boolean'."""
!     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.
  
  class DateTime:
***************
*** 259,264 ****
          return cmp(self.value, other)
  
      def __repr__(self):
!         return "<DateTime %s at %x>" % (self.value, id(self))
  
      def decode(self, data):
--- 345,358 ----
          return cmp(self.value, other)
  
+     ##
+     # Get date/time value.
+     #
+     # @return Date/time value, as an ISO 8601 string.
+ 
+     def __str__(self):
+         return self.value
+ 
      def __repr__(self):
!         return "<DateTime %s at %x>" % (repr(self.value), id(self))
  
      def decode(self, data):
***************
*** 270,278 ****
          out.write("</dateTime.iso8601></value>\n")
  
! def datetime(data):
      value = DateTime()
      value.decode(data)
      return value
  
  class Binary:
      """Wrapper for binary data."""
--- 364,379 ----
          out.write("</dateTime.iso8601></value>\n")
  
! def _datetime(data):
!     # decode xml element contents into a DateTime structure.
      value = DateTime()
      value.decode(data)
      return value
  
+ ##
+ # 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.
+ 
  class Binary:
      """Wrapper for binary data."""
***************
*** 281,284 ****
--- 382,393 ----
          self.data = data
  
+     ##
+     # Get buffer contents.
+     #
+     # @return Buffer contents, as an 8-bit string.
+ 
+     def __str__(self):
+         return self.data or ""
+ 
      def __cmp__(self, other):
          if isinstance(other, Binary):
***************
*** 296,300 ****
          out.write("</base64></value>\n")
  
! def binary(data):
      value = Binary()
      value.decode(data)
--- 405,410 ----
          out.write("</base64></value>\n")
  
! def _binary(data):
!     # decode xml element contents into a Binary structure
      value = Binary()
      value.decode(data)
***************
*** 315,318 ****
--- 425,434 ----
      FastParser = FastUnmarshaller = None
  
+ try:
+     import _xmlrpclib
+     FastMarshaller = _xmlrpclib.Marshaller
+ except (AttributeError, ImportError):
+     FastMarshaller = None
+ 
  #
  # the SGMLOP parser is about 15x faster than Python's builtin
***************
*** 368,378 ****
      from xml.parsers import expat
      if not hasattr(expat, "ParserCreate"):
!         raise ImportError, "ParserCreate"
  except ImportError:
!     ExpatParser = None
  else:
      class ExpatParser:
!         # fast expat parser for Python 2.0.  this is about 50%
!         # slower than sgmlop, on roundtrip testing
          def __init__(self, target):
              self._parser = parser = expat.ParserCreate(None, None)
--- 484,494 ----
      from xml.parsers import expat
      if not hasattr(expat, "ParserCreate"):
!         raise ImportError
  except ImportError:
!     ExpatParser = None # expat not available
  else:
      class ExpatParser:
!         # fast expat parser for Python 2.0 and later.  this is about
!         # 50% slower than sgmlop, on roundtrip testing
          def __init__(self, target):
              self._parser = parser = expat.ParserCreate(None, None)
***************
*** 404,407 ****
--- 520,524 ----
          self.unknown_starttag = target.start
          self.handle_data = target.data
+         self.handle_cdata = target.data
          self.unknown_endtag = target.end
          try:
***************
*** 413,416 ****
--- 530,540 ----
  # XML-RPC marshalling and unmarshalling code
  
+ ##
+ # XML-RPC marshaller.
+ #
+ # @param encoding Default encoding for 8-bit strings.  The default
+ #     value is None (interpreted as UTF-8).
+ # @see dumps
+ 
  class Marshaller:
      """Generate an XML-RPC params chunk from a Python data structure.
***************
*** 434,443 ****
  
      def dumps(self, values):
!         self.__out = []
!         self.write = write = self.__out.append
          if isinstance(values, Fault):
              # fault instance
              write("<fault>\n")
!             self.__dump(vars(values))
              write("</fault>\n")
          else:
--- 558,568 ----
  
      def dumps(self, values):
!         out = []
!         write = out.append
!         dump = self.__dump
          if isinstance(values, Fault):
              # fault instance
              write("<fault>\n")
!             dump(vars(values), write)
              write("</fault>\n")
          else:
***************
*** 451,462 ****
              for v in values:
                  write("<param>\n")
!                 self.__dump(v)
                  write("</param>\n")
              write("</params>\n")
!         result = string.join(self.__out, "")
!         del self.__out, self.write # don't need this any more
          return result
  
!     def __dump(self, value):
          try:
              f = self.dispatch[type(value)]
--- 576,586 ----
              for v in values:
                  write("<param>\n")
!                 dump(v, write)
                  write("</param>\n")
              write("</params>\n")
!         result = string.join(out, "")
          return result
  
!     def __dump(self, value, write):
          try:
              f = self.dispatch[type(value)]
***************
*** 464,545 ****
              raise TypeError, "cannot marshal %s objects" % type(value)
          else:
!             f(self, value)
  
!     def dump_int(self, value):
          # in case ints are > 32 bits
          if value > MAXINT or value < MININT:
              raise OverflowError, "int exceeds XML-RPC limits"
!         self.write("<value><int>%s</int></value>\n" % value)
      dispatch[IntType] = dump_int
  
!     def dump_long(self, value):
!         # in case ints are > 32 bits
          if value > MAXINT or value < MININT:
              raise OverflowError, "long int exceeds XML-RPC limits"
!         self.write("<value><int>%s</int></value>\n" % int(value))
      dispatch[LongType] = dump_long
  
!     def dump_double(self, value):
!         self.write("<value><double>%s</double></value>\n" % repr(value))
      dispatch[FloatType] = dump_double
  
!     def dump_string(self, value, escape=escape):
!         self.write("<value><string>%s</string></value>\n" % escape(value))
      dispatch[StringType] = dump_string
  
      if unicode:
!         def dump_unicode(self, value, escape=escape):
              value = value.encode(self.encoding)
!             self.write("<value><string>%s</string></value>\n" % escape(value))
          dispatch[UnicodeType] = dump_unicode
  
!     def opencontainer(self, value):
!         if value:
!             i = id(value)
!             if i in self.memo:
!                 raise TypeError, "cannot marshal recursive data structures"
!             self.memo[i] = None
! 
!     def closecontainer(self, value):
!         if value:
!             del self.memo[id(value)]
! 
!     def dump_array(self, value):
!         self.opencontainer(value)
!         write = self.write
          dump = self.__dump
          write("<value><array><data>\n")
          for v in value:
!             dump(v)
          write("</data></array></value>\n")
!         self.closecontainer(value)
      dispatch[TupleType] = dump_array
      dispatch[ListType] = dump_array
  
!     def dump_struct(self, value, escape=escape):
!         self.opencontainer(value)
!         write = self.write
          dump = self.__dump
          write("<value><struct>\n")
!         for k, v in value.items():
              write("<member>\n")
              if type(k) is not StringType:
                  raise TypeError, "dictionary key must be string"
              write("<name>%s</name>\n" % escape(k))
!             dump(v)
              write("</member>\n")
          write("</struct></value>\n")
!         self.closecontainer(value)
      dispatch[DictType] = dump_struct
  
!     def dump_instance(self, value):
          # check for special wrappers
          if value.__class__ in WRAPPERS:
              value.encode(self)
          else:
              # store instance attributes as a struct (really?)
!             self.dump_struct(value.__dict__)
      dispatch[InstanceType] = dump_instance
  
  class Unmarshaller:
      """Unmarshal an XML-RPC response, based on incoming XML event
--- 588,678 ----
              raise TypeError, "cannot marshal %s objects" % type(value)
          else:
!             f(self, value, write)
  
!     def dump_int(self, value, write):
          # in case ints are > 32 bits
          if value > MAXINT or value < MININT:
              raise OverflowError, "int exceeds XML-RPC limits"
!         write("<value><int>")
!         write(str(value))
!         write("</int></value>\n")
      dispatch[IntType] = dump_int
  
!     def dump_long(self, value, write):
          if value > MAXINT or value < MININT:
              raise OverflowError, "long int exceeds XML-RPC limits"
!         write("<value><int>")
!         write(str(int(value)))
!         write("</int></value>\n")
      dispatch[LongType] = dump_long
  
!     def dump_double(self, value, write):
!         write("<value><double>")
!         write(repr(value))
!         write("</double></value>\n")
      dispatch[FloatType] = dump_double
  
!     def dump_string(self, value, write, escape=escape):
!         write("<value><string>")
!         write(escape(value))
!         write("</string></value>\n")
      dispatch[StringType] = dump_string
  
      if unicode:
!         def dump_unicode(self, value, write, escape=escape):
              value = value.encode(self.encoding)
!             write("<value><string>")
!             write(escape(value))
!             write("</string></value>\n")
          dispatch[UnicodeType] = dump_unicode
  
!     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
          dump = self.__dump
          write("<value><array><data>\n")
          for v in value:
!             dump(v, write)
          write("</data></array></value>\n")
!         del self.memo[i]
      dispatch[TupleType] = dump_array
      dispatch[ListType] = dump_array
  
!     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
          dump = self.__dump
          write("<value><struct>\n")
!         for k in value.keys():
              write("<member>\n")
              if type(k) is not StringType:
                  raise TypeError, "dictionary key must be string"
              write("<name>%s</name>\n" % escape(k))
!             dump(value[k], write)
              write("</member>\n")
          write("</struct></value>\n")
!         del self.memo[i]
      dispatch[DictType] = dump_struct
  
!     def dump_instance(self, value, write):
          # check for special wrappers
          if value.__class__ in WRAPPERS:
+             self.write = write
              value.encode(self)
+             del self.write
          else:
              # store instance attributes as a struct (really?)
!             self.dump_struct(value.__dict__, write)
      dispatch[InstanceType] = dump_instance
  
+ ##
+ # XML-RPC unmarshaller.
+ #
+ # @see loads
+ 
  class Unmarshaller:
      """Unmarshal an XML-RPC response, based on incoming XML event
***************
*** 680,684 ****
  
      def end_value(self, data):
!         # if we stumble upon an value element with no internal
          # elements, treat it as a string element
          if self._value:
--- 813,817 ----
  
      def end_value(self, data):
!         # if we stumble upon a value element with no internal
          # elements, treat it as a string element
          if self._value:
***************
*** 705,708 ****
--- 838,847 ----
  # convenience functions
  
+ ##
+ # Create a parser object, and connect it to an unmarshalling instance.
+ # This function picks the fastest available XML parser.
+ #
+ # return A (parser, unmarshaller) tuple.
+ 
  def getparser():
      """getparser() -> parser, unmarshaller
***************
*** 712,716 ****
      """
      if FastParser and FastUnmarshaller:
!         target = FastUnmarshaller(True, False, binary, datetime)
          parser = FastParser(target)
      else:
--- 851,855 ----
      """
      if FastParser and FastUnmarshaller:
!         target = FastUnmarshaller(True, False, _binary, _datetime, Fault)
          parser = FastParser(target)
      else:
***************
*** 726,729 ****
--- 865,881 ----
      return parser, target
  
+ ##
+ # 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.
+ 
  def dumps(params, methodname=None, methodresponse=None, encoding=None):
      """data [,options] -> marshalled data
***************
*** 756,772 ****
          assert len(params) == 1, "response tuple must be a singleton"
  
!     if encoding is None:
          encoding = "utf-8"
  
!     m = Marshaller(encoding)
      data = m.dumps(params)
  
      if encoding != "utf-8":
!         xmlheader = "<?xml version='1.0' encoding=%s?>\n" % repr(encoding)
      else:
          xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
  
      # standard XML-RPC wrappings
!     if methodname is not None:
          # a method call
          if not isinstance(methodname, StringType):
--- 908,928 ----
          assert len(params) == 1, "response tuple must be a singleton"
  
!     if not encoding:
          encoding = "utf-8"
  
!     if FastMarshaller:
!         m = FastMarshaller(encoding)
!     else:
!         m = Marshaller(encoding)
! 
      data = m.dumps(params)
  
      if encoding != "utf-8":
!         xmlheader = "<?xml version='1.0' encoding='%s'?>\n" % str(encoding)
      else:
          xmlheader = "<?xml version='1.0'?>\n" # utf-8 is default
  
      # standard XML-RPC wrappings
!     if methodname:
          # a method call
          if not isinstance(methodname, StringType):
***************
*** 791,794 ****
--- 947,959 ----
      return string.join(data, "")
  
+ ##
+ # 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
+ 
  def loads(data):
      """data -> unmarshalled data, method name
***************
*** 800,803 ****
--- 965,969 ----
      raises a Fault exception.
      """
+     import sys
      p, u = getparser()
      p.feed(data)
***************
*** 820,823 ****
--- 986,994 ----
          return self.__send(self.__name, args)
  
+ ##
+ # Standard transport class for XML-RPC over HTTP.
+ # <p>
+ # You can create custom transports by subclassing this method, and
+ # overriding selected methods.
  
  class Transport:
***************
*** 827,830 ****
--- 998,1010 ----
      user_agent = "xmlrpclib.py/%s (by www.pythonware.com)" % __version__
  
+     ##
+     # 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.
+ 
      def request(self, host, handler, request_body, verbose=0):
          # issue XML-RPC request
***************
*** 850,854 ****
          self.verbose = verbose
  
!         return self.parse_response(h.getfile())
  
      def getparser(self):
--- 1030,1044 ----
          self.verbose = verbose
  
!         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.
  
      def getparser(self):
***************
*** 856,859 ****
--- 1046,1055 ----
          return getparser()
  
+     ##
+     # Connect to server.
+     #
+     # @param host Target host.
+     # @return A connection handle.
+ 
      def make_connection(self, host):
          # create a HTTP connection object from a host descriptor
***************
*** 861,873 ****
--- 1057,1093 ----
          return httplib.HTTP(host)
  
+     ##
+     # Send request header.
+     #
+     # @param connection Connection handle.
+     # @param handler Target RPC handler.
+     # @param request_body XML-RPC body.
+ 
      def send_request(self, connection, handler, request_body):
          connection.putrequest("POST", handler)
  
+     ##
+     # Send host name.
+     #
+     # @param connection Connection handle.
+     # @param host Host name.
+ 
      def send_host(self, connection, host):
          connection.putheader("Host", host)
  
+     ##
+     # Send user-agent identifier.
+     #
+     # @param connection Connection handle.
+ 
      def send_user_agent(self, connection):
          connection.putheader("User-Agent", self.user_agent)
  
+     ##
+     # Send request body.
+     #
+     # @param connection Connection handle.
+     # @param request_body XML-RPC request body.
+ 
      def send_content(self, connection, request_body):
          connection.putheader("Content-Type", "text/xml")
***************
*** 877,887 ****
              connection.send(request_body)
  
!     def parse_response(self, f):
!         # read response from input file, and parse it
  
          p, u = self.getparser()
  
          while 1:
!             response = f.read(1024)
              if not response:
                  break
--- 1097,1130 ----
              connection.send(request_body)
  
!     ##
!     # 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
  
          p, u = self.getparser()
  
          while 1:
!             if sock:
!                 response = sock.recv(1024)
!             else:
!                 response = file.read(1024)
              if not response:
                  break
***************
*** 890,901 ****
              p.feed(response)
  
!         f.close()
          p.close()
  
          return u.close()
  
  class SafeTransport(Transport):
      """Handles an HTTPS transaction to an XML-RPC server."""
  
      def make_connection(self, host):
          # create a HTTPS connection object from a host descriptor
--- 1133,1149 ----
              p.feed(response)
  
!         file.close()
          p.close()
  
          return u.close()
  
+ ##
+ # Standard transport class for XML-RPC over HTTPS.
+ 
  class SafeTransport(Transport):
      """Handles an HTTPS transaction to an XML-RPC server."""
  
+     # FIXME: mostly untested
+ 
      def make_connection(self, host):
          # create a HTTPS connection object from a host descriptor
***************
*** 919,922 ****
--- 1167,1187 ----
          connection.putheader("Host", host)
  
+ ##
+ # 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
+ 
  class ServerProxy:
      """uri [,options] -> a logical connection to an XML-RPC server
***************
*** 996,999 ****
--- 1261,1265 ----
  
  # compatibility
+ 
  Server = ServerProxy