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
ServerProxyest 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 deSafeTransportpour les URL HTTPS sinon d'une instance deTransport. 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
Noneest traduite en XML ; le comportement par défaut est queNonelève uneTypeError. 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 objetsdatetime.datetimeet que les données binaires soient présentées comme des objetsbytes; cet indicateur est faux par défaut. Les objetsdatetime.datetime,bytesetbytearraypeuvent ê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'unessl.SSLContextpour 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 partieuser:passest 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
booleanint,i1,i2,i4,i8oubigintegerintcompris entre -2147483648 et 2147483647. Les valeurs sont marquées avec la balise<int>.doubleoufloatfloat. Les valeurs reçoivent la balise<double>.stringarraylisteoun-upletcontenant des éléments conformes. Les tableaux sont renvoyés sous forme delistes.structdict. 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.iso8601DateTimeoudatetime.datetime. Le type renvoyé dépend des valeurs des indicateurs use_builtin_types et use_datetime.base64Binary,bytesoubytearray. Le type renvoyé dépend de la valeur de l'indicateur use_builtin_types.nilLa constante
None. Son utilisation n'est autorisée que si allow_none est vrai.bigdecimaldecimal.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'exceptionProtocolErrorutilisée pour signaler une erreur dans la couche de transport HTTP/HTTPS.FaultetProtocolErrordérivent d'une exception mère appeléeError. Notez que le modulexmlrpc.clientne 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 classesbytesoubytearrayou la classe de surcoucheBinarydécrite ci-dessous.Serverest conservé comme alias pourServerProxypour des raisons de compatibilité descendante. Le nouveau code doit utiliserServerProxy.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,floatetbigdecimal. 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 dedatetime.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
DateTimeau 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 richeset__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 objetBinaryest fourni par un attribut :- data¶
Données binaires encapsulées par l'instance
Binary. Les données sont fournies sous forme d'objetbytes.
Les objets
Binaryont 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
bytesencodant 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
Faultencapsule 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
ProtocolErrordé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
MultiCallne fait que stocker le nom de la méthode et ses arguments, l'appel renvoie immédiatementNone. Appeler l'objet lui-même entraîne la transmission de tous les appels stockés sous la forme d'une seule requêtesystem.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
Faultexception 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'sNonevalue 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, ouNonesi 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 exceptionFault. L'indicateur use_builtin_types peut être utilisé pour que les valeurs temporelles soient converties en objetsdatetime.datetimeet que les données binaires soient présentées comme des objetsbytes; 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