Claude Code for xmlrpc.client: Python XML-RPC Client — Claude Skills 360 Blog
Blog / AI / Claude Code for xmlrpc.client: Python XML-RPC Client
AI

Claude Code for xmlrpc.client: Python XML-RPC Client

Published: September 10, 2028
Read time: 5 min read
By: Claude Skills 360

Python’s xmlrpc.client module implements an XML-RPC client that calls remote methods over HTTP. import xmlrpc.client. ServerProxy: proxy = xmlrpc.client.ServerProxy("http://localhost:8000/RPC2") — all attribute accesses become remote calls; proxy.method(arg1, arg2) serializes args to XML, POSTs, and returns the decoded response. Type options: ServerProxy(url, allow_none=True) — marshals Python None as <nil/>; use_datetime=True — returns datetime.datetime instead of xmlrpc.client.DateTime; use_builtin_types=True — maps <base64> to bytes instead of xmlrpc.client.Binary. HTTPS: ServerProxy("https://host/RPC2", context=ssl.create_default_context()). MultiCall: mc = xmlrpc.client.MultiCall(proxy); mc.add(1,2); mc.ping(); results = mc() — batches all calls into one HTTP round-trip. Errors: xmlrpc.client.Fault — server raised an error (.faultCode, .faultString); xmlrpc.client.ProtocolError — HTTP error (.url, .errcode, .errmsg). Binary: xmlrpc.client.Binary(b"...") — wraps bytes for transmission. Introspection: proxy.system.listMethods(), proxy.system.methodHelp("name"), proxy.system.methodSignature("name"). Low-level: xmlrpc.client.dumps((arg,), "method") → XML string; xmlrpc.client.loads(xml) → (params, method). Claude Code generates WordPress API clients, legacy service bridges, batch RPC callers, and XML-RPC introspection tools.

CLAUDE.md for xmlrpc.client

## xmlrpc.client Stack
- Stdlib: import xmlrpc.client, ssl
- Call:   proxy = xmlrpc.client.ServerProxy("http://host/RPC2", allow_none=True)
- Invoke: result = proxy.method_name(arg1, arg2)
- Batch:  mc = xmlrpc.client.MultiCall(proxy); mc.fn1(); mc.fn2(); r1, r2 = mc()
- HTTPS:  ServerProxy("https://host/RPC2", context=ssl.create_default_context())
- Errors: except xmlrpc.client.Fault as e: e.faultCode, e.faultString

xmlrpc.client RPC Pipeline

# app/xmlrpcutil.py — proxy, retry, batch, introspect, type helpers
from __future__ import annotations

import ssl
import time
import xmlrpc.client
from contextlib import contextmanager
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Callable, Generator, TypeVar

T = TypeVar("T")


# ─────────────────────────────────────────────────────────────────────────────
# 1. Proxy factory helpers
# ─────────────────────────────────────────────────────────────────────────────

def make_proxy(
    url: str,
    *,
    allow_none: bool = True,
    use_datetime: bool = True,
    use_builtin_types: bool = True,
    tls: bool | None = None,
    verbose: bool = False,
) -> xmlrpc.client.ServerProxy:
    """
    Create an XML-RPC ServerProxy with sensible modern defaults.
    tls=True forces HTTPS context; None auto-detects from URL scheme.

    Example:
        proxy = make_proxy("http://localhost:8000/RPC2")
        result = proxy.system.listMethods()
    """
    kwargs: dict[str, Any] = {
        "allow_none": allow_none,
        "use_datetime": use_datetime,
        "use_builtin_types": use_builtin_types,
        "verbose": verbose,
    }
    use_tls = tls if tls is not None else url.startswith("https://")
    if use_tls:
        kwargs["context"] = ssl.create_default_context()
    return xmlrpc.client.ServerProxy(url, **kwargs)


@contextmanager
def proxy_session(url: str, **kwargs) -> Generator[xmlrpc.client.ServerProxy, None, None]:
    """
    Context manager that creates and closes an XML-RPC proxy.

    Example:
        with proxy_session("http://localhost:8000/RPC2") as proxy:
            print(proxy.system.listMethods())
    """
    proxy = make_proxy(url, **kwargs)
    try:
        yield proxy
    finally:
        proxy("close")()  # type: ignore[operator]


# ─────────────────────────────────────────────────────────────────────────────
# 2. Error handling wrappers
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class RPCResult:
    ok:     bool
    value:  Any
    fault_code: int = 0
    fault_msg:  str = ""
    error:      str = ""

    def unwrap(self) -> Any:
        """Return value or raise appropriate exception."""
        if not self.ok:
            if self.fault_code:
                raise xmlrpc.client.Fault(self.fault_code, self.fault_msg)
            raise RuntimeError(self.error)
        return self.value

    def __str__(self) -> str:
        if self.ok:
            return f"OK: {self.value!r}"
        if self.fault_code:
            return f"Fault({self.fault_code}): {self.fault_msg}"
        return f"Error: {self.error}"


def safe_call(fn: Callable[[], T]) -> RPCResult:
    """
    Execute an XML-RPC call; return RPCResult instead of raising.

    Example:
        result = safe_call(lambda: proxy.do_something(42))
        if result.ok:
            print(result.value)
        else:
            print(result)
    """
    try:
        return RPCResult(ok=True, value=fn())
    except xmlrpc.client.Fault as e:
        return RPCResult(ok=False, value=None, fault_code=e.faultCode, fault_msg=e.faultString)
    except xmlrpc.client.ProtocolError as e:
        return RPCResult(ok=False, value=None, error=f"HTTP {e.errcode}: {e.errmsg}")
    except Exception as e:
        return RPCResult(ok=False, value=None, error=str(e))


def call_with_retry(
    fn: Callable[[], T],
    max_attempts: int = 3,
    backoff: float = 1.0,
    retry_faults: tuple[int, ...] = (),
) -> T:
    """
    Call an XML-RPC method with retry on connection/transport errors.
    retry_faults allows retrying specific XML-RPC fault codes.

    Example:
        result = call_with_retry(lambda: proxy.slow_method(), max_attempts=4)
    """
    delay = backoff
    last_exc: BaseException | None = None
    for attempt in range(max_attempts):
        try:
            return fn()
        except xmlrpc.client.Fault as e:
            if e.faultCode in retry_faults and attempt < max_attempts - 1:
                last_exc = e
            else:
                raise
        except (xmlrpc.client.ProtocolError, OSError, TimeoutError) as e:
            last_exc = e
            if attempt == max_attempts - 1:
                raise
        time.sleep(delay)
        delay *= 2.0
    raise last_exc  # type: ignore[misc]


# ─────────────────────────────────────────────────────────────────────────────
# 3. MultiCall helpers
# ─────────────────────────────────────────────────────────────────────────────

def batch_call(
    proxy: xmlrpc.client.ServerProxy,
    calls: list[tuple[str, tuple]],
) -> list[RPCResult]:
    """
    Execute multiple RPC calls as a MultiCall batch (single HTTP round-trip).
    calls: [(method_name, args_tuple), ...]

    Example:
        results = batch_call(proxy, [
            ("add", (1, 2)),
            ("multiply", (3, 4)),
            ("echo", ("hello",)),
        ])
        for r in results:
            print(r)
    """
    mc = xmlrpc.client.MultiCall(proxy)
    for method_name, args in calls:
        getattr(mc, method_name)(*args)
    results: list[RPCResult] = []
    try:
        for value in mc():
            results.append(RPCResult(ok=True, value=value))
    except xmlrpc.client.Fault as e:
        results.append(RPCResult(ok=False, value=None,
                                 fault_code=e.faultCode, fault_msg=e.faultString))
    return results


# ─────────────────────────────────────────────────────────────────────────────
# 4. Introspection helpers
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class MethodInfo:
    name:      str
    help_text: str = ""
    signature: list[str] = field(default_factory=list)

    def __str__(self) -> str:
        sig = " | ".join(self.signature) if self.signature else "?"
        return f"{self.name}  sig={sig}\n  {self.help_text[:80]}"


def introspect(proxy: xmlrpc.client.ServerProxy) -> list[MethodInfo]:
    """
    List all methods exposed by the server (requires system.* support).

    Example:
        methods = introspect(proxy)
        for m in methods:
            print(m)
    """
    try:
        names: list[str] = proxy.system.listMethods()
    except Exception:
        return []
    infos: list[MethodInfo] = []
    for name in names:
        help_text = ""
        sig: list[str] = []
        try:
            help_text = proxy.system.methodHelp(name) or ""
        except Exception:
            pass
        try:
            raw_sig = proxy.system.methodSignature(name)
            if isinstance(raw_sig, list):
                sig = [" ".join(s) if isinstance(s, list) else str(s) for s in raw_sig]
        except Exception:
            pass
        infos.append(MethodInfo(name=name, help_text=help_text, signature=sig))
    return infos


# ─────────────────────────────────────────────────────────────────────────────
# 5. Serialization helpers
# ─────────────────────────────────────────────────────────────────────────────

def dumps_request(method: str, args: tuple) -> str:
    """
    Serialize an XML-RPC request to XML without sending it.

    Example:
        xml = dumps_request("add", (1, 2))
        print(xml)
    """
    return xmlrpc.client.dumps(args, method, allow_none=True)


def loads_response(xml: str | bytes) -> tuple[Any, str | None]:
    """
    Deserialize an XML-RPC response from XML bytes.
    Returns (params, method_name_or_None).

    Example:
        params, _ = loads_response(b"<methodResponse>...</methodResponse>")
    """
    if isinstance(xml, str):
        xml = xml.encode()
    return xmlrpc.client.loads(xml, use_datetime=True, use_builtin_types=True)


def wrap_bytes(data: bytes) -> xmlrpc.client.Binary:
    """Wrap bytes for XML-RPC Binary transport."""
    return xmlrpc.client.Binary(data)


def unwrap_bytes(value: xmlrpc.client.Binary | bytes) -> bytes:
    """Unwrap XML-RPC Binary to Python bytes."""
    if isinstance(value, xmlrpc.client.Binary):
        return value.data
    return value


# ─────────────────────────────────────────────────────────────────────────────
# Demo (spins up a minimal in-process XML-RPC server)
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    import threading
    from xmlrpc.server import SimpleXMLRPCServer

    print("=== xmlrpc.client demo ===")

    # ── Start a tiny in-process server ───────────────────────────────────────
    PORT = 18700

    def _serve() -> None:
        server = SimpleXMLRPCServer(("127.0.0.1", PORT), logRequests=False)
        server.register_introspection_functions()
        server.register_function(lambda a, b: a + b, "add")
        server.register_function(lambda a, b: a * b, "multiply")
        server.register_function(lambda s: s.upper(), "shout")
        server.register_function(lambda: None, "return_none")
        server.handle_request()  # serves 3 requests then exits
        server.handle_request()
        server.handle_request()

    t = threading.Thread(target=_serve, daemon=True)
    t.start()
    import time; time.sleep(0.05)

    proxy = make_proxy(f"http://127.0.0.1:{PORT}/")

    # ── basic calls ───────────────────────────────────────────────────────────
    print("\n--- basic calls ---")
    print(f"  add(3, 4) = {proxy.add(3, 4)}")
    print(f"  multiply(6, 7) = {proxy.multiply(6, 7)}")
    print(f"  shout('hello') = {proxy.shout('hello')!r}")

    # ── safe_call ─────────────────────────────────────────────────────────────
    print("\n--- safe_call ---")
    r = safe_call(lambda: proxy.add(10, 20))
    print(f"  {r}")

    # ── dumps_request ─────────────────────────────────────────────────────────
    print("\n--- dumps_request ---")
    xml = dumps_request("add", (1, 2))
    print(f"  {xml[:80].strip()!r}")

    # ── introspect (requires the 3rd handle_request) ──────────────────────────
    print("\n--- introspect ---")
    try:
        methods = introspect(proxy)
        for m in methods[:5]:
            print(f"  {m.name}")
    except Exception as e:
        print(f"  {e}")

    t.join(timeout=2.0)
    print("\n=== done ===")

For the xmlrpc.server alternative — xmlrpc.server.SimpleXMLRPCServer is the server-side companion exposing Python functions as RPC endpoints; it is used by the in-process demo above; the client and server together form a complete XML-RPC stack — they are complementary rather than alternative; xmlrpc.client is always the calling side and xmlrpc.server is the serving side. For the requests + JSON-RPC alternative — JSON-RPC over HTTP (typically via requests and a PyPI library like jsonrpcclient) provides semantically equivalent remote procedure calling with a lighter payload and native JSON types; it is the modern replacement for XML-RPC — use XML-RPC when integrating with existing systems that already speak it (WordPress XML-RPC API, Bugzilla, legacy Python services that use xmlrpc.server); use JSON-RPC for new inter-service communication where you control both sides. The Claude Skills 360 bundle includes xmlrpc.client skill sets covering make_proxy()/proxy_session() factory helpers, RPCResult dataclass with safe_call()/unwrap(), call_with_retry() with exponential backoff, batch_call() MultiCall helper, MethodInfo with introspect() for server discovery, and dumps_request()/loads_response()/wrap_bytes()/unwrap_bytes() serialization utilities. Start with the free tier to try XML-RPC client patterns and xmlrpc.client pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free