20.23. xmlrpclib — XML-RPC クライアントアクセス — Python 2.7ja1 documentation

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.7ja1 documentation »
- Python 標準ライブラリ »
- 20. インターネットプロトコルとその支援 »

# 20.23. `xmlrpclib` — XML-RPC クライアントアクセス

ノート

`xmlrpclib` モジュールは、Python 3では `xmlrpc.client` にリネームされました。 2to3 ツールは、自動的にソースコードのimportをPython 3用に修正します。

バージョン 2.2 で追加.

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

class `xmlrpclib.` `ServerProxy`(uri[, transport[, encoding[, verbose[, allow_none[, use_datetime]]]]])

  `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.html を参照してください。 use_datetime フラグは `datetime.datetime` のオブジェクトとして日付/時刻を表現する時に使用し、デフォルトでは false に設定されています。呼び出しに `datetime.datetime` のオブジェクトを渡すことができます。

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

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

  `ServerProxy` インスタンスのメソッドは引数としてPythonの基礎型とオブジェクトを受け取り、戻り値としてPythonの基礎型かオブジェクトを返します。以下の型をXMLに変換(XMLを通じてマーシャルする)する事ができます (特別な指定がない限り、逆変換でも同じ型として変換されます):

  名前 | 意味
  --- | ---
  boolean | 定数 `True` と `False`
  整数 | そのまま
  浮動小数点 | そのまま
  文字列 | そのまま
  配列 | 変換可能な要素を含むPythonシーケンス。戻り値はリスト。
  構造体 | Pythonの辞書。キーは文字列のみ。全ての値は変換可能でなくてはならない。ユーザー定義型を渡すこともできます。 __dict__ の属性のみ転送されます。
  日付 | エポックからの経過秒数(`DateTime` クラスのインスタンスとして渡す) もしくは、 `datetime.datetime` のインスタンス
  バイナリ | `Binary` ラッパクラスのインスタンス

  上記のXML-RPCでサポートする全データ型を使用することができます。メソッド呼び出し時、XML- RPCサーバエラーが発生すると `Fault` インスタンスを送出し、HTTP/HTTPSトランスポート層でエラーが発生した場合には `ProtocolError` を送出します。 `Error` をベースとする `Fault` と `ProtocolError` の両方が発生します。 Python 2.2以降では組み込み型のサブクラスを作成する事ができますが、現在のところxmlrpclibではそのようなサブクラスのインスタンスをマーシャルすることはできません。

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

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

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

  バージョン 2.6 で変更: ニュースタイルクラス(new-style class)も、 __dict__ 属性を持っていて、特別な方法でマーシャルされている親クラスを 持っていなければ、渡すことができます。

参考

XML-RPC HOWTO
  週種類のプログラミング言語で記述された XML-RPCの操作とクライアントソフトウェアの素晴らしい説明が掲載されています。 XML- RPCクライアントの開発者が知っておくべきことがほとんど全て記載されています。
XML-RPC-Hacks page
  イントロスペクションとマルチコールをサポートしているオープンソースの拡張ライブラリについて説明しています。
XML-RPC Introspection
  インストロペクションをサポートする、 XML-RPC プロトコルの拡張を解説しています。
XML-RPC Specification
  公式の仕様
Unofficial XML-RPC Errata
  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.”

## 20.23.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では複数のシグネチャ(オーバロード)を使用することができるので、単独のシグネチャではなく、シグネチャのリストを返します。

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

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

`ServerProxy.system.` `methodHelp`(name)

  XML-RPCサーバで実装されているメソッドの名前を指定し、そのメソッドを解説する文書文字列を取得します。文書文字列を取得できない場合は空文字列を返します。文書文字列にはHTMLマークアップが含まれます

## 20.23.2. Boolean オブジェクト

このクラスは全てのPythonの値で初期化することができ、生成されるインスタンスは指定した値の真偽値によってのみ決まります。Booleanという名前から想像される通りに各種のPython演算子を実装しており、 `__cmp__()`, `__repr__()`, `__int__()`, `__nonzero__()` で定義される演算子を使用することができます。

以下のメソッドは、主に内部的にアンマーシャル時に使用されます:

`Boolean.` `encode`(out)

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

動作する例です。サーバー側:

    import xmlrpclib
    from SimpleXMLRPCServer 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 xmlrpclib

    proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
    print "3 is even: %s" % str(proxy.is_even(3))
    print "100 is even: %s" % str(proxy.is_even(100))

## 20.23.3. DateTime オブジェクト

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

`DateTime.` `decode`(string)

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

`DateTime.` `encode`(out)

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

また、 `__cmp__()` と `__repr__()` で定義される演算子を使用することができます。

## 20.23.4. Binary オブジェクト

このクラスは、文字列(NULを含む)で初期化することができます。 `Binary` の内容は、属性で参照します。

`Binary.` `data`

  `Binary` インスタンスがカプセル化しているバイナリデータ。このデータは8bitクリーンです。

以下のメソッドは、主に内部的にマーシャル/アンマーシャル時に使用されます:

`Binary.` `decode`(string)

  指定されたbase64文字列をデコードし、インスタンスのデータとします。

`Binary.` `encode`(out)

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

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

また、 `__cmp__()` で定義される演算子を使用することができます。

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

    from SimpleXMLRPCServer import SimpleXMLRPCServer
    import xmlrpclib

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

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

    server.serve_forever()

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

    import xmlrpclib

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

## 20.23.5. Fault オブジェクト

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

`Fault.` `faultCode`

  失敗のタイプを示す文字列。

`Fault.` `faultString`

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

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

    from SimpleXMLRPCServer 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 xmlrpclib

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

## 20.23.6. ProtocolError オブジェクト

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

`ProtocolError.` `url`

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

`ProtocolError.` `errcode`

  エラーコード。

`ProtocolError.` `errmsg`

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

`ProtocolError.` `headers`

  エラーの原因となったHTTP/HTTPSリクエストを含む文字列。

次の例では、XMLRPC サーバを指していない URI を利用して、故意に `ProtocolError` を発生させています。

    import xmlrpclib

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

    try:
        proxy.some_method()
    except xmlrpclib.ProtocolError, 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

## 20.23.7. MultiCall オブジェクト

バージョン 2.4 で追加.

遠隔のサーバに対する複数の呼び出しをひとつのリクエストにカプセル化する方法は、http://www.xmlrpc.com/discuss/msgReader%241208 で示されています。

class `xmlrpclib.` `MultiCall`(server)

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

以下にこのクラスの使い方を示します。

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

    from SimpleXMLRPCServer 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 xmlrpclib

    proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
    multicall = xmlrpclib.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)

## 20.23.8. 補助関数

`xmlrpclib.` `boolean`(value)

  Pythonの値を、XML-RPCのBoolean定数 `True` または `False` に変換します。

`xmlrpclib.` `dumps`(params[, methodname[, methodresponse[, encoding[, allow_none]]]])

  params を XML-RPC リクエストの形式に変換します。 methodresponse が真の場合、XML-RPC レスポンスの形式に変換します。 params に指定できるのは、引数からなるタプルか `Fault` 例外クラスのインスタンスです。 methodresponse が真の場合、単一の値だけを返します。従って、 params の長さも 1 でなければなりません。 encoding を指定した場合、生成される XML のエンコード方式になります。デフォルトは UTF-8 です。 Python の `None` は標準の XML-RPC には利用できません。 `None` を使えるようにするには、 allow_none を真にして、拡張機能つきにしてください。

`xmlrpclib.` `loads`(data[, use_datetime])

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

  バージョン 2.5 で変更: use_datetime フラグを追加.

## 20.23.9. クライアントのサンプル

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

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

    print server

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

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

    import xmlrpclib, httplib

    class ProxiedTransport(xmlrpclib.Transport):
        def set_proxy(self, proxy):
            self.proxy = proxy
        def make_connection(self, host):
            self.realhost = host
            h = httplib.HTTP(self.proxy)
            return h
        def send_request(self, connection, handler, request_body):
            connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler))
        def send_host(self, connection, host):
            connection.putheader('Host', self.realhost)

    p = ProxiedTransport()
    p.set_proxy('proxy-server:8080')
    server = xmlrpclib.Server('http://time.xmlrpc.com/RPC2', transport=p)
    print server.currentTime.getCurrentTime()

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

SimpleXMLRPCServer の例 を参照してください。

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.7ja1 documentation »
- Python 標準ライブラリ »
- 20. インターネットプロトコルとその支援 »