aioxmlrpc-0.5/ 0000755 0001750 0000144 00000000000 13155203333 014515 5 ustar guillaume users 0000000 0000000 aioxmlrpc-0.5/setup.cfg 0000644 0001750 0000144 00000000046 13155203333 016336 0 ustar guillaume users 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
aioxmlrpc-0.5/PKG-INFO 0000644 0001750 0000144 00000006173 13155203333 015621 0 ustar guillaume users 0000000 0000000 Metadata-Version: 1.1
Name: aioxmlrpc
Version: 0.5
Summary: XML-RPC client for asyncio
Home-page: https://github.com/mardiros/aioxmlrpc
Author: Guillaume Gauvrit
Author-email: guillaume@gauvr.it
License: UNKNOWN
Description-Content-Type: UNKNOWN
Description: =========
aioxmlrpc
=========
.. image:: https://travis-ci.org/mardiros/aioxmlrpc.png?branch=master
:target: https://travis-ci.org/mardiros/aioxmlrpc
Getting Started
===============
Asyncio version of the standard lib ``xmlrpc``
Currently only ``aioxmlrpc.client``, which works like ``xmlrpc.client`` but
with coroutine is implemented.
Fill free to fork me if you want to implement the server part.
``aioxmlrpc`` is based on ``aiohttp`` for the transport, and just patch
the necessary from the python standard library to get it working.
Installation
------------
::
pip install aioxmlrpc
Example of usage
----------------
This example show how to print the current version of the Gandi XML-RPC api.
::
import asyncio
from aioxmlrpc.client import ServerProxy
@asyncio.coroutine
def print_gandi_api_version():
api = ServerProxy('https://rpc.gandi.net/xmlrpc/')
result = yield from api.version.info()
print(result)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(print_gandi_api_version())
loop.stop()
Changelog
=========
0.5 released on 2017-09-10
--------------------------
* Remove compatibility with aiohttp < 1.0 (Ovv)
0.4 released on 2017-03-30
--------------------------
* Fix NXDOMAIN Exception handling (Vladimir Rutsky)
* Fix cancel of futures handling (Gustavo Tavares Cabral)
0.3 released on 2016-06-16
--------------------------
* Fix socket closing issue
0.2 released on 2016-05-26
--------------------------
* Update compatibility for aiohttp >= 0.20
.. important::
This break the compatibility of python 3.3
0.1 released on 2014-05-17
--------------------------
* Initial version implementing ``aioxmlrpc.client``
Keywords: asyncio xml-rpc rpc
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
aioxmlrpc-0.5/setup.py 0000644 0001750 0000144 00000003113 13155202555 016232 0 ustar guillaume users 0000000 0000000 import os
import re
import sys
from setuptools import setup, find_packages
py_version = sys.version_info[:2]
if py_version < (3, 3):
raise RuntimeError('Unsupported Python version. Python 3.3+ required')
here = os.path.abspath(os.path.dirname(__file__))
NAME = 'aioxmlrpc'
with open(os.path.join(here, 'README.rst')) as readme:
README = readme.read()
with open(os.path.join(here, 'CHANGES.rst')) as changes:
CHANGES = changes.read()
with open(os.path.join(here, NAME, '__init__.py')) as version:
VERSION = re.compile(r".*__version__ = '(.*?)'",
re.S).match(version.read()).group(1)
requires = ['aiohttp >= 1.0.0']
if py_version < (3, 4):
requires.append('asyncio')
setup(name=NAME,
version=VERSION,
description='XML-RPC client for asyncio',
long_description=README + '\n\n' + CHANGES,
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License'
],
author='Guillaume Gauvrit',
author_email='guillaume@gauvr.it',
url='https://github.com/mardiros/aioxmlrpc',
keywords='asyncio xml-rpc rpc',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
test_suite='{}.tests'.format(NAME),
install_requires=requires
)
aioxmlrpc-0.5/CHANGES.rst 0000644 0001750 0000144 00000001215 13155203241 016314 0 ustar guillaume users 0000000 0000000 Changelog
=========
0.5 released on 2017-09-10
--------------------------
* Remove compatibility with aiohttp < 1.0 (Ovv)
0.4 released on 2017-03-30
--------------------------
* Fix NXDOMAIN Exception handling (Vladimir Rutsky)
* Fix cancel of futures handling (Gustavo Tavares Cabral)
0.3 released on 2016-06-16
--------------------------
* Fix socket closing issue
0.2 released on 2016-05-26
--------------------------
* Update compatibility for aiohttp >= 0.20
.. important::
This break the compatibility of python 3.3
0.1 released on 2014-05-17
--------------------------
* Initial version implementing ``aioxmlrpc.client``
aioxmlrpc-0.5/CONTRIBUTORS.rst 0000644 0001750 0000144 00000000146 13155202555 017212 0 ustar guillaume users 0000000 0000000 Contributors
============
A. Jesse Jiryu Davis
Gustavo Tavares Cabral
Vladimir Rutsky
nibrag
sayoun
aioxmlrpc-0.5/MANIFEST.in 0000644 0001750 0000144 00000000070 12721650525 016257 0 ustar guillaume users 0000000 0000000 include LICENSE
include *.rst
recursive-exclude . *.pyc
aioxmlrpc-0.5/aioxmlrpc.egg-info/ 0000755 0001750 0000144 00000000000 13155203333 020205 5 ustar guillaume users 0000000 0000000 aioxmlrpc-0.5/aioxmlrpc.egg-info/dependency_links.txt 0000644 0001750 0000144 00000000001 13155203333 024253 0 ustar guillaume users 0000000 0000000
aioxmlrpc-0.5/aioxmlrpc.egg-info/PKG-INFO 0000644 0001750 0000144 00000006173 13155203333 021311 0 ustar guillaume users 0000000 0000000 Metadata-Version: 1.1
Name: aioxmlrpc
Version: 0.5
Summary: XML-RPC client for asyncio
Home-page: https://github.com/mardiros/aioxmlrpc
Author: Guillaume Gauvrit
Author-email: guillaume@gauvr.it
License: UNKNOWN
Description-Content-Type: UNKNOWN
Description: =========
aioxmlrpc
=========
.. image:: https://travis-ci.org/mardiros/aioxmlrpc.png?branch=master
:target: https://travis-ci.org/mardiros/aioxmlrpc
Getting Started
===============
Asyncio version of the standard lib ``xmlrpc``
Currently only ``aioxmlrpc.client``, which works like ``xmlrpc.client`` but
with coroutine is implemented.
Fill free to fork me if you want to implement the server part.
``aioxmlrpc`` is based on ``aiohttp`` for the transport, and just patch
the necessary from the python standard library to get it working.
Installation
------------
::
pip install aioxmlrpc
Example of usage
----------------
This example show how to print the current version of the Gandi XML-RPC api.
::
import asyncio
from aioxmlrpc.client import ServerProxy
@asyncio.coroutine
def print_gandi_api_version():
api = ServerProxy('https://rpc.gandi.net/xmlrpc/')
result = yield from api.version.info()
print(result)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(print_gandi_api_version())
loop.stop()
Changelog
=========
0.5 released on 2017-09-10
--------------------------
* Remove compatibility with aiohttp < 1.0 (Ovv)
0.4 released on 2017-03-30
--------------------------
* Fix NXDOMAIN Exception handling (Vladimir Rutsky)
* Fix cancel of futures handling (Gustavo Tavares Cabral)
0.3 released on 2016-06-16
--------------------------
* Fix socket closing issue
0.2 released on 2016-05-26
--------------------------
* Update compatibility for aiohttp >= 0.20
.. important::
This break the compatibility of python 3.3
0.1 released on 2014-05-17
--------------------------
* Initial version implementing ``aioxmlrpc.client``
Keywords: asyncio xml-rpc rpc
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
aioxmlrpc-0.5/aioxmlrpc.egg-info/SOURCES.txt 0000644 0001750 0000144 00000000555 13155203333 022076 0 ustar guillaume users 0000000 0000000 CHANGES.rst
CONTRIBUTORS.rst
LICENSE
MANIFEST.in
README.rst
setup.py
aioxmlrpc/__init__.py
aioxmlrpc/client.py
aioxmlrpc.egg-info/PKG-INFO
aioxmlrpc.egg-info/SOURCES.txt
aioxmlrpc.egg-info/dependency_links.txt
aioxmlrpc.egg-info/not-zip-safe
aioxmlrpc.egg-info/requires.txt
aioxmlrpc.egg-info/top_level.txt
aioxmlrpc/tests/__init__.py
aioxmlrpc/tests/test_client.py aioxmlrpc-0.5/aioxmlrpc.egg-info/not-zip-safe 0000644 0001750 0000144 00000000001 12721652364 022445 0 ustar guillaume users 0000000 0000000
aioxmlrpc-0.5/aioxmlrpc.egg-info/requires.txt 0000644 0001750 0000144 00000000017 13155203333 022603 0 ustar guillaume users 0000000 0000000 aiohttp>=1.0.0
aioxmlrpc-0.5/aioxmlrpc.egg-info/top_level.txt 0000644 0001750 0000144 00000000012 13155203333 022730 0 ustar guillaume users 0000000 0000000 aioxmlrpc
aioxmlrpc-0.5/README.rst 0000644 0001750 0000144 00000002153 12721650525 016214 0 ustar guillaume users 0000000 0000000 =========
aioxmlrpc
=========
.. image:: https://travis-ci.org/mardiros/aioxmlrpc.png?branch=master
:target: https://travis-ci.org/mardiros/aioxmlrpc
Getting Started
===============
Asyncio version of the standard lib ``xmlrpc``
Currently only ``aioxmlrpc.client``, which works like ``xmlrpc.client`` but
with coroutine is implemented.
Fill free to fork me if you want to implement the server part.
``aioxmlrpc`` is based on ``aiohttp`` for the transport, and just patch
the necessary from the python standard library to get it working.
Installation
------------
::
pip install aioxmlrpc
Example of usage
----------------
This example show how to print the current version of the Gandi XML-RPC api.
::
import asyncio
from aioxmlrpc.client import ServerProxy
@asyncio.coroutine
def print_gandi_api_version():
api = ServerProxy('https://rpc.gandi.net/xmlrpc/')
result = yield from api.version.info()
print(result)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(print_gandi_api_version())
loop.stop()
aioxmlrpc-0.5/aioxmlrpc/ 0000755 0001750 0000144 00000000000 13155203333 016513 5 ustar guillaume users 0000000 0000000 aioxmlrpc-0.5/aioxmlrpc/client.py 0000644 0001750 0000144 00000012052 13155202555 020350 0 ustar guillaume users 0000000 0000000 """
XML-RPC Client with asyncio.
This module adapt the ``xmlrpc.client`` module of the standard library to
work with asyncio.
"""
import sys
import asyncio
import logging
import aiohttp
from xmlrpc import client as xmlrpc
__ALL__ = ['ServerProxy', 'Fault', 'ProtocolError']
# you don't have to import xmlrpc.client from your code
Fault = xmlrpc.Fault
ProtocolError = xmlrpc.ProtocolError
log = logging.getLogger(__name__)
PY35 = sys.version_info >= (3, 5)
class _Method:
# some magic to bind an XML-RPC method to an RPC server.
# supports "nested" methods (e.g. examples.getStateName)
def __init__(self, send, name):
self.__send = send
self.__name = name
def __getattr__(self, name):
return _Method(self.__send, "%s.%s" % (self.__name, name))
@asyncio.coroutine
def __call__(self, *args):
ret = yield from self.__send(self.__name, args)
return ret
class AioTransport(xmlrpc.Transport):
"""
``xmlrpc.Transport`` subclass for asyncio support
"""
def __init__(self, session, use_https, *, use_datetime=False,
use_builtin_types=False, loop, headers=None, auth=None):
super().__init__(use_datetime, use_builtin_types)
self.use_https = use_https
self._loop = loop
self._session = session
self.auth = auth
if not headers:
headers = {'User-Agent': 'python/aioxmlrpc',
'Accept': 'text/xml',
'Content-Type': 'text/xml'}
self.headers = headers
@asyncio.coroutine
def request(self, host, handler, request_body, verbose=False):
"""
Send the XML-RPC request, return the response.
This method is a coroutine.
"""
url = self._build_url(host, handler)
response = None
try:
response = yield from self._session.request(
'POST', url, headers=self.headers, data=request_body, auth=self.auth)
body = yield from response.text()
if response.status != 200:
raise ProtocolError(url, response.status,
body, response.headers)
except asyncio.CancelledError:
raise
except ProtocolError:
raise
except Exception as exc:
log.error('Unexpected error', exc_info=True)
if response is not None:
errcode = response.status
headers = response.headers
else:
errcode = 0
headers = {}
raise ProtocolError(url, errcode, str(exc), headers)
return self.parse_response(body)
def parse_response(self, body):
"""
Parse the xmlrpc response.
"""
p, u = self.getparser()
p.feed(body)
p.close()
return u.close()
def _build_url(self, host, handler):
"""
Build a url for our request based on the host, handler and use_http
property
"""
scheme = 'https' if self.use_https else 'http'
return '%s://%s%s' % (scheme, host, handler)
class ServerProxy(xmlrpc.ServerProxy):
"""
``xmlrpc.ServerProxy`` subclass for asyncio support
"""
def __init__(self, uri, session=None, encoding=None, verbose=False,
allow_none=False, use_datetime=False, use_builtin_types=False,
loop=None, auth=None, headers=None):
self._loop = loop or asyncio.get_event_loop()
if session:
self._session = session
self._close_session = False
else:
self._close_session = True
self._session = aiohttp.ClientSession(loop=self._loop)
transport = AioTransport(use_https=uri.startswith('https://'),
loop=self._loop,
session=self._session,
auth=auth,
headers=headers)
super().__init__(uri, transport, encoding, verbose, allow_none,
use_datetime, use_builtin_types)
@asyncio.coroutine
def __request(self, methodname, params):
# call a method on the remote server
request = xmlrpc.dumps(params, methodname, encoding=self.__encoding,
allow_none=self.__allow_none).encode(self.__encoding)
response = yield from self.__transport.request(
self.__host,
self.__handler,
request,
verbose=self.__verbose
)
if len(response) == 1:
response = response[0]
return response
@asyncio.coroutine
def close(self):
if self._close_session:
yield from self._session.close()
def __getattr__(self, name):
return _Method(self.__request, name)
if PY35:
@asyncio.coroutine
def __aenter__(self):
return self
@asyncio.coroutine
def __aexit__(self, exc_type, exc_val, exc_tb):
if self._close_session:
yield from self._session.close()
aioxmlrpc-0.5/aioxmlrpc/tests/ 0000755 0001750 0000144 00000000000 13155203333 017655 5 ustar guillaume users 0000000 0000000 aioxmlrpc-0.5/aioxmlrpc/tests/test_client.py 0000644 0001750 0000144 00000012334 13155202555 022554 0 ustar guillaume users 0000000 0000000 import sys
import asyncio
import aiohttp
from unittest import TestCase
from unittest import mock
from aioxmlrpc.client import ServerProxy, ProtocolError, Fault
RESPONSES = {
'http://localhost/test_xmlrpc_ok': {'status': 200,
'body': """
1
"""
},
'http://localhost/test_xmlrpc_fault': {'status': 200,
'body': """
faultCode
4
faultString
You are not lucky
"""
},
'http://localhost/test_http_500': {'status': 500,
'body': """
I am really broken
"""
}
}
PY35 = sys.version_info >= (3, 5)
@asyncio.coroutine
def dummy_response(method, url, **kwargs):
class Response:
def __init__(self):
response = RESPONSES[url]
self.status = response['status']
self.body = response['body']
self.headers = {}
@asyncio.coroutine
def text(self):
return self.body
return Response()
@asyncio.coroutine
def dummy_request(*args, **kwargs):
if isinstance(args[0], aiohttp.ClientSession):
return dummy_response(*args[1:], **kwargs)
else:
return dummy_response(*args, **kwargs)
class ServerProxyWithSessionTestCase(TestCase):
def setUp(self):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self.session = aiohttp.ClientSession(loop=self.loop)
self.session.request = dummy_request
def tearDown(self):
self.loop.run_until_complete(self.session.close())
def test_xmlrpc_ok(self):
client = ServerProxy('http://localhost/test_xmlrpc_ok',
loop=self.loop,
session=self.session)
response = self.loop.run_until_complete(
client.name.space.proxfyiedcall()
)
self.assertEqual(response, 1)
self.assertIs(self.loop, client._loop)
def test_xmlrpc_fault(self):
client = ServerProxy('http://localhost/test_xmlrpc_fault',
loop=self.loop,
session=self.session)
with self.assertRaises(Fault):
self.loop.run_until_complete(client.name.space.proxfyiedcall())
def test_http_500(self):
client = ServerProxy('http://localhost/test_http_500',
loop=self.loop,
session=self.session)
with self.assertRaises(ProtocolError):
self.loop.run_until_complete(client.name.space.proxfyiedcall())
def test_xmlrpc_ok_global_loop(self):
client = ServerProxy('http://localhost/test_xmlrpc_ok',
session=self.session)
response = self.loop.run_until_complete(
client.name.space.proxfyiedcall()
)
self.assertIs(self.loop, client._loop)
self.assertEqual(response, 1)
class ServerProxyWithoutSessionTestCase(TestCase):
def setUp(self):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
session_request = mock.patch('aiohttp.ClientSession.request', new=dummy_request)
session_request.start()
self.addCleanup(session_request.stop)
def test_close_session(self):
client = ServerProxy('http://localhost/test_xmlrpc_ok',
loop=self.loop)
response = self.loop.run_until_complete(
client.name.space.proxfyiedcall()
)
self.assertEqual(response, 1)
self.assertIs(self.loop, client._loop)
self.loop.run_until_complete(client.close())
# def test_contextmanager(self):
# self.loop.run_until_complete(self.xmlrpc_with_context_manager())
#
# async def xmlrpc_with_context_manager(self):
# async with ServerProxy('http://localhost/test_xmlrpc_ok',
# loop=self.loop) as client:
# response = await client.name.space.proxfyiedcall()
# self.assertEqual(response, 1)
# self.assertIs(self.loop, client._loop)
@asyncio.coroutine
def failing_request(*args, **kwargs):
raise OSError
class HTTPErrorTestCase(TestCase):
def setUp(self):
self.loop = asyncio.new_event_loop()
self.session = aiohttp.ClientSession(loop=self.loop)
self.session.request = failing_request
def tearDown(self):
self.loop.run_until_complete(self.session.close())
def test_http_error(self):
client = ServerProxy('http://nonexistent/nonexistent', loop=self.loop,
session=self.session)
with self.assertRaises(ProtocolError):
self.loop.run_until_complete(client.name.space.proxfyiedcall())
aioxmlrpc-0.5/aioxmlrpc/tests/__init__.py 0000644 0001750 0000144 00000000053 12721650525 021773 0 ustar guillaume users 0000000 0000000 """
Test suite for the aioxmlrpc module
""" aioxmlrpc-0.5/aioxmlrpc/__init__.py 0000644 0001750 0000144 00000000076 13155202555 020634 0 ustar guillaume users 0000000 0000000 """
XML-RPC Protocol for ``asyncio``
"""
__version__ = '0.5'
aioxmlrpc-0.5/LICENSE 0000644 0001750 0000144 00000002765 13155202555 015541 0 ustar guillaume users 0000000 0000000 Copyright (c) 2014-2017, Guillaume Gauvrit and Contibutors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.