aioxmlrpc-0.5/0000755000175000001440000000000013155203333014515 5ustar guillaumeusers00000000000000aioxmlrpc-0.5/setup.cfg0000644000175000001440000000004613155203333016336 0ustar guillaumeusers00000000000000[egg_info] tag_build = tag_date = 0 aioxmlrpc-0.5/PKG-INFO0000644000175000001440000000617313155203333015621 0ustar guillaumeusers00000000000000Metadata-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.py0000644000175000001440000000311313155202555016232 0ustar guillaumeusers00000000000000import 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.rst0000644000175000001440000000121513155203241016314 0ustar guillaumeusers00000000000000Changelog ========= 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.rst0000644000175000001440000000014613155202555017212 0ustar guillaumeusers00000000000000Contributors ============ A. Jesse Jiryu Davis Gustavo Tavares Cabral Vladimir Rutsky nibrag sayoun aioxmlrpc-0.5/MANIFEST.in0000644000175000001440000000007012721650525016257 0ustar guillaumeusers00000000000000include LICENSE include *.rst recursive-exclude . *.pyc aioxmlrpc-0.5/aioxmlrpc.egg-info/0000755000175000001440000000000013155203333020205 5ustar guillaumeusers00000000000000aioxmlrpc-0.5/aioxmlrpc.egg-info/dependency_links.txt0000644000175000001440000000000113155203333024253 0ustar guillaumeusers00000000000000 aioxmlrpc-0.5/aioxmlrpc.egg-info/PKG-INFO0000644000175000001440000000617313155203333021311 0ustar guillaumeusers00000000000000Metadata-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.txt0000644000175000001440000000055513155203333022076 0ustar guillaumeusers00000000000000CHANGES.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.pyaioxmlrpc-0.5/aioxmlrpc.egg-info/not-zip-safe0000644000175000001440000000000112721652364022445 0ustar guillaumeusers00000000000000 aioxmlrpc-0.5/aioxmlrpc.egg-info/requires.txt0000644000175000001440000000001713155203333022603 0ustar guillaumeusers00000000000000aiohttp>=1.0.0 aioxmlrpc-0.5/aioxmlrpc.egg-info/top_level.txt0000644000175000001440000000001213155203333022730 0ustar guillaumeusers00000000000000aioxmlrpc aioxmlrpc-0.5/README.rst0000644000175000001440000000215312721650525016214 0ustar guillaumeusers00000000000000========= 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/0000755000175000001440000000000013155203333016513 5ustar guillaumeusers00000000000000aioxmlrpc-0.5/aioxmlrpc/client.py0000644000175000001440000001205213155202555020350 0ustar guillaumeusers00000000000000""" 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/0000755000175000001440000000000013155203333017655 5ustar guillaumeusers00000000000000aioxmlrpc-0.5/aioxmlrpc/tests/test_client.py0000644000175000001440000001233413155202555022554 0ustar guillaumeusers00000000000000import 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__.py0000644000175000001440000000005312721650525021773 0ustar guillaumeusers00000000000000""" Test suite for the aioxmlrpc module """aioxmlrpc-0.5/aioxmlrpc/__init__.py0000644000175000001440000000007613155202555020634 0ustar guillaumeusers00000000000000""" XML-RPC Protocol for ``asyncio`` """ __version__ = '0.5' aioxmlrpc-0.5/LICENSE0000644000175000001440000000276513155202555015541 0ustar guillaumeusers00000000000000Copyright (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.