# `xmlrpc.client` — XML-RPC client access

Вихідний код: Lib/xmlrpc/client.py

XML-RPC — це метод віддаленого виклику процедури, який використовує XML, що передається через HTTP(S) як транспорт. З його допомогою клієнт може викликати методи з параметрами на віддаленому сервері (сервер має назву 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` тепер виконує всі необхідні перевірки сертифікатів і імен хостів за умовчанням.

Availability: not WASI.

This module does not work or is not available on WebAssembly. See WebAssembly platforms for more information.

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 (уніфікований індикатор ресурсу), і зазвичай це URL-адреса сервера. Необов’язковий другий аргумент - екземпляр транспортної фабрики; за замовчуванням це внутрішній екземпляр `SafeTransport` для https: URL-адрес і внутрішній екземпляр HTTP `Transport` в інших випадках. Необов’язковий третій аргумент – це кодування, за умовчанням UTF-8. Необов’язковий четвертий аргумент - це позначка налагодження.

  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 for `None` to raise a `TypeError`. 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 as `datetime.datetime` objects and binary data to be presented as `bytes` objects; this flag is false by default. `datetime.datetime`, `bytes` and `bytearray` objects may be passed to calls. The headers parameter is an optional sequence of HTTP headers to send with each request, expressed as a sequence of 2-tuples representing the header name and value. (e.g. `[('Header-Name', 'value')]`). If an HTTPS URL is provided, context may be `ssl.SSLContext` and configures the SSL settings of the underlying HTTPS connection. The obsolete use_datetime flag is similar to use_builtin_types but it applies only to date/time values.

  Змінено в версії 3.3: Додано прапорець use_builtin_types.

  Змінено в версії 3.8: Додано параметр headers.

  Both the HTTP and HTTPS transports support the URL syntax extension for HTTP Basic Authentication: `http://user:pass@host:port/path`. The `user:pass` portion will be base64-encoded as an HTTP „Authorization“ header, and sent to the remote server as part of the connection process when invoking an XML-RPC method. You only need to use this if the remote server requires a Basic Authentication user and password.

  Повернений екземпляр — це проксі-об’єкт із методами, які можна використовувати для виклику відповідних викликів RPC на віддаленому сервері. Якщо віддалений сервер підтримує API інтроспекції, проксі також можна використовувати для запиту віддаленого сервера щодо методів, які він підтримує (виявлення служби), і отримання інших пов’язаних із сервером метаданих.

  Типи, які є сумісними (наприклад, які можна маршалізувати через XML), включають наступне (і, якщо не зазначено, вони не маршалізуються як той самий тип Python):

  Тип XML-RPC | Тип Python
  --- | ---
  `логічний` | `bool`
  `int`, `i1`, `i2`, `i4`, `i8` або `biginteger` | `int` в діапазоні від -2147483648 до 2147483647. Значення отримують тег `<int>`.
  `double` або `float` | `float`. Значення отримують тег `<double>`.
  `рядок` | `str`
  `array` | `list` або `tuple`, що містять відповідні елементи. Масиви повертаються як `lists`.
  `структура` | `dict`. Ключі мають бути рядками, значення можуть мати будь-який відповідний тип. Можна передати об’єкти визначених користувачем класів; передається лише їхній атрибут `__dict__`.
  `dateTime.iso8601` | `DateTime` або `datetime.datetime`. Повернений тип залежить від значень прапорців use_builtin_types і use_datetime.
  `base64` | `Binary`, `bytes` або `bytearray`. Повернений тип залежить від значення прапорця use_builtin_types.
  `нуль` | Константа `None`. Передача дозволена, лише якщо allow_none має значення true.
  `великий десятковий` | `decimal.Decimal`. Тільки повернутий тип.

  Це повний набір типів даних, які підтримує XML-RPC. Виклики методів також можуть викликати спеціальний екземпляр `Fault`, який використовується для сигналізації про помилки сервера XML-RPC, або `ProtocolError`, який використовується для сигналізації про помилку на транспортному рівні HTTP/HTTPS. І `Fault`, і `ProtocolError` походять від базового класу під назвою `Error`. Зауважте, що клієнтський модуль xmlrpc наразі не маршалює екземпляри підкласів вбудованих типів.

  Під час передачі рядків спеціальні символи XML, такі як `<`, `>` і `&`, будуть автоматично екрановані. Однак відповідальністю абонента є переконатися, що рядок вільний від символів, які не дозволені в XML, таких як контрольні символи зі значеннями ASCII від 0 до 31 (за винятком, звичайно, табуляції, нового рядка та повернення каретки); якщо цього не зробити, запит XML-RPC не є правильно сформованим XML. Якщо вам потрібно передати довільні байти через XML-RPC, використовуйте класи `bytes` або `bytearray` або клас-оболонку `Binary`, описаний нижче.

  `Server` зберігається як псевдонім для `ServerProxy` для зворотної сумісності. Новий код має використовувати `ServerProxy`.

  Змінено в версії 3.5: Додано аргумент контекст.

  Змінено в версії 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` and `bigdecimal`. See https://ws.apache.org/xmlrpc/types.html for a description.

Дивись також

XML-RPC HOWTO

  Гарний опис роботи XML-RPC і клієнтського програмного забезпечення кількома мовами. Містить практично все, що потрібно знати розробнику клієнта XML-RPC.

XML-RPC Introspection

  Описує розширення протоколу XML-RPC для самоаналізу.

Специфікація XML-RPC

  Офіційна специфікація.

## Об’єкти ServerProxy

Екземпляр `ServerProxy` має метод, що відповідає кожному виклику віддаленої процедури, прийнятому сервером XML-RPC. Виклик методу виконує RPC, відправляється як за назвою, так і за підписом аргументу (наприклад, те саме ім’я методу може бути перевантажено декількома підписами аргументів). RPC завершується поверненням значення, яке може бути або повернутими даними відповідного типу, або об’єктом `Fault` чи `ProtocolError`, що вказує на помилку.

Сервери, які підтримують API інтроспекції XML, підтримують деякі загальні методи, згруповані в зарезервованому атрибуті `system`:

ServerProxy.system.listMethods()

  Цей метод повертає список рядків, по одному для кожного (несистемного) методу, який підтримує сервер XML-RPC.

ServerProxy.system.methodSignature(name)

  Цей метод приймає один параметр, назву методу, реалізованого сервером XML-RPC. Він повертає масив можливих підписів для цього методу. Підпис — це масив типів. Перший із цих типів є типом повернення методу, решта є параметрами.

  Оскільки дозволено кілька підписів (тобто перевантаження), цей метод повертає список підписів, а не одиночний.

  Самі підписи обмежені параметрами верхнього рівня, очікуваними методом. Наприклад, якщо метод очікує один масив структур як параметр і повертає рядок, його підпис буде просто «рядок, масив». Якщо він очікує три цілі числа та повертає рядок, його підписом є «рядок, int, int, int».

  Якщо для методу не визначено підпису, повертається немасивне значення. У Python це означає, що типом поверненого значення буде щось інше, ніж список.

ServerProxy.system.methodHelp(name)

  Цей метод приймає один параметр, назву методу, реалізованого сервером XML-RPC. Він повертає рядок документації, що описує використання цього методу. Якщо такий рядок недоступний, повертається порожній рядок. Рядок документації може містити розмітку HTML.

Змінено в версії 3.5: Екземпляри `ServerProxy` підтримують протокол context manager для закриття основного транспорту.

Нижче наведено робочий приклад. Код сервера:

    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)

    Запишіть кодування XML-RPC цього елемента `DateTime` в об’єкт потоку out.

  It also supports certain of Python’s built-in operators through `rich comparison` and `__repr__()` methods.

Нижче наведено робочий приклад. Код сервера:

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

## Двійкові об’єкти

class xmlrpc.client.Binary

  Цей клас може бути ініціалізований з даних байтів (які можуть включати NUL). Основний доступ до вмісту об’єкта `Binary` забезпечується атрибутом:

  data

    Двійкові дані, інкапсульовані екземпляром `Binary`. Дані надаються як об’єкт `bytes`.

  `Binary` об’єкти мають такі методи, які підтримуються переважно для внутрішнього використання кодом маршалінгу/демаршалінгу:

  decode(bytes)

    Прийміть об’єкт base64 `bytes` і декодуйте його як нові дані екземпляра.

  encode(out)

    Запишіть кодування XML-RPC base 64 цього бінарного елемента в об’єкт потоку out.

    Закодовані дані матимуть символи нового рядка через кожні 76 символів відповідно до RFC 2045, розділ 6.8, який був де-факто стандартною специфікацією base64 на момент написання специфікації XML-RPC.

  It also supports certain of Python’s built-in operators through `__eq__()` and `__ne__()` methods.

Приклад використання бінарних об’єктів. Ми збираємося передати зображення через 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()

Клієнт отримує зображення та зберігає його у файл:

    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)

## Об’єкти несправності

class xmlrpc.client.Fault

  Об’єкт `Fault` інкапсулює вміст тегу помилки XML-RPC. Об’єкти несправностей мають такі атрибути:

  faultCode

    Int, що вказує на тип помилки.

  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)

## Об’єкти ProtocolError

class xmlrpc.client.ProtocolError

  Об’єкт `ProtocolError` описує помилку протоколу на базовому транспортному рівні (наприклад, помилку 404 «не знайдено», якщо сервер, названий URI, не існує). Він має такі атрибути:

  url

    URI або URL-адреса, яка викликала помилку.

  errcode

    Код помилки.

  errmsg

    Повідомлення про помилку або діагностичний рядок.

  headers

    Dict, що містить заголовки запиту HTTP/HTTPS, який викликав помилку.

У наступному прикладі ми навмисно спричинимо `ProtocolError`, вказавши недійсний URI:

    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)

## Об’єкти MultiCall

Об’єкт `MultiCall` забезпечує спосіб інкапсулювати кілька викликів до віддаленого сервера в один запит [1].

class xmlrpc.client.MultiCall(server)

  Створіть об’єкт, який використовується для викликів методу boxcar. сервер є кінцевою метою виклику. Виклики можна здійснювати до об’єкта результату, але вони негайно повертатимуть `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))

## Функції зручності

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

  Перетворіть params на запит XML-RPC. або у відповідь, якщо methodresponse має значення true. params може бути або кортежем аргументів, або екземпляром класу винятків `Fault`. Якщо methodresponse має значення true, можна повернути лише одне значення, тобто params має мати довжину 1. encoding, якщо вказано, це кодування, яке буде використовуватися у створеному XML; типовим є UTF-8. Значення Python `None` не можна використовувати в стандартному XML-RPC; щоб дозволити використовувати його через розширення, надайте справжнє значення allow_none.

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

  Перетворення запиту чи відповіді XML-RPC на об’єкти Python, `(params, methodname)`. params — це кортеж аргументів; methodname — це рядок або `None`, якщо в пакеті немає імені методу. Якщо пакет XML-RPC представляє стан помилки, ця функція викличе виняток `Fault`. Прапор use_builtin_types можна використовувати, щоб значення дати/часу відображалися як об’єкти `datetime.datetime`, а двійкові дані — як об’єкти `bytes`; цей прапор за замовчуванням false.

  Застарілий прапор use_datetime подібний до use_builtin_types, але він застосовується лише до значень дати/часу.

  Змінено в версії 3.3: Додано прапорець use_builtin_types.

## Приклад використання клієнта

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

## Приклад використання клієнта та сервера

Див. Приклад SimpleXMLRPCServer.

Виноски

[ 1 ]

Цей підхід вперше було представлено в обговоренні на xmlrpc.com.