Skip to main content

Lib/xmlrpc/client.py

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/client.py

xmlrpc.client provides a client-side implementation of the XML-RPC protocol. The central abstraction is ServerProxy, a transparent proxy object whose attribute accesses become remote method names and whose calls encode arguments as XML, send them over HTTP, and decode the response back into Python types. The module handles the full marshalling pipeline from Python objects to the <methodCall> XML document and back.

Transport is pluggable. The default Transport class opens a plain HTTP connection using http.client.HTTPConnection. SafeTransport subclasses it to use HTTPS. Both classes expose request() as the single entry point that higher layers call, letting callers swap in custom transports for proxies, authentication, or testing without touching ServerProxy itself.

Batch operations are supported through MultiCall. A MultiCall instance records method calls without executing them, then sends all accumulated calls in a single system.multicall request. The server processes each sub-call independently and returns a list of results or faults, which MultiCall unpacks into per-call outcomes. This reduces round-trips when many independent methods need to be called together.

Map

LinesSymbolRolegopy
1-80module header, ExpatParser import guardImports and compatibility shims
81-220dumps(), loads()Top-level marshal/unmarshal entry points
221-420MarshallerEncodes Python objects to XML-RPC <value> nodes
421-580UnmarshallerSAX-driven decoder mapping XML back to Python types
581-720Transport, SafeTransportHTTP/HTTPS connection management and request dispatch
721-820ServerProxyTransparent proxy; turns attribute access into method calls
821-920MultiCall, _MultiCallMethodDeferred batch-call builder and result iterator
921-1050DateTime, BinaryWrapper types for XML-RPC datetime and base64 values
1051-1200Fault, ProtocolError, ResponseErrorException hierarchy for server and transport errors
1201-1400boolean, _datetime, helper constantsSentinel values, format strings, and minor utilities

Reading

Module-level marshalling entry points (lines 81 to 220)

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/client.py#L81-220

dumps() and loads() are the public marshal/unmarshal API. dumps() accepts a tuple of arguments (and an optional method name) and returns a UTF-8 XML string. loads() parses an XML-RPC response or fault document and returns (params, methodname). Both delegate immediately to Marshaller and Unmarshaller respectively.

def dumps(params, methodname=None, methodresponse=None,
encoding=None, allow_none=False):
if isinstance(params, Fault):
methodresponse = 1
elif methodresponse and isinstance(params, tuple):
assert len(params) == 1, "response tuple must be a singleton"
...
m = Marshaller(encoding, allow_none)
data = m.dumps(params)
...

Marshaller: encoding Python types (lines 221 to 420)

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/client.py#L221-420

Marshaller walks a Python value tree and emits XML-RPC <value> elements. It dispatches on type(value) through a dispatch dict that maps each built-in type to a dump_* method. Unsupported types raise TypeError. bool must be checked before int because bool is a subclass of int in Python.

dispatch = {}

def dump_int(self, value, write):
write("<value><int>%d</int></value>\n" % value)
dispatch[int] = dump_int

def dump_bool(self, value, write):
write("<value><boolean>%d</boolean></value>\n" % bool(value))
dispatch[bool] = dump_bool

def dump_double(self, value, write):
write("<value><double>%r</double></value>\n" % value)
dispatch[float] = dump_double

Unmarshaller: SAX-driven decoding (lines 421 to 580)

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/client.py#L421-580

Unmarshaller implements the SAX ContentHandler interface. It maintains a _stack of in-progress values and a _marks list of stack positions for arrays and structs. On endElement events the top of the stack is coerced to the typed Python value and pushed back. Faults in the response XML become Fault exceptions raised from close().

def end_int(self, data):
self.append(int(data))
self._value = 0

def end_array(self, data):
mark = self._marks.pop()
# slice the stack down to the mark, assemble list
self._stack[mark:] = [self._stack[mark:]]
self._value = 0

def close(self):
if self._type is None or self._marks:
raise ResponseError()
if self._type == "fault":
raise Fault(**self._stack[0])
return tuple(self._stack)

Transport and SafeTransport (lines 581 to 720)

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/client.py#L581-720

Transport.request() is the single method that ServerProxy calls. It builds the HTTP headers (Content-Type, Content-Length, User-Agent), opens a connection via make_connection(), sends the request body, and parses the response with parse_response(). SafeTransport overrides make_connection() to return an HTTPSConnection instead, reusing all other logic.

def request(self, host, handler, request_body, verbose=False):
http_conn = self.send_request(host, handler, request_body, verbose)
resp = http_conn.getresponse()
if resp.status != 200:
raise ProtocolError(host + handler, resp.status,
resp.reason, resp.msg)
return self.parse_response(resp)

ServerProxy and MultiCall (lines 721 to 920)

cpython 3.14 @ ab2d84fe1023/Lib/xmlrpc/client.py#L721-920

ServerProxy.__getattr__ returns a _Method closure that captures the method name. When called, _Method.__call__ invokes ServerProxy._ServerProxy__request, which marshals args, calls Transport.request, and unmarshals the result. MultiCall works similarly but stores _MultiCallMethod closures that append to a call list instead of sending. After all methods are queued, calling the MultiCall object sends a single system.multicall request and returns a generator of per-call results.

class _Method:
def __init__(self, send, name):
self.__send = send
self.__name = name
def __call__(self, *args):
return self.__send(self.__name, args)
def __getattr__(self, name):
return _Method(self.__send, "%s.%s" % (self.__name, name))

gopy mirror

Not yet ported.