xmlrpc.client — Client XML-RPC

Source code: Lib/xmlrpc/client.py


XML-RPC est une méthode d'appel de procédure distante qui utilise du XML transmis via HTTP(S) comme transport. Un client peut ainsi appeler des méthodes avec des paramètres sur un serveur distant (le serveur est nommé par un URI) et récupérer des données structurées. Ce module prend en charge l'écriture de code client XML-RPC ; il gère la traduction entre les objets Python et le XML sur le réseau.

Avertissement

Le module xmlrpc.client n'est pas sécurisé contre les données construites de façon malveillante. Si vous avez besoin d'analyser des données non sécurisées ou non authentifiées, voir XML security.

Modifié dans la version 3.5: pour les URI HTTPS, xmlrpc.client effectue désormais par défaut toutes les vérifications nécessaires des certificats et des noms d'hôtes.

Disponibilité: not WASI.

Ce module ne fonctionne pas, ou n'est pas disponible en WebAssembly. Voir Plateformes WebAssembly pour plus d'informations.

class xmlrpc.client.ServerProxy(uri, transport=None, encoding=None, verbose=False, allow_none=False, use_datetime=False, use_builtin_types=False, *, headers=(), context=None)

Une instance ServerProxy est un objet qui gère la communication avec un serveur XML-RPC distant. Le premier argument, requis, est un URI (Uniform Resource Identifier, litt. identifiant uniforme de ressource), et est normalement l'URL du serveur. Le deuxième argument, facultatif, est une instance de fabrique de transport ; par défaut, il s'agit d'une instance de SafeTransport pour les URL HTTPS sinon d'une instance de Transport. Le troisième argument , facultatif, est un encodage, par défaut UTF-8. Le quatrième argument, facultatif, est un indicateur de débogage.

Les paramètres suivants régissent l'utilisation de l'instance de mandataire renvoyée. Si allow_none est vrai, la constante Python None est traduite en XML ; le comportement par défaut est que None lève une TypeError. Il s'agit d'une extension de la spécification XML-RPC couramment utilisée, mais elle n'est pas prise en charge par tous les clients et serveurs ; voir http://ontosys.com/xml-rpc/extensions.php. L'indicateur use_builtin_types peut être utilisé pour que les dates et heures soient présentées comme des objets datetime.datetime et que les données binaires soient présentées comme des objets bytes ; cet indicateur est faux par défaut. Les objets datetime.datetime, bytes et bytearray peuvent être transmis aux appels. Le paramètre headers est une séquence facultative d'en-têtes HTTP à envoyer avec chaque requête, exprimée sous la forme d'une séquence de paires représentant le nom et la valeur de l'en-tête (par exemple [('Header-Name', 'value')]). Si une l'URL utilise HTTPS, context peut-être fourni sous forme d'une ssl.SSLContext pour configurer les paramètres SSL de la connexion sous-jacente. L'indicateur obsolète use_datetime est similaire à use_builtin_types mais il s'applique uniquement aux valeurs de date et heure.

Modifié dans la version 3.3: l'indicateur use_builtin_types a été ajouté.

Modifié dans la version 3.8: le paramètre headers a été ajouté.

Les transports HTTP et HTTPS prennent en charge l'extension de syntaxe URL pour l'authentification HTTP basique : http://user:pass@host:port/path. La partie user:pass est codée en base64 en tant qu'en-tête HTTP « Authorization » et envoyée au serveur distant lors de l'appel d'une méthode XML-RPC. Vous ne devez l'utiliser que si le serveur distant nécessite un utilisateur et un mot de passe (Basic Authentication).

L'instance renvoyée est un objet mandataire avec des méthodes qui peuvent être utilisées pour effectuer les appels RPC correspondants sur le serveur distant. Si le serveur distant prend en charge l'API d'introspection, le mandataire peut également être utilisé pour interroger le serveur distant sur les méthodes qu'il prend en charge (découverte de services) et récupérer d'autres métadonnées associées au serveur.

Les types conformes (qui peuvent être sérialisés via XML) sont les éléments suivants (et, sauf indication contraire, sont du même type Python une fois désérialisés) :

Type XML-RPC

Type Python

boolean

bool

int, i1, i2, i4, i8 ou biginteger

int compris entre -2147483648 et 2147483647. Les valeurs sont marquées avec la balise <int>.

double ou float

float. Les valeurs reçoivent la balise <double>.

string

str

array

liste ou n-uplet contenant des éléments conformes. Les tableaux sont renvoyés sous forme de listes.

struct

dict. Les clés doivent être des chaînes, les valeurs peuvent être de n'importe quel type conforme. Des instances de classes définies par l'utilisateur peuvent être transmises ; seul leur attribut __dict__ est transmis.

dateTime.iso8601

DateTime ou datetime.datetime. Le type renvoyé dépend des valeurs des indicateurs use_builtin_types et use_datetime.

base64

Binary, bytes ou bytearray. Le type renvoyé dépend de la valeur de l'indicateur use_builtin_types.

nil

La constante None. Son utilisation n'est autorisée que si allow_none est vrai.

bigdecimal

decimal.Decimal. Type renvoyé uniquement.

Il s'agit de l'ensemble complet des types de données pris en charge par XML-RPC. Les appels de méthode peuvent également lever l'exception Fault, utilisée pour signaler les erreurs du serveur XML-RPC, ou l'exception ProtocolError utilisée pour signaler une erreur dans la couche de transport HTTP/HTTPS. Fault et ProtocolError dérivent d'une exception mère appelée Error. Notez que le module xmlrpc.client ne sérialise actuellement pas les instances de sous-classes de types natifs.

Lors de la sérialisation de chaînes, les caractères spéciaux à XML tels que <, > et & sont automatiquement échappés. Cependant, il est de la responsabilité de l'appelant de s'assurer que la chaîne ne contient pas de caractères non autorisés en XML, tels que les caractères de contrôle avec des valeurs ASCII comprises entre 0 et 31 (sauf, bien sûr, la tabulation, la nouvelle ligne et le retour chariot) ; si vous ne le faites pas, vous obtiendrez une requête XML-RPC qui n'est pas du XML valide. Si vous devez transmettre des octets arbitraires via XML-RPC, utilisez les classes bytes ou bytearray ou la classe de surcouche Binary décrite ci-dessous.

Server est conservé comme alias pour ServerProxy pour des raisons de compatibilité descendante. Le nouveau code doit utiliser ServerProxy.

Modifié dans la version 3.5: ajout de l'argument context.

Modifié dans la version 3.6: ajout du support des balises de type avec préfixes (par exemple ex:nil). Ajout de la prise en charge des types supplémentaires utilisés par l'implémentation Apache XML-RPC pour les valeurs numériques : i1, i2, i8, biginteger, float et bigdecimal. Voir https://ws.apache.org/xmlrpc/types.html pour une description.

Voir aussi

Guide pratique XML-RPC

Une bonne description du fonctionnement de XML-RPC et du logiciel client pour plusieurs langages. Contient à peu près tout ce qu'un développeur de client XML-RPC doit savoir.

Introspection de XML-RPC

Décrit l'extension du protocole XML-RPC pour l'introspection.

Spécification XML-RPC

La spécification officielle.

Objets ServerProxy

Un ServerProxy possède une méthode correspondant à chaque procédure distante acceptée par le serveur XML-RPC. L'appel de la méthode effectue un appel distant (RPC) en fonction du nom et de la signature des arguments (le même nom de méthode pouvant être surchargé avec plusieurs signatures d'arguments). L'appel termine soit en renvoyant une valeur dans un type conforme, soit en levant une Fault ou une ProtocolError indiquant une erreur.

Les serveurs qui prennent en charge l'API d'introspection XML prennent en charge certaines méthodes courantes regroupées sous l'attribut réservé system :

ServerProxy.system.listMethods()

Cette méthode renvoie une liste de chaînes, une pour chaque méthode (non système) prise en charge par le serveur XML-RPC.

ServerProxy.system.methodSignature(name)

Cette méthode prend un paramètre, le nom d'une méthode implémentée par le serveur XML-RPC. Elle renvoie une liste de signatures possibles pour cette méthode. Une signature est une liste de types. Le premier de ces types est le type de retour de la méthode, les autres sont des paramètres.

Étant donné que plusieurs signatures (c'est-à-dire surcharges) sont autorisées, cette méthode renvoie une liste de signatures.

Les signatures elles-mêmes sont limitées aux paramètres de niveau supérieur attendus par une méthode. Par exemple, si une méthode attend un tableau de structures comme paramètre et qu'elle renvoie une chaîne, sa signature est simplement [str, list]. Si elle attend trois entiers et renvoie une chaîne, sa signature est [str, int, int, int].

Si aucune signature n'est définie pour la méthode, le type de la valeur renvoyée est autre chose qu'une liste.

ServerProxy.system.methodHelp(name)

Cette méthode prend un paramètre, le nom d'une méthode implémentée par le serveur XML-RPC. Elle renvoie une chaîne de documentation décrivant l'utilisation de cette méthode. Si aucune chaîne de ce type n'est disponible, une chaîne vide est renvoyée. La chaîne de documentation peut contenir un balisage HTML.

Modifié dans la version 3.5: les instances de ServerProxy prennent en charge le protocole context manager pour fermer le transport sous-jacent.

Voici un exemple concret. Le code du serveur :

from xmlrpc.server import SimpleXMLRPCServer

def is_even(n):
    return n % 2 == 0

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(is_even, "is_even")
server.serve_forever()

Le code client correspondant au serveur précédent :

import xmlrpc.client

with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
    print("3 is even: %s" % str(proxy.is_even(3)))
    print("100 is even: %s" % str(proxy.is_even(100)))

Objets DateTime

class xmlrpc.client.DateTime

Cette classe peut être initialisée avec les secondes écoulées depuis epoch, un n-uplet temporel (semblable à un time.struct_time), une chaîne au format ISO 8601 ou une instance de datetime.datetime. Elle dispose des méthodes suivantes, prises en charge principalement pour un usage interne par le code de sérialisation-désérialisation :

decode(string)

Accepte une chaîne comme nouvelle valeur temporelle de l'instance.

encode(out)

Sérialise ce DateTime au format attendu par XML-RPC et l'écrit dans l'objet de flux out.

Elle prend également en charge certains opérateurs natifs de Python via les méthodes de comparaison riches et __repr__().

Voici un exemple concret. Le code du serveur :

import datetime
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client

def today():
    today = datetime.datetime.today()
    return xmlrpc.client.DateTime(today)

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(today, "today")
server.serve_forever()

Le code client correspondant au serveur précédent :

import xmlrpc.client
import datetime

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")

today = proxy.today()
# convert the ISO8601 string to a datetime object
converted = datetime.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print("Today: %s" % converted.strftime("%d.%m.%Y, %H:%M"))

Objets binaires

class xmlrpc.client.Binary

Cette classe peut être initialisée à partir d'instances de bytes (qui peuvent inclure des NUL). L'accès principal au contenu d'un objet Binary est fourni par un attribut :

data

Données binaires encapsulées par l'instance Binary. Les données sont fournies sous forme d'objet bytes.

Les objets Binary ont les méthodes suivantes, prises en charge principalement pour un usage interne par le code de sérialisation-désérialisation :

decode(bytes)

Accepte un objet bytes encodant de la donnée en base64 et le décode comme les nouvelles données de l'instance.

encode(out)

Sérialise cette instance en base 64 tel qu'attendu par XML-RPC dans l'objet de flux out.

Les données encodées sont découpées en lignes de 76 caractères conformément à la RFC 2045 section 6.8, qui était la spécification base64 standard de facto lorsque la spécification XML-RPC a été écrite.

Elle prend également en charge certains opérateurs natifs de Python via les méthodes __eq__() et __ne__().

Exemple d'utilisation des objets binaires. Nous allons transférer une image via XMLRPC :

from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client

def python_logo():
    with open("python_logo.jpg", "rb") as handle:
        return xmlrpc.client.Binary(handle.read())

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(python_logo, 'python_logo')

server.serve_forever()

Le client récupère l'image et l'enregistre dans un fichier :

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
with open("fetched_python_logo.jpg", "wb") as handle:
    handle.write(proxy.python_logo().data)

Objets Fault

class xmlrpc.client.Fault

Un objet Fault encapsule le contenu d'une balise d'erreur XML-RPC. Les objets d'erreurs ont les attributs suivants :

faultCode

Entier indiquant le type d'erreur.

faultString

Chaîne contenant un message de diagnostic associé à l'erreur.

Dans l'exemple suivant, nous allons provoquer intentionnellement une Fault en renvoyant un objet de type complexe. Le code du serveur :

from xmlrpc.server import SimpleXMLRPCServer

# A marshalling error is going to occur because we're returning a
# complex number
def add(x, y):
    return x+y+0j

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(add, 'add')

server.serve_forever()

Le code client correspondant au serveur précédent :

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
try:
    proxy.add(2, 5)
except xmlrpc.client.Fault as err:
    print("A fault occurred")
    print("Fault code: %d" % err.faultCode)
    print("Fault string: %s" % err.faultString)

Objets ProtocolError

class xmlrpc.client.ProtocolError

Un objet ProtocolError décrit une erreur de protocole dans la couche de transport sous-jacente (telle qu'une erreur 404 « not found » si le serveur nommé par l'URI n'existe pas). Il possède les attributs suivants :

url

URI ou URL qui a déclenché l'erreur.

errcode

Code d'erreur.

errmsg

Message d'erreur ou chaîne de diagnostic.

headers

Dictionnaire contenant les en-têtes de la requête HTTP/HTTPS qui a déclenché l'erreur.

Dans l'exemple suivant, nous allons intentionnellement provoquer une ProtocolError en fournissant un URI non valide :

import xmlrpc.client

# create a ServerProxy with a URI that doesn't respond to XMLRPC requests
proxy = xmlrpc.client.ServerProxy("http://google.com/")

try:
    proxy.some_method()
except xmlrpc.client.ProtocolError as err:
    print("A protocol error occurred")
    print("URL: %s" % err.url)
    print("HTTP/HTTPS headers: %s" % err.headers)
    print("Error code: %d" % err.errcode)
    print("Error message: %s" % err.errmsg)

Objets MultiCall

L'objet MultiCall fournit un moyen d'encapsuler plusieurs appels vers un serveur distant dans une seule requête [1].

class xmlrpc.client.MultiCall(server)

Crée un objet utilisé pour regrouper plusieurs appels de méthode. server est la cible de l'appel. Appeler des méthodes sur une instance de MultiCall ne fait que stocker le nom de la méthode et ses arguments, l'appel renvoie immédiatement None . Appeler l'objet lui-même entraîne la transmission de tous les appels stockés sous la forme d'une seule requête system.multicall. Le résultat de cet appel est un générateur ; itérer sur ce générateur donne les résultats individuels.

Voici un exemple d'utilisation de cette classe. Le code du serveur :

from xmlrpc.server import SimpleXMLRPCServer

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    return x // y

# A simple server with simple arithmetic functions
server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_multicall_functions()
server.register_function(add, 'add')
server.register_function(subtract, 'subtract')
server.register_function(multiply, 'multiply')
server.register_function(divide, 'divide')
server.serve_forever()

Le code client correspondant au serveur précédent :

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy("http://localhost:8000/")
multicall = xmlrpc.client.MultiCall(proxy)
multicall.add(7, 3)
multicall.subtract(7, 3)
multicall.multiply(7, 3)
multicall.divide(7, 3)
result = multicall()

print("7+3=%d, 7-3=%d, 7*3=%d, 7//3=%d" % tuple(result))

Fonctions utilitaires

xmlrpc.client.dumps(params, methodname=None, methodresponse=None, encoding=None, allow_none=False)

Convert params into an XML-RPC request, or into a response if methodresponse is true. params can be either a tuple of arguments or an instance of the Fault exception class. If methodresponse is true, only a single value can be returned, meaning that params must be of length 1. encoding, if supplied, is the encoding to use in the generated XML; the default is UTF-8. Python's None value cannot be used in standard XML-RPC; to allow using it via an extension, provide a true value for allow_none.

xmlrpc.client.loads(data, use_datetime=False, use_builtin_types=False)

Convertit une requête ou une réponse XML-RPC en une paire (params, methodname). params est un n-uplet d'arguments ; methodname est une chaîne, ou None si aucun nom de méthode n'est présent dans le paquet. Si le paquet XML-RPC représente une erreur, cette fonction lève une exception Fault. L'indicateur use_builtin_types peut être utilisé pour que les valeurs temporelles soient converties en objets datetime.datetime et que les données binaires soient présentées comme des objets bytes ; cet indicateur est faux par défaut.

L'indicateur obsolète use_datetime est similaire à use_builtin_types mais il s'applique uniquement aux valeurs temporelles.

Modifié dans la version 3.3: l'indicateur use_builtin_types a été ajouté.

Exemple d'utilisation du client

# simple test program (from the XML-RPC specification)
from xmlrpc.client import ServerProxy, Error

# server = ServerProxy("http://localhost:8000") # local server
with ServerProxy("http://betty.userland.com") as proxy:

    print(proxy)

    try:
        print(proxy.examples.getStateName(41))
    except Error as v:
        print("ERROR", v)

Pour accéder à un serveur XML-RPC via un mandataire HTTP, vous devez définir un transport personnalisé. L'exemple suivant montre comment faire :

import http.client
import xmlrpc.client

class ProxiedTransport(xmlrpc.client.Transport):

    def set_proxy(self, host, port=None, headers=None):
        self.proxy = host, port
        self.proxy_headers = headers

    def make_connection(self, host):
        connection = http.client.HTTPConnection(*self.proxy)
        connection.set_tunnel(host, headers=self.proxy_headers)
        self._connection = host, connection
        return connection

transport = ProxiedTransport()
transport.set_proxy('proxy-server', 8080)
server = xmlrpc.client.ServerProxy('http://betty.userland.com', transport=transport)
print(server.examples.getStateName(41))

Exemple d'utilisation du client et du serveur

Voir Exemple SimpleXMLRPCServer.

Notes