21.26. xmlrpc.client
--- XML-RPC クライアントアクセス¶
ソースコード: Lib/xmlrpc/client.py
XML-RPCはXMLを利用した遠隔手続き呼び出し(Remote Procedure Call)の一種で、HTTP(S)をトランスポートとして使用します。XML- RPCでは、クライアントはリモートサーバ(URIで指定されたサーバ)上のメソッドをパラメータを指定して呼び出し、構造化されたデータを取得します。このモジュールは、XML-RPCクライアントの開発をサポートしており、Pythonオブジェクトに適合する転送用XMLの変換の全てを行います。
警告
xmlrpc.client
モジュールは悪意を持って構築されたデータに対して安全ではありません。信頼できないデータや認証されていないデータを解析する必要がある場合は、XML の脆弱性 を参照してください。
バージョン 3.5 で変更: HTTPS URI の場合、 xmlrpc.client
は必要な証明書検証とホスト名チェックを全てデフォルトで行います。
-
class
xmlrpc.client.
ServerProxy
(uri, transport=None, encoding=None, verbose=False, allow_none=False, use_datetime=False, use_builtin_types=False, *, context=None)¶ バージョン 3.3 で変更: use_builtin_types フラグが追加されました。
ServerProxy
は、リモートのXML-RPCサーバとの通信を管理するオブジェクトです。最初のパラメータはURI(Uniform Resource Indicator)で、通常はサーバのURLを指定します。2番目のパラメータにはトランスポート・ファクトリを指定する事ができます。トランスポート・ファクトリを省略した場合、URLが https: ならモジュール内部のSafeTransport
インスタンスを使用し、それ以外の場合にはモジュール内部のTransport
インスタンスを使用します。オプションの 3 番目の引数はエンコード方法で、デフォルトでは UTF-8 です。オプションの 4 番目の引数はデバッグフラグです。The following parameters govern the use of the returned proxy instance. If allow_none is true, the Python constant
None
will be translated into XML; the default behaviour is forNone
to raise aTypeError
. This is a commonly-used extension to the XML-RPC specification, but isn't supported by all clients and servers; see http://ontosys.com/xml-rpc/extensions.php for a description. The use_builtin_types flag can be used to cause date/time values to be presented asdatetime.datetime
objects and binary data to be presented asbytes
objects; this flag is false by default.datetime.datetime
,bytes
andbytearray
objects may be passed to calls. The obsolete use_datetime flag is similar to use_builtin_types but it applies only to date/time values.HTTP及びHTTPS通信の両方で、
http://user:pass@host:port/path
のようなHTTP基本認証のための拡張URL構文をサポートしています。user:pass
はbase64でエンコードしてHTTPの'Authorization 'ヘッダとなり、XML-RPCメソッド呼び出し時に接続処理の一部としてリモートサーバに送信されます。リモートサーバが基本認証を要求する場合のみ、この機能を利用する必要があります。HTTPS URL が与えられたなら、 context はssl.SSLContext
にでき、基底のHTTP接続のSSL設定を設定します。生成されるインスタンスはリモートサーバへのプロクシオブジェクトで、RPC呼び出しを行う為のメソッドを持ちます。リモートサーバがイントロスペクション APIをサポートしている場合は、リモートサーバのサポートするメソッドを検索 (サービス検索)やサーバのメタデータの取得なども行えます。
以下の型をXMLに変換(XMLを通じてマーシャルする)する事ができます (特別な指定がない限り、逆変換でも同じ型として変換されます):
XML-RPC の型
Python の型
boolean
int
,i1
,i2
,i4
,i8
またはbiginteger
int
in range from -2147483648 to 2147483647. Values get the<int>
tag.double
またはfloat
float
. Values get the<double>
tag.string
array
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
. Returned type only.上記のXML-RPCでサポートする全データ型を使用することができます。メソッド呼び出し時、XML- RPCサーバエラーが発生すると
Fault
インスタンスを送出し、HTTP/HTTPSトランスポート層でエラーが発生した場合にはProtocolError
を送出します。Error
をベースとするFault
とProtocolError
の両方が発生します。現在のところxmlrpclibでは組み込み型のサブクラスのインスタンスをマーシャルすることはできません。文字列を渡す場合、
<
,>
,&
などのXMLで特殊な意味を持つ文字は自動的にエスケープされます。しかし、ASCII値0〜31の制御文字(もちろん、タブ'TAB',改行'LF',リターン'CR'は除く)などのXMLで使用することのできない文字を使用することはできず、使用するとそのXML-RPCリクエストはwell-formedなXMLとはなりません。そのようなバイト列を渡す必要がある場合は、bytes
,bytearray
クラスまたは後述のBinary
ラッパクラスを使用してください。Server
は、後方互換性の為にServerProxy
の別名として残されています。新しいコードではServerProxy
を使用してください。バージョン 3.5 で変更: context 引数が追加されました。
バージョン 3.6 で変更: Added support of type tags with prefixes (e.g.
ex:nil
). Added support of unmarshalling additional types used by Apache XML-RPC implementation for numerics:i1
,i2
,i8
,biginteger
,float
andbigdecimal
. See http://ws.apache.org/xmlrpc/types.html for a description.
参考
- XML-RPC HOWTO
数種類のプログラミング言語で記述された XML-RPCの操作とクライアントソフトウェアの素晴らしい説明が掲載されています。 XML- RPCクライアントの開発者が知っておくべきことがほとんど全て記載されています。
- XML-RPC Introspection
インストロペクションをサポートする、 XML-RPC プロトコルの拡張を解説しています。
- XML-RPC Specification
公式の仕様
- XML-RPC 非公式正誤表
Fredrik Lundh による "unofficial errata, intended to clarify certain details in the XML-RPC specification, as well as hint at 'best practices' to use when designing your own XML-RPC implementations."
21.26.1. ServerProxy オブジェクト¶
ServerProxy
インスタンスの各メソッドはそれぞれXML-RPCサーバの遠隔手続き呼び出しに対応しており、メソッドが呼び出されると名前と引数をシグネチャとしてRPCを実行します(同じ名前のメソッドでも、異なる引数シグネチャによってオーバロードされます)。RPC実行後、変換された値を返すか、または Fault
オブジェクトもしくは ProtocolError
オブジェクトでエラーを通知します。
予約属性 system
から、XMLイントロスペクションAPIの一般的なメソッドを利用する事ができます:
-
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サーバで実装されているメソッドの名前を指定し、そのメソッドを解説する文書文字列を取得します。文書文字列を取得できない場合は空文字列を返します。文書文字列にはHTMLマークアップが含まれます。
バージョン 3.5 で変更: Instances of ServerProxy
support the context manager protocol
for closing the underlying transport.
以下は、動作する例です。サーバ側のコード:
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)))
21.26.2. DateTime オブジェクト¶
-
class
xmlrpc.client.
DateTime
¶ このクラスは、エポックからの秒数、タプルで表現された時刻、ISO 8601形式の時間/日付文字列、
datetime.datetime
, のインスタンスのいずれかで初期化することができます。このクラスには以下のメソッドがあり、主にコードをマーシャル/アンマーシャルするための内部処理を行います:-
decode
(string)¶ 文字列をインスタンスの新しい時間を示す値として指定します。
また、比較と
__repr__()
で定義される演算子を使用することができます。-
以下は、動作する例です。サーバ側のコード:
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()
上記のサーバーに対するクライアントコード:
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"))
21.26.3. Binary オブジェクト¶
-
class
xmlrpc.client.
Binary
¶ このクラスは、バイト列データ(NULを含む)で初期化することができます。
Binary
の内容は、属性で参照します:Binary
オブジェクトは以下のメソッドを持ち、主に内部的にマーシャル/アンマーシャル時に使用されます:-
encode
(out)¶ バイナリ値をbase64でエンコードし、出力ストリームオブジェクト out に出力します。
エンコードされたデータは、 RFC 2045 section 6.8 にある通り、76文字ごとに改行されます。これは、XMC-RPC仕様が作成された時のデ・ファクト・スタンダードのbase64です。
-
バイナリオブジェクトの使用例です。 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)
21.26.4. Fault オブジェクト¶
-
class
xmlrpc.client.
Fault
¶ Fault
オブジェクトは、XML-RPCのfaultタグの内容をカプセル化しており、以下の属性を持ちます:-
faultCode
¶ 失敗のタイプを示す文字列。
-
faultString
¶ 失敗の診断メッセージを含む文字列。
-
以下のサンプルでは、複素数型のオブジェクトを返そうとして、故意に Fault
を起こしています。
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()
上記のサーバーに対するクライアントコード:
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)
21.26.5. ProtocolError オブジェクト¶
-
class
xmlrpc.client.
ProtocolError
¶ ProtocolError
オブジェクトはトランスポート層で発生したエラー(URI で指定したサーバが見つからなかった場合に発生する404 'not found'など)の内容を示し、以下の属性を持ちます:-
url
¶ エラーの原因となったURIまたはURL。
-
errcode
¶ エラーコード。
-
errmsg
¶ エラーメッセージまたは診断文字列。
-
headers
¶ エラーの原因となったHTTP/HTTPSリクエストを含む辞書。
-
次の例では、不適切な URI を利用して、故意に ProtocolError
を発生させています:
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)
21.26.6. MultiCall オブジェクト¶
遠隔のサーバに対する複数の呼び出しをひとつのリクエストにカプセル化する方法は、http://www.xmlrpc.com/discuss/msgReader%241208 で示されています。
-
class
xmlrpc.client.
MultiCall
(server)¶ 巨大な (boxcar) メソッド呼び出しに使えるオブジェクトを作成します。 server には最終的に呼び出しを行う対象を指定します。作成した MultiCall オブジェクトを使って呼び出しを行うと、即座に
None
を返し、呼び出したい手続き名とパラメタをMultiCall
オブジェクトに保存するだけに留まります。オブジェクト自体を呼び出すと、それまでに保存しておいたすべての呼び出しを単一のsystem.multicall
リクエストの形で伝送します。呼び出し結果はジェネレータ(generator)になります。このジェネレータにわたってイテレーションを行うと、個々の呼び出し結果を返します。
以下は、このクラスの使用例です。サーバ側のコード:
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()
上記のサーバーに対するクライアントコード:
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))
21.26.7. 補助関数¶
-
xmlrpc.client.
dumps
(params, methodname=None, methodresponse=None, encoding=None, allow_none=False)¶ params を XML-RPC リクエストの形式に変換します。 methodresponse が真の場合、XML-RPC レスポンスの形式に変換します。 params に指定できるのは、引数からなるタプルか
Fault
例外クラスのインスタンスです。 methodresponse が真の場合、単一の値だけを返します。従って、 params の長さも 1 でなければなりません。 encoding を指定した場合、生成される XML のエンコード方式になります。デフォルトは UTF-8 です。 Python のNone
は標準の XML-RPC には利用できません。None
を使えるようにするには、 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 フラグが追加されました。
21.26.8. クライアントのサンプル¶
# 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)
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))