xmlrpc.client --- XML-RPC クライアントアクセス

ソースコード: Lib/xmlrpc/client.py


XML-RPCはXMLを利用した遠隔手続き呼び出し(Remote Procedure Call)の一種で、HTTP(S)をトランスポートとして使用します。XML- RPCでは、クライアントはリモートサーバ(URIで指定されたサーバ)上のメソッドをパラメータを指定して呼び出し、構造化されたデータを取得します。このモジュールは、XML-RPCクライアントの開発をサポートしており、Pythonオブジェクトに適合する転送用XMLの変換の全てを行います。

警告

The xmlrpc.client module is not secure against maliciously constructed data. If you need to parse untrusted or unauthenticated data, see XML security.

バージョン 3.5 で変更: HTTPS URI の場合、 xmlrpc.client は必要な証明書検証とホスト名チェックを全てデフォルトで行います。

利用可能な環境: not WASI.

このモジュールは WebAssembly では動作しないか、利用不可です。詳しくは、WebAssembly プラットフォーム を見てください。

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

ServerProxy は、リモートのXML-RPCサーバとの通信を管理するオブジェクトです。最初のパラメータはURI(Uniform Resource Indicator)で、通常はサーバのURLを指定します。2番目のパラメータにはトランスポート・ファクトリを指定する事ができます。トランスポート・ファクトリを省略した場合、URLが https: ならモジュール内部の SafeTransport インスタンスを使用し、それ以外の場合にはモジュール内部の Transport インスタンスを使用します。オプションの 3 番目の引数はエンコード方法で、デフォルトでは UTF-8 です。オプションの 4 番目の引数はデバッグフラグです。

以下の引数は、返されるプロキシインスタンスの動作を制御します。 allow_none が真の場合、Python の定数 None は XML に変換されます。 デフォルトでは None を渡すと TypeError が送出されます。 これは XML-RPC 仕様のよく使われる拡張ですが、すべてのクライアントやサーバーがサポートしているわけではありません。 説明は http://ontosys.com/xml-rpc/extensions.php を参照してください。 use_builtin_types フラグを使うと、日時の値を datetime.datetime オブジェクト、バイナリデータを bytes オブジェクトとして受け取れます。 このフラグのデフォルトは偽です。 呼び出しには datetime.datetime、bytes、bytearray オブジェクトを渡せます。 headers は各リクエストで送信する HTTP ヘッダーを指定する省略可能な引数で、ヘッダー名と値を表す 2 要素のタプルのシーケンス (例えば [('Header-Name', 'value')]) で指定します。 HTTPS URL を指定した場合、context に ssl.SSLContext を指定して、内部の HTTPS 接続の SSL 設定を構成できます。 旧式の use_datetime フラグは use_builtin_types と似ていますが、日時の値にだけ適用されます。

バージョン 3.3 で変更: use_builtin_types フラグが追加されました。

バージョン 3.8 で変更: headers 引数が追加されました。

HTTP及びHTTPS通信の両方で、 http://user:pass@host:port/path のようなHTTP基本認証のための拡張URL構文をサポートしています。 user:pass はbase64でエンコードしてHTTPの'Authorization 'ヘッダとなり、XML-RPCメソッド呼び出し時に接続処理の一部としてリモートサーバに送信されます。リモートサーバが基本認証を要求する場合のみ、この機能を利用する必要があります。

生成されるインスタンスはリモートサーバへのプロクシオブジェクトで、RPC呼び出しを行う為のメソッドを持ちます。リモートサーバがイントロスペクション APIをサポートしている場合は、リモートサーバのサポートするメソッドを検索 (サービス検索)やサーバのメタデータの取得なども行えます。

以下の型をXMLに変換(XMLを通じてマーシャルする)する事ができます (特別な指定がない限り、逆変換でも同じ型として変換されます):

XML-RPC の型

Python の型

boolean

bool

int, i1, i2, i4, i8 または biginteger

-2147483648 から 2147483647 までの範囲の int。 値には <int> タグが付けられます。

double または float

float。 値には <double> タグが付けられます。

string

str

array

適合する要素を持つ list または tuple。array は list として返します。

struct

dict。 キーは文字列でなければならず、値には変換可能な任意の型を使用できます。 ユーザー定義クラスのインスタンスも渡せますが、転送されるのは __dict__ 属性だけです。

dateTime.iso8601

DateTime または datetime.datetime。返される型は use_builtin_types および use_datetime の値に依ります。

base64

Binary、 bytes または bytearray。返される型は use_builtin_types フラグの値に依ります。

nil

None 定数。 allow_none が真の場合にのみ渡すことが出来ます。

bigdecimal

decimal.Decimal。 返される値としてのみ使われます。

以上が XML-RPC でサポートされるデータ型のすべてです。 メソッド呼び出しでは、XML-RPC サーバーのエラーを表す Fault インスタンスや、HTTP/HTTPS トランスポート層のエラーを表す ProtocolError が送出されることもあります。 Fault と ProtocolError は、どちらも Error という基底クラスから派生しています。 現在の xmlrpc クライアントモジュールは、組み込み型のサブクラスのインスタンスをマーシャルできないことに注意してください。

文字列を渡す場合、 <, >, & などのXMLで特殊な意味を持つ文字は自動的にエスケープされます。しかし、ASCII値0〜31の制御文字(もちろん、タブ'TAB',改行'LF',リターン'CR'は除く)などのXMLで使用することのできない文字を使用することはできず、使用するとそのXML-RPCリクエストはwell-formedなXMLとはなりません。そのようなバイト列を渡す必要がある場合は、 bytes, bytearray クラスまたは後述の Binary ラッパークラスを使用してください。

Server は、後方互換性の為に ServerProxy の別名として残されています。新しいコードでは ServerProxy を使用してください。

バージョン 3.5 で変更: context 引数が追加されました。

バージョン 3.6 で変更: 接頭辞付きの型タグ (ex:nil など) をサポートしました。 Apache の XML-RPC 実装が数値に使う追加の型 i1、i2、i8、biginteger、float、bigdecimal のアンマーシャルをサポートしました。 説明は https://ws.apache.org/xmlrpc/types.html を参照してください。

参考

XML-RPC HOWTO

数種類のプログラミング言語で記述された XML-RPCの操作とクライアントソフトウェアの素晴らしい説明が掲載されています。 XML- RPCクライアントの開発者が知っておくべきことがほとんど全て記載されています。

XML-RPC Introspection

インストロペクションをサポートする、 XML-RPC プロトコルの拡張を解説しています。

XML-RPC Specification

公式の仕様

ServerProxy オブジェクト

ServerProxy インスタンスの各メソッドはそれぞれXML-RPCサーバの遠隔手続き呼び出しに対応しており、メソッドが呼び出されると名前と引数をシグネチャとしてRPCを実行します(同じ名前のメソッドでも、異なる引数シグネチャによってオーバロードされます)。RPC実行後、変換された値を返すか、または Fault オブジェクトもしくは ProtocolError オブジェクトでエラーを通知します。

XML イントロスペクション API をサポートするサーバーは、予約された system 属性の下にまとめられた共通のメソッドを提供します。

ServerProxy.system.listMethods()

XML-RPCサーバがサポートするメソッド名(system以外)を格納する文字列のリストを返します。

ServerProxy.system.methodSignature(name)

XML-RPCサーバで実装されているメソッドの名前を指定し、利用可能なシグネチャの配列を取得します。シグネチャは型のリストで、先頭の型は戻り値の型を示し、以降はパラメータの型を示します。

XML-RPCでは複数のシグネチャ(オーバロード)を使用することができるので、単独のシグネチャではなく、シグネチャのリストを返します。

シグネチャは、メソッドが使用する最上位のパラメータにのみ適用されます。例えばあるメソッドのパラメータが構造体の配列で戻り値が文字列の場合、シグネチャは単に"string, array" となります。パラメータが三つの整数で戻り値が文字列の場合は"string, int, int, int"となります。

メソッドにシグネチャが定義されていない場合、配列以外の値が返ります。 Pythonでは、この値はlist以外の値となります。

ServerProxy.system.methodHelp(name)

XML-RPC サーバーが実装するメソッドの名前を引数として 1 つ受け取り、そのメソッドの使い方を説明する文書文字列を返します。 そのような文字列がない場合は空文字列を返します。 文書文字列には HTML マークアップが含まれることがあります。

バージョン 3.5 で変更: ServerProxy インスタンスは、内部のトランスポートを閉じるための コンテキストマネージャー プロトコルをサポートしました。

以下は、動作する例です。サーバ側のコード:

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()

上記のサーバーに対するクライアントコード:

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)))

DateTime オブジェクト

class xmlrpc.client.DateTime

このクラスは、エポックからの秒数、タプルで表現された時刻、ISO 8601形式の時間/日付文字列、 datetime.datetime のインスタンスのいずれかで初期化することができます。 このクラスには以下のメソッドがあり、主にマーシャル/アンマーシャルを行うコードから内部的に使用されます:

decode(string)

文字列をインスタンスの新しい時間を示す値として指定します。

encode(out)

出力ストリームオブジェクト out に、XML-RPCエンコーディングの DateTime 値を出力します。

拡張比較 メソッドと __repr__() メソッドを通じて、Python の組み込み演算子の一部もサポートしています。

以下は、動作する例です。サーバ側のコード:

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

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

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

上記のサーバーに対するクライアントコード:

import xmlrpc.client
import datetime as dt

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

today = proxy.today()
# convert the ISO 8601 string to a datetime object
converted = dt.datetime.strptime(today.value, "%Y%m%dT%H:%M:%S")
print(f"Today: {converted.strftime('%d.%m.%Y, %H:%M')}")

Binary オブジェクト

class xmlrpc.client.Binary

このクラスは、バイト列データ(NULを含む)で初期化することができます。 Binary の内容は、属性で参照します:

data

Binary インスタンスがカプセル化しているバイナリデータ。このデータは bytes オブジェクトです。

Binary オブジェクトは以下のメソッドを持ち、主に内部的にマーシャル/アンマーシャル時に使用されます:

decode(bytes)

指定されたbase64 bytes オブジェクトをデコードし、インスタンスのデータとします。

encode(out)

バイナリ値をbase64でエンコードし、出力ストリームオブジェクト out に出力します。

エンコードされたデータは、 RFC 2045 section 6.8 にある通り、76文字ごとに改行されます。これは、XMC-RPC仕様が作成された時のデ・ファクト・スタンダードのbase64です。

__eq__() メソッドと __ne__() メソッドを通じて、Python の組み込み演算子の一部もサポートしています。

バイナリオブジェクトの使用例です。 XML-RPCごしに画像を転送します。

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()

クライアントは画像を取得して、ファイルに保存します。

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)

Fault オブジェクト

class xmlrpc.client.Fault

Fault オブジェクトは、XML-RPCのfaultタグの内容をカプセル化しており、以下の属性を持ちます:

faultCode

失敗のタイプを示す整数。

faultString

失敗の診断メッセージを含む文字列。

以下のサンプルでは、複素数型のオブジェクトを返そうとして、故意に Fault を起こしています。

from xmlrpc.server import SimpleXMLRPCServer

# 複素数を返すため、マーシャル時にエラーが発生する
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()

上記のサーバーに対するクライアントコード:

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)

ProtocolError オブジェクト

class xmlrpc.client.ProtocolError

ProtocolError オブジェクトはトランスポート層で発生したエラー(URI で指定したサーバが見つからなかった場合に発生する404 'not found'など)の内容を示し、以下の属性を持ちます:

url

エラーの原因となったURIまたはURL。

errcode

エラーコード。

errmsg

エラーメッセージまたは診断文字列。

headers

エラーの原因となった HTTP/HTTPS リクエストのヘッダーを含む辞書。

次の例では、不適切な URI を利用して、故意に ProtocolError を発生させています:

import xmlrpc.client

# XMLRPC リクエストに応答しない URI で ServerProxy を作成する
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)

MultiCall オブジェクト

MultiCall オブジェクトは遠隔のサーバに対する複数の呼び出しをひとつのリクエストにカプセル化する方法を提供します [1]。

class xmlrpc.client.MultiCall(server)

巨大な (boxcar) メソッド呼び出しに使えるオブジェクトを作成します。 server には最終的に呼び出しを行う対象を指定します。作成した MultiCall オブジェクトを使って呼び出しを行うと、即座に None を返し、呼び出したい手続き名とパラメタを MultiCall オブジェクトに保存するだけに留まります。オブジェクト自体を呼び出すと、それまでに保存しておいたすべての呼び出しを単一の system.multicall リクエストの形で伝送します。呼び出し結果は ジェネレータ になります。このジェネレータにわたってイテレーションを行うと、個々の呼び出し結果を返します。

以下は、このクラスの使用例です。サーバ側のコード:

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

# 簡単な算術関数を持つシンプルなサーバー
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()

上記のサーバーに対するクライアントコード:

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))

補助関数

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)

XML-RPC リクエストまたはレスポンスを (params, methodname) の形式をとる Python オブジェクトにします。 params は引数のタプルです。 methodname は文字列で、パケット中にメソッド名がない場合には None になります。例外条件を示す XML-RPC パケットの場合には、 Fault 例外を送出します。 use_builtin_types フラグは datetime.datetime のオブジェクトとして日付/時刻を、 bytes のオブジェクトとしてバイナリデータを表現する時に使用し、デフォルトでは false に設定されています。

非推奨となった use_datetime フラグは use_builtin_types に似ていますが date/time 値にのみ適用されます。

バージョン 3.3 で変更: use_builtin_types フラグが追加されました。

クライアントのサンプル

# 簡単なテストプログラム (XML-RPC 仕様から引用)
from xmlrpc.client import ServerProxy, Error

# server = ServerProxy("http://localhost:8000") # ローカルサーバー
with ServerProxy("http://betty.userland.com") as proxy:

    print(proxy)

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

XML-RPC サーバに HTTP プロキシを経由して接続する場合、カスタムトランスポートを定義する必要があります。以下に例を示します:

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))

クライアントとサーバーの利用例

SimpleXMLRPCServer example を参照してください。

脚注