"xmlrpc.client" --- Cliente XML-RPC
***********************************

**Código-fonte:** Lib/xmlrpc/client.py

======================================================================

XML-RPC é um método de chamada remota de métodos que usa XML usando
HTTP(S) como transporte.  Com ele, um cliente pode chamar métodos com
parâmetros em um servidor remoto (o servidor é nomeado por um URI) e
receber de volta dados estruturados.  Este módulo oferece suporte à
escrita de código de clientes XML-RPC; ele lida com todos os detalhes
da tradução entre Python objetos e XML.

Aviso:

  The "xmlrpc.client" module is not secure against maliciously
  constructed data.  If you need to parse untrusted or unauthenticated
  data, see Segurança no XML.

Alterado na versão 3.5: For HTTPS URIs, "xmlrpc.client" now performs
all the necessary certificate and hostname checks by default.

Disponibilidade: not WASI.

Este módulo não funciona ou não está disponível em WebAssembly. Veja
Plataformas WebAssembly para mais informações.

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

   Uma instância de "ServerProxy" é um objeto que gerencia a
   comunicação com um servidor XML-RPC remoto. O primeiro argumento
   obrigatório é uma URI (Uniform Resource Indicator - Indicador de
   Recurso Uniforme) e normalmente vai ser a URL do servidor. O
   segundo parâmetro, opcional, é uma instância de um factory de
   transporte; por padrão é uma instância de "SafeTransport" para URLs
   https e uma instância de "Transport" caso contrário. O terceiro
   parâmetro, opcional, é o encoding, por padrão sendo UTF-8. O quarto
   argumento, opcional, é a flag de debug.

   Os seguinte parâmetros coordenam o uso da instância de proxy
   retornada. Se *alow_none* for verdadeiro, a constante "None" do
   Python será traduzida para XML; o comportamento padrão é que "None"
   levante uma "TypeError", Isso é uma extensão comum da especificação
   do XML-RPC, mas não é suportado por todos os clientes e servidores,
   veja  http://ontosys.com/xml-rpc/extensions.php para uma descrição.
   A flag *use_builtin_types* pode ser usada para  que valores de data
   e hora sejam representados como objetos "datetime.datetime" e dados
   binários representados com objetos "bytes"; essa flag é False por
   padrão. Objetos "datetime.datetime", "bytes" e "bytearray" podem
   ser usados nas chamadas. O parâmetro *headers* é uma sequência
   opcional de headers a serem enviados em cada requisição,
   representados por uma sequência de tuplas de dois valores
   representando o nome do header e seu valor (como "[('Header-Name',
   'value')]"). Se uma URL HTTPS é fornecida, *context* pode ser
   "ssl.SSLContext" e configura as definições SSL da conexão HTTPS
   subjacente. A flag *use_datetime* é obsoleta e é similar a
   *use_builtin_types* mas se aplica somente a valores de data e hora.

   Alterado na versão 3.3: O sinalizador *use_builtin_types* foi
   adicionado.

   Alterado na versão 3.8: O parâmetro *headers* foi adicionado.

   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.

   A instância retornada é um objeto proxy com métodos que podem ser
   usados para invocar a chamada RPC correspondendo no servidor
   remoto. Se o servidor remoto suportar a API de instrospecção, o
   proxy também pode ser usado para perguntar ao servidor remoto pelos
   métodos que ele suporta (descoberta de serviço) e recuperar outros
   meta-dados associados com o servidor.

   Os tipos que são conformáveis (por exemplo, que podem ser
   convertidos para XML) incluem os seguintes (e exceto onde indicado,
   eles não são convertidos como o mesmo tipo Python):

   +------------------------+---------------------------------------------------------+
   | Tipo XML-RPC           | Tipo em Python                                          |
   |========================|=========================================================|
   | "boolean"              | "bool"                                                  |
   +------------------------+---------------------------------------------------------+
   | "int", "i1", "i2",     | "int" no intervalo de -2147483648 a 2147483647. Os      |
   | "i4", "i8" ou          | valores recebem a tag "<int>".                          |
   | "biginteger"           |                                                         |
   +------------------------+---------------------------------------------------------+
   | "double" ou "float"    | "float".  Os valores recebem a tag "<double>".          |
   +------------------------+---------------------------------------------------------+
   | "string"               | "str"                                                   |
   +------------------------+---------------------------------------------------------+
   | "array"                | "list" ou "tuple" contendo elementos conformáveis.  As  |
   |                        | matrizes são retornadas como "lists".                   |
   +------------------------+---------------------------------------------------------+
   | "struct"               | "dict". Chaves devem ser strings, valores podem ser     |
   |                        | qualquer tipo conformáveis. Objetos de classes          |
   |                        | definidas pelo usuário pode ser usadas; apenas o        |
   |                        | atributo "__dict__" delas é transmitido.                |
   +------------------------+---------------------------------------------------------+
   | "dateTime.iso8601"     | "DateTime" ou "datetime.datetime". O tipo retornado     |
   |                        | depende de volumes de sinalizadores *use_builtin_types* |
   |                        | e *use_datetime*.                                       |
   +------------------------+---------------------------------------------------------+
   | "base64"               | "Binary", "bytes" ou "bytearray".  O tipo retornado     |
   |                        | depende do valor da flag *use_builtin_types*.           |
   +------------------------+---------------------------------------------------------+
   | "nil"                  | A constante "None".  A passagem é permitida somente se  |
   |                        | *allow_none* for verdadeiro.                            |
   +------------------------+---------------------------------------------------------+
   | "bigdecimal"           | "decimal.Decimal".  Somente tipo retornado.             |
   +------------------------+---------------------------------------------------------+

   Esta é a lista completa de tipos suportados por XML-RPC. Chamadas
   de método podem também levantar uma instância de "Fault", usado
   para que o servidor XML-RPC indique erros, ou "ProtocolError" para
   indicar erros na camada HTTP/HTTPS. Tnato "Fault" quanto
   "ProtocolError" derivam da classe base "Error". Observe que o
   módulo de cliente xmlrpc atualmente não converte instância de
   subclasses dos tipos built-in.

   Ao passar strings, os caracteres especiais para XML, como "<", ">"
   e "&", serão automaticamente escapados.  No entanto, é
   responsabilidade do chamador garantir que o string esteja livre de
   caracteres que não são permitidos em XML, como os caracteres de
   controle com valores ASCII entre 0 e 31 (exceto, é claro,
   tabulação, nova linha e retorno de carro); se isso não for feito,
   resultará em uma solicitação XML-RPC que não é um XML bem formado.
   Se você precisar passar bytes arbitrários via XML-RPC, use as
   classes "bytes" ou "bytearray" ou a classe wrapper "Binary"
   descrito abaixo.

   "Server" foi mantido como um apelido para "ServerProxy" para
   compatibilidade retroativa.  Código novo deve usar "ServerProxy".

   Alterado na versão 3.5: Argumento *context* adicionado.

   Alterado na versão 3.6: Adicionado suporte para tags com prefixos
   (por exemplo "ex:nil") Adicionado suporte para desconversão de
   tipos adicionados usados pela implementação do Apache XML-RPC para
   numéricos: "i1", "i2", "i8", "biginteger", "float" e "bigdecimal".
   Veja   https://ws.apache.org/xmlrpc/types.html para uma descrição.

Ver também:

  XML-RPC HOWTO
     Uma boa descrição das operações XML-RPC e software cliente em
     vários idiomas. Contém praticamente tudo o que um desenvolvedor
     de clientes XML-RPC precisa saber.

  XML-RPC Introspection
     Describe a extensão do protocolo XML-RPC para instrospecção.

  XML-RPC Specification
     A especificação oficial.


Objetos ServerProxy
===================

A "ServerProxy" instance has a method corresponding to each remote
procedure call accepted by the XML-RPC server.  Calling the method
performs an RPC, dispatched by both name and argument signature (e.g.
the same method name can be overloaded with multiple argument
signatures).  The RPC finishes either by returning data in a
conformant type or by raising a "Fault" or "ProtocolError" exception
indicating an error.

Servers that support the XML introspection API support some common
methods grouped under the reserved "system" attribute:

ServerProxy.system.listMethods()

   This method returns a list of strings, one for each (non-system)
   method supported by the XML-RPC server.

ServerProxy.system.methodSignature(name)

   This method takes one parameter, the name of a method implemented
   by the XML-RPC server. It returns an array of possible signatures
   for this method. A signature is an array of types. The first of
   these types is the return type of the method, the rest are
   parameters.

   Because multiple signatures (ie. overloading) is permitted, this
   method returns a list of signatures rather than a singleton.

   Signatures themselves are restricted to the top level parameters
   expected by a method. For instance if a method expects one array of
   structs as a parameter, and it returns a string, its signature is
   simply "string, array". If it expects three integers and returns a
   string, its signature is "string, int, int, int".

   If no signature is defined for the method, a non-array value is
   returned. In Python this means that the type of the returned  value
   will be something other than list.

ServerProxy.system.methodHelp(name)

   This method takes one parameter, the name of a method implemented
   by the XML-RPC server.  It returns a documentation string
   describing the use of that method. If no such string is available,
   an empty string is returned. The documentation string may contain
   HTML markup.

Alterado na versão 3.5: Instances of "ServerProxy" support the
*context manager* protocol for closing the underlying transport.

A working example follows. The server code:

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

The client code for the preceding server:

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


Objetos DateTime
================

class xmlrpc.client.DateTime

   This class may be initialized with seconds since the epoch, a time
   tuple, an ISO 8601 time/date string, or a "datetime.datetime"
   instance.  It has the following methods, supported mainly for
   internal use by the marshalling/unmarshalling code:

   decode(string)

      Accept a string as the instance's new time value.

   encode(out)

      Write the XML-RPC encoding of this "DateTime" item to the *out*
      stream object.

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

A working example follows. The server code:

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

The client code for the preceding server:

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


Objetos Binários
================

class xmlrpc.client.Binary

   This class may be initialized from bytes data (which may include
   NULs). The primary access to the content of a "Binary" object is
   provided by an attribute:

   data

      The binary data encapsulated by the "Binary" instance.  The data
      is provided as a "bytes" object.

   "Binary" objects have the following methods, supported mainly for
   internal use by the marshalling/unmarshalling code:

   decode(bytes)

      Accept a base64 "bytes" object and decode it as the instance's
      new data.

   encode(out)

      Write the XML-RPC base 64 encoding of this binary item to the
      *out* stream object.

      The encoded data will have newlines every 76 characters as per
      **RFC 2045 section 6.8**, which was the de facto standard base64
      specification when the XML-RPC spec was written.

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

Example usage of the binary objects.  We're going to transfer an image
over 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()

The client gets the image and saves it to a file:

   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)


Objetos Fault
=============

class xmlrpc.client.Fault

   A "Fault" object encapsulates the content of an XML-RPC fault tag.
   Fault objects have the following attributes:

   faultCode

      An int indicating the fault type.

   faultString

      A string containing a diagnostic message associated with the
      fault.

In the following example we're going to intentionally cause a "Fault"
by returning a complex type object.  The server code:

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

The client code for the preceding server:

   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)


Objetos ProtocolError
=====================

class xmlrpc.client.ProtocolError

   A "ProtocolError" object describes a protocol error in the
   underlying transport layer (such as a 404 'not found' error if the
   server named by the URI does not exist).  It has the following
   attributes:

   url

      The URI or URL that triggered the error.

   errcode

      O código do erro.

   errmsg

      The error message or diagnostic string.

   headers

      A dict containing the headers of the HTTP/HTTPS request that
      triggered the error.

In the following example we're going to intentionally cause a
"ProtocolError" by providing an invalid 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)


Objetos MultiCall
=================

The "MultiCall" object provides a way to encapsulate multiple calls to
a remote server into a single request [1].

class xmlrpc.client.MultiCall(server)

   Create an object used to boxcar method calls. *server* is the
   eventual target of the call. Calls can be made to the result
   object, but they will immediately return "None", and only store the
   call name and arguments in the "MultiCall" object. Calling the
   object itself causes all stored calls to be transmitted as a single
   "system.multicall" request. The result of this call is a
   *generator*; iterating over this generator yields the individual
   results.

A usage example of this class follows.  The server code:

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

The client code for the preceding server:

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


Convenience Functions
=====================

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)

   Convert an XML-RPC request or response into Python objects, a
   "(params, methodname)".  *params* is a tuple of argument;
   *methodname* is a string, or "None" if no method name is present in
   the packet. If the XML-RPC packet represents a fault condition,
   this function will raise a "Fault" exception. 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.

   The obsolete *use_datetime* flag is similar to *use_builtin_types*
   but it applies only to date/time values.

   Alterado na versão 3.3: O sinalizador *use_builtin_types* foi
   adicionado.


Exemplo de uso do cliente
=========================

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

To access an XML-RPC server through a HTTP proxy, you need to define a
custom transport.  The following example shows how:

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


Example of Client and Server Usage
==================================

Veja SimpleXMLRPCServer example.

-[ Notas de rodapé ]-

[1] This approach has been first presented in a discussion on
    xmlrpc.com.
