[Python-modules-commits] [api-hour] 01/04: Import api-hour_0.8.2.orig.tar.gz
Piotr Ożarowski
piotr at moszumanska.debian.org
Mon Nov 13 20:21:52 UTC 2017
This is an automated email from the git hooks/post-receive script.
piotr pushed a commit to branch master
in repository api-hour.
commit e391298a2bcb50541a568f646e07ae0bd956c287
Author: Piotr Ożarowski <piotr at debian.org>
Date: Mon Nov 13 21:03:08 2017 +0100
Import api-hour_0.8.2.orig.tar.gz
---
HISTORY.rst | 6 ++
PKG-INFO | 20 +++--
README.rst | 12 +--
api_hour.egg-info/PKG-INFO | 20 +++--
api_hour.egg-info/SOURCES.txt | 3 +
api_hour/__init__.py | 2 +-
api_hour/container.py | 14 +++-
api_hour/plugins/aiohttp/__init__.py | 32 +------
api_hour/plugins/aiohttp/environment.py | 98 ++++++++++++++++++++++
.../plugins/aiohttp/{__init__.py => response.py} | 15 ++--
api_hour/plugins/aiohttp/router.py | 16 ++++
api_hour/worker.py | 40 +++++----
setup.cfg | 2 +-
setup.py | 6 +-
14 files changed, 206 insertions(+), 80 deletions(-)
diff --git a/HISTORY.rst b/HISTORY.rst
index c2d2d7c..ec69a46 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,6 +1,12 @@
CHANGES
=======
+0.8.2 (2017-11-10)
+------------------
+
+* Add pre_start coroutine
+* Fix setup.py to check correctly minimal Python version. Thanks @romuald
+
0.8.1 (2016-07-08)
------------------
diff --git a/PKG-INFO b/PKG-INFO
index ea00f73..263bae5 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: api_hour
-Version: 0.8.1
+Version: 0.8.2
Summary: Write efficient network daemons (HTTP, SSH...) with ease.
Home-page: http://www.api-hour.io
Author: Eyepea Dev Team
@@ -45,37 +45,37 @@ Description: API Hour
For each layer, we use the best in term of performance and simplicity:
#. `AsyncIO <https://docs.python.org/3/library/asyncio.html>`_: an easy asynchronous framework, directly integrated in Python 3.4+
- #. `aiohttp.web <http://aiohttp.readthedocs.org/en/latest/web.html>`_: HTTP protocol implementation for AsyncIO + Web framework
+ #. `aiohttp.web <https://aiohttp.readthedocs.org/en/latest/web.html>`_: HTTP protocol implementation for AsyncIO + Web framework
#. `ujson <https://github.com/esnme/ultrajson#ultrajson>`_: fastest JSON serialization
Examples
--------
#. `API-Hour Starter Kit (Cookiecutter) <https://github.com/Eyepea/cookiecutter-API-Hour>`_
- #. `API-Hour implementation of TechEmpower Web Framework Benchmarks <https://github.com/Eyepea/FrameworkBenchmarks/tree/API-Hour/frameworks/Python/API-Hour>`_
+ #. `API-Hour implementation of TechEmpower Web Framework Benchmarks <https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Python/asyncio>`_
#. `HTTP+SSH Daemon <https://github.com/Eyepea/API-Hour/tree/master/examples/http_and_ssh>`_
#. `Quick'n'dirty benchmarks on a kitchen table <https://github.com/Eyepea/API-Hour/tree/master/benchmarks/api_hour/benchmarks>`_
How-to start an API-Hour project ?
----------------------------------
- You can follow `one of our tutorials <http://pythonhosted.org/api_hour/tutorials/index.html>`_
+ You can follow `one of our tutorials <https://pythonhosted.org/api_hour/tutorials/index.html>`_
Support
-------
- * `Documentation <http://pythonhosted.org/api_hour/>`_.
+ * `Documentation <https://pythonhosted.org/api_hour/>`_.
* `Mailing-list <https://groups.google.com/d/forum/api-hour>`_
Requirements
------------
- - Python 3.3+
+ - Python 3.5+
Install
-------
- Follow `official documentation <http://pythonhosted.org/api_hour/installation.html>`_.
+ Follow `official documentation <https://pythonhosted.org/api_hour/installation.html>`_.
License
-------
@@ -114,6 +114,12 @@ Description: API Hour
CHANGES
=======
+ 0.8.2 (2017-11-10)
+ ------------------
+
+ * Add pre_start coroutine
+ * Fix setup.py to check correctly minimal Python version. Thanks @romuald
+
0.8.1 (2016-07-08)
------------------
diff --git a/README.rst b/README.rst
index 0f5cbe1..3dc11c4 100644
--- a/README.rst
+++ b/README.rst
@@ -36,37 +36,37 @@ Moreover, we've tried to reduce as much as possible layers between your code and
For each layer, we use the best in term of performance and simplicity:
#. `AsyncIO <https://docs.python.org/3/library/asyncio.html>`_: an easy asynchronous framework, directly integrated in Python 3.4+
-#. `aiohttp.web <http://aiohttp.readthedocs.org/en/latest/web.html>`_: HTTP protocol implementation for AsyncIO + Web framework
+#. `aiohttp.web <https://aiohttp.readthedocs.org/en/latest/web.html>`_: HTTP protocol implementation for AsyncIO + Web framework
#. `ujson <https://github.com/esnme/ultrajson#ultrajson>`_: fastest JSON serialization
Examples
--------
#. `API-Hour Starter Kit (Cookiecutter) <https://github.com/Eyepea/cookiecutter-API-Hour>`_
-#. `API-Hour implementation of TechEmpower Web Framework Benchmarks <https://github.com/Eyepea/FrameworkBenchmarks/tree/API-Hour/frameworks/Python/API-Hour>`_
+#. `API-Hour implementation of TechEmpower Web Framework Benchmarks <https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Python/asyncio>`_
#. `HTTP+SSH Daemon <https://github.com/Eyepea/API-Hour/tree/master/examples/http_and_ssh>`_
#. `Quick'n'dirty benchmarks on a kitchen table <https://github.com/Eyepea/API-Hour/tree/master/benchmarks/api_hour/benchmarks>`_
How-to start an API-Hour project ?
----------------------------------
-You can follow `one of our tutorials <http://pythonhosted.org/api_hour/tutorials/index.html>`_
+You can follow `one of our tutorials <https://pythonhosted.org/api_hour/tutorials/index.html>`_
Support
-------
-* `Documentation <http://pythonhosted.org/api_hour/>`_.
+* `Documentation <https://pythonhosted.org/api_hour/>`_.
* `Mailing-list <https://groups.google.com/d/forum/api-hour>`_
Requirements
------------
-- Python 3.3+
+- Python 3.5+
Install
-------
-Follow `official documentation <http://pythonhosted.org/api_hour/installation.html>`_.
+Follow `official documentation <https://pythonhosted.org/api_hour/installation.html>`_.
License
-------
diff --git a/api_hour.egg-info/PKG-INFO b/api_hour.egg-info/PKG-INFO
index 527f1c4..d73ea12 100644
--- a/api_hour.egg-info/PKG-INFO
+++ b/api_hour.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: api-hour
-Version: 0.8.1
+Version: 0.8.2
Summary: Write efficient network daemons (HTTP, SSH...) with ease.
Home-page: http://www.api-hour.io
Author: Eyepea Dev Team
@@ -45,37 +45,37 @@ Description: API Hour
For each layer, we use the best in term of performance and simplicity:
#. `AsyncIO <https://docs.python.org/3/library/asyncio.html>`_: an easy asynchronous framework, directly integrated in Python 3.4+
- #. `aiohttp.web <http://aiohttp.readthedocs.org/en/latest/web.html>`_: HTTP protocol implementation for AsyncIO + Web framework
+ #. `aiohttp.web <https://aiohttp.readthedocs.org/en/latest/web.html>`_: HTTP protocol implementation for AsyncIO + Web framework
#. `ujson <https://github.com/esnme/ultrajson#ultrajson>`_: fastest JSON serialization
Examples
--------
#. `API-Hour Starter Kit (Cookiecutter) <https://github.com/Eyepea/cookiecutter-API-Hour>`_
- #. `API-Hour implementation of TechEmpower Web Framework Benchmarks <https://github.com/Eyepea/FrameworkBenchmarks/tree/API-Hour/frameworks/Python/API-Hour>`_
+ #. `API-Hour implementation of TechEmpower Web Framework Benchmarks <https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Python/asyncio>`_
#. `HTTP+SSH Daemon <https://github.com/Eyepea/API-Hour/tree/master/examples/http_and_ssh>`_
#. `Quick'n'dirty benchmarks on a kitchen table <https://github.com/Eyepea/API-Hour/tree/master/benchmarks/api_hour/benchmarks>`_
How-to start an API-Hour project ?
----------------------------------
- You can follow `one of our tutorials <http://pythonhosted.org/api_hour/tutorials/index.html>`_
+ You can follow `one of our tutorials <https://pythonhosted.org/api_hour/tutorials/index.html>`_
Support
-------
- * `Documentation <http://pythonhosted.org/api_hour/>`_.
+ * `Documentation <https://pythonhosted.org/api_hour/>`_.
* `Mailing-list <https://groups.google.com/d/forum/api-hour>`_
Requirements
------------
- - Python 3.3+
+ - Python 3.5+
Install
-------
- Follow `official documentation <http://pythonhosted.org/api_hour/installation.html>`_.
+ Follow `official documentation <https://pythonhosted.org/api_hour/installation.html>`_.
License
-------
@@ -114,6 +114,12 @@ Description: API Hour
CHANGES
=======
+ 0.8.2 (2017-11-10)
+ ------------------
+
+ * Add pre_start coroutine
+ * Fix setup.py to check correctly minimal Python version. Thanks @romuald
+
0.8.1 (2016-07-08)
------------------
diff --git a/api_hour.egg-info/SOURCES.txt b/api_hour.egg-info/SOURCES.txt
index 9a9ccfc..fe959a8 100644
--- a/api_hour.egg-info/SOURCES.txt
+++ b/api_hour.egg-info/SOURCES.txt
@@ -18,6 +18,9 @@ api_hour.egg-info/requires.txt
api_hour.egg-info/top_level.txt
api_hour/plugins/__init__.py
api_hour/plugins/aiohttp/__init__.py
+api_hour/plugins/aiohttp/environment.py
+api_hour/plugins/aiohttp/response.py
+api_hour/plugins/aiohttp/router.py
test/__init__.py
test/plugins/__init__.py
test/plugins/aiohttp/__init__.py
diff --git a/api_hour/__init__.py b/api_hour/__init__.py
index 8d75736..a7bb360 100644
--- a/api_hour/__init__.py
+++ b/api_hour/__init__.py
@@ -4,7 +4,7 @@ import collections
__author__ = 'Ludovic Gasc (GMLudo)'
__email__ = 'git at gmludo.eu'
-__version__ = '0.8.1'
+__version__ = '0.8.2'
version = __version__ + ' , Python ' + sys.version
diff --git a/api_hour/container.py b/api_hour/container.py
index 7598780..ef9281d 100644
--- a/api_hour/container.py
+++ b/api_hour/container.py
@@ -37,19 +37,25 @@ class Container:
"""To customize loop generation"""
return asyncio.new_event_loop()
+ async def pre_start(self):
+ pass
+
async def start(self):
LOG.info('Starting application...')
def pre_stop(self):
if not self._stopping:
self._stopping = True
- task = asyncio.ensure_future(self.stop(), loop=self.loop)
- task.add_done_callback(self.post_stop)
+ task = asyncio.ensure_future(self.shutdown(), loop=self.loop)
+ task.add_done_callback(self.cleanup())
else:
LOG.debug('Already stopping application, not doing anything')
- async def stop(self):
- LOG.info('Stopping application...')
+ async def shutdown(self):
+ pass
+
+ async def cleanup(self):
+ pass
def post_stop(self, future):
pass
diff --git a/api_hour/plugins/aiohttp/__init__.py b/api_hour/plugins/aiohttp/__init__.py
index 4c82405..107aa54 100644
--- a/api_hour/plugins/aiohttp/__init__.py
+++ b/api_hour/plugins/aiohttp/__init__.py
@@ -1,29 +1,3 @@
-from aiohttp.web import Response
-
-try:
- import ujson as json
-except ImportError:
- import json
-
-
-class JSON(Response):
- """Serialize response to JSON with aiohttp.web"""
-
- def __init__(self, data, status=200,
- reason=None, headers=None):
- body = json.dumps(data).encode('utf-8')
-
- super().__init__(body=body, status=status, reason=reason,
- headers=headers, content_type='application/json')
-
-
-class HTML(Response):
- """Serialize response to HTML with aiohttp.web"""
-
- def __init__(self, data, status=200,
- reason=None, headers=None):
-
- body = data.encode('utf-8')
-
- super().__init__(body=body, status=status, reason=reason,
- headers=headers, content_type='text/html')
\ No newline at end of file
+from .response import JSON, HTML
+from .environment import env_middleware_factory
+from .router import Router
diff --git a/api_hour/plugins/aiohttp/environment.py b/api_hour/plugins/aiohttp/environment.py
new file mode 100644
index 0000000..b494a0b
--- /dev/null
+++ b/api_hour/plugins/aiohttp/environment.py
@@ -0,0 +1,98 @@
+import logging
+
+try:
+ import ujson as json
+except ImportError:
+ import json
+
+from . import JSON
+
+LOG = logging.getLogger(__name__)
+
+
+async def env_middleware_factory(app, handler):
+ async def env_middleware(request):
+
+ LOG.debug('incoming request %s from: %s', request.method, request.path)
+ request['env'] = {
+ 'container': request.app['ah_container'],
+ 'id': request.headers.get('Request_ID', None)
+ }
+
+ try:
+ name = request.match_info.route.resource.name
+ config = request['env']['container'].env_config.get(name, [])
+ except AttributeError:
+ LOG.debug('Can not retrieve resource name for %(http_path)s', {'http_path': request.path})
+ return await handler(request)
+
+ LOG.debug('Resource name: %s, config: %s', name, config)
+
+ if 'pg' in config and 'pg' in request['env']['container'].engines:
+ LOG.debug('Creating pg cursor')
+ request['env']['pg'] = dict()
+ request['env']['pg']['engine'] = await request['env']['container'].engines['pg']
+ request['env']['pg']['cursor_context_manager'] = await request['env']['pg']['engine'].cursor()
+ request['env']['pg']['cursor'] = request['env']['pg']['cursor_context_manager'].__enter__()
+ await request['env']['pg']['cursor'].execute('BEGIN')
+
+ if 'mysql' in config and 'mysql' in request['env']['container'].engines:
+ LOG.debug('Creating mysql cursor')
+ request['env']['mysql'] = dict()
+ request['env']['mysql']['engine'] = await request['env']['container'].engines['mysql']
+ request['env']['mysql']['connection'] = await request['env']['mysql']['engine'].acquire()
+ request['env']['mysql']['cursor'] = await request['env']['mysql']['connection'].cursor()
+ await request['env']['mysql']['connection'].begin()
+
+ if 'redis' in config and 'redis' in request['env']['container'].engines:
+ LOG.debug('Creating redis connection')
+ request['env']['redis'] = dict()
+ request['env']['redis']['engine'] = await request['env']['container'].engines['redis']
+ request['env']['redis']['connection'] = await request['env']['redis']['engine'].acquire()
+
+ if 'json' in config:
+ LOG.debug('Parsing json')
+ try:
+ request['env']['json'] = await request.json(loads=json.loads)
+ except ValueError:
+ raise JSON(status=400, data='''The payload must be of json format''')
+ LOG.debug('Json parsed')
+
+ request['env']['name'] = name
+ request['env']['config'] = config
+
+ try:
+ LOG.debug('Handling request')
+ response = await handler(request)
+ except Exception as exception:
+ if 'pg' in config and 'pg' in request['env'] and not request['env']['pg']['cursor'].closed:
+ LOG.debug('Rolling back postgres transaction')
+ await request['env']['pg']['cursor'].execute('ROLLBACK')
+ request['env']['pg']['cursor_context_manager'].__exit__()
+
+ if 'mysql' in config and 'mysql' in request['env'] and not request['env']['mysql']['cursor'].closed:
+ LOG.debug('Rolling back mysql transaction')
+ await request['env']['mysql']['connection'].rollback()
+ await request['env']['mysql']['cursor'].close()
+ request['env']['mysql']['engine'].release(request['env']['mysql']['connection'])
+ raise exception
+ else:
+ if 'pg' in config and 'pg' in request['env'] and not request['env']['pg']['cursor'].closed:
+ LOG.debug('Committing postgres transaction')
+ await request['env']['pg']['cursor'].execute('COMMIT')
+ request['env']['pg']['cursor_context_manager'].__exit__()
+
+ if 'mysql' in config and 'mysql' in request['env'] and not request['env']['mysql']['cursor'].closed:
+ LOG.debug('Committing mysql transaction')
+ await request['env']['mysql']['connection'].commit()
+ await request['env']['mysql']['cursor'].close()
+ request['env']['mysql']['engine'].release(request['env']['mysql']['connection'])
+ finally:
+ if 'redis' in config and 'redis' in request['env'] and not request['env']['redis']['connection'].closed:
+ LOG.debug('Closing redis connection')
+ request['env']['redis']['connection'].close()
+ await request['env']['redis']['connection'].wait_closed()
+
+ return response
+
+ return env_middleware
diff --git a/api_hour/plugins/aiohttp/__init__.py b/api_hour/plugins/aiohttp/response.py
similarity index 68%
copy from api_hour/plugins/aiohttp/__init__.py
copy to api_hour/plugins/aiohttp/response.py
index 4c82405..7d31c93 100644
--- a/api_hour/plugins/aiohttp/__init__.py
+++ b/api_hour/plugins/aiohttp/response.py
@@ -1,4 +1,4 @@
-from aiohttp.web import Response
+from aiohttp.web import HTTPException
try:
import ujson as json
@@ -6,24 +6,25 @@ except ImportError:
import json
-class JSON(Response):
+class JSON(HTTPException):
"""Serialize response to JSON with aiohttp.web"""
def __init__(self, data, status=200,
reason=None, headers=None):
body = json.dumps(data).encode('utf-8')
+ self.status_code = status
- super().__init__(body=body, status=status, reason=reason,
+ super().__init__(body=body, reason=reason,
headers=headers, content_type='application/json')
-class HTML(Response):
+class HTML(HTTPException):
"""Serialize response to HTML with aiohttp.web"""
def __init__(self, data, status=200,
reason=None, headers=None):
-
body = data.encode('utf-8')
+ self.status_code = status
- super().__init__(body=body, status=status, reason=reason,
- headers=headers, content_type='text/html')
\ No newline at end of file
+ super().__init__(body=body, reason=reason,
+ headers=headers, content_type='text/html')
diff --git a/api_hour/plugins/aiohttp/router.py b/api_hour/plugins/aiohttp/router.py
new file mode 100644
index 0000000..0ad7731
--- /dev/null
+++ b/api_hour/plugins/aiohttp/router.py
@@ -0,0 +1,16 @@
+from aiohttp.web_urldispatcher import UrlDispatcher
+
+
+class Router(UrlDispatcher):
+ def __init__(self, container):
+ self._container = container
+ self._container.env_config = dict()
+ super().__init__()
+
+ def add_route(self, method, path, handler,
+ *, name=None, expect_handler=None, env_config=None):
+ resource = self.add_resource(path, name=name)
+ if name:
+ self._container.env_config[name] = env_config or []
+ return resource.add_route(method, handler,
+ expect_handler=expect_handler)
diff --git a/api_hour/worker.py b/api_hour/worker.py
index 01f7c93..95e2bf1 100644
--- a/api_hour/worker.py
+++ b/api_hour/worker.py
@@ -7,6 +7,11 @@ import signal
import sys
import gunicorn.workers.base as base
+try:
+ import aiohttp.web
+except ImportError:
+ aiohttp = None
+
# from pycallgraph import PyCallGraph
# from pycallgraph import Config
# from pycallgraph.output import GraphvizOutput
@@ -59,35 +64,38 @@ class Worker(base.Worker):
self.handlers = None
# stop accepting connections
+ self.log.info("Closing %s servers. PID: %s", len(servers), self.pid)
+ closing = list()
for server, handler in servers.items():
- if hasattr(handler, 'connections'):
- self.log.info("Stopping server: %s, connections: %s",
- self.pid, len(handler.connections))
- else:
- self.log.info("Stopping server: %s",
- self.pid)
server.close()
+ closing.append(server.wait_closed())
+
+ if closing:
+ await asyncio.wait(closing, return_when=asyncio.ALL_COMPLETED, loop=self.loop)
- # stop alive connections
+ self.log.debug('Shutting down')
+ await self.container.shutdown()
tasks = []
for handler in servers.values():
- if hasattr(handler, 'finish_connections'):
- tasks.append(handler.finish_connections(
- timeout=self.cfg.graceful_timeout / 100 * 80))
+ if aiohttp and isinstance(handler, aiohttp.web.Server):
+ tasks.append(handler.shutdown(timeout=self.cfg.graceful_timeout / 100 * 80))
if tasks:
- await asyncio.wait(tasks, loop=self.loop)
+ await asyncio.wait(tasks, loop=self.loop, return_when=asyncio.ALL_COMPLETED)
- # stop container
- await self.container.stop()
+ self.log.debug('Cleaning container')
+ await self.container.cleanup()
- # Wait the end of close
- for server, handler in servers.items():
- await server.wait_closed()
+ self.log.debug('All server closed')
+
+ else:
+ await self.container.shutdown()
+ await self.container.cleanup()
async def _run(self):
self.container = self.app.callable(config=self.app.config,
worker=self,
loop=self.loop)
+ await self.container.pre_start()
if asyncio.iscoroutinefunction(self.container.make_servers):
self.handlers = await self.container.make_servers(self.sockets)
else:
diff --git a/setup.cfg b/setup.cfg
index acb701c..ae4385d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,7 +5,7 @@ description-file = README.rst
universal = 1
[egg_info]
-tag_date = 0
tag_build =
+tag_date = 0
tag_svn_revision = 0
diff --git a/setup.py b/setup.py
index 584369b..bfab681 100644
--- a/setup.py
+++ b/setup.py
@@ -5,10 +5,12 @@ from setuptools import setup, find_packages
__docformat__ = 'rst'
-PY_VER = sys.version_info
+PY_VER = sys.version_info[:3]
if PY_VER < (3, 5, 0):
- raise RuntimeError("api_hour doesn't support Python earlier than 3.5.0, current Python version is: %s" % PY_VER)
+ PY_VERS = '.'.join(map(str, PY_VER))
+ raise RuntimeError("api_hour doesn't support Python earlier than 3.5.0, "
+ "current Python version is: %s" % PY_VERS)
install_requires = ['gunicorn', 'PyYAML', 'setproctitle']
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/api-hour.git
More information about the Python-modules-commits
mailing list