From f9b3f6fa19c359988fa96ff6af76c81f8955743a Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 28 Jun 2017 10:27:01 +0100 Subject: [PATCH 1/3] set_loop for app check, allow app_factory() --- aiohttp_devtools/cli.py | 7 +++--- aiohttp_devtools/runserver/config.py | 20 ++++++++++++---- aiohttp_devtools/runserver/serve.py | 5 +--- tests/test_runserver_main.py | 36 ++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/aiohttp_devtools/cli.py b/aiohttp_devtools/cli.py index 1bfaf7be..9ee4c000 100644 --- a/aiohttp_devtools/cli.py +++ b/aiohttp_devtools/cli.py @@ -51,8 +51,9 @@ def serve(path, livereload, port, verbose): precheck_help = ("Whether to start and stop the app before creating it in a subprocess to check it's working. " "env variable AIO_PRECHECK") app_factory_help = ('name of the app factory to create an aiohttp.web.Application with, if missing default app-factory ' - 'names are tried. This can be either a function with signature "def create_app(loop): -> ' - 'Application" or just an instance of aiohttp.Application. env variable AIO_APP_FACTORY') + 'names are tried. This can be either a function with signature ' + '"def create_app(loop): -> Application" or "def create_app(): -> Application" ' + 'or just an instance of aiohttp.Application. env variable AIO_APP_FACTORY') port_help = 'Port to serve app from, default 8000. env variable: AIO_PORT' aux_port_help = 'Port to serve auxiliary app (reload and static) on, default port + 1. env variable: AIO_AUX_PORT' @@ -73,7 +74,7 @@ def serve(path, livereload, port, verbose): @click.option('-v', '--verbose', is_flag=True, help=verbose_help) def runserver(**config): """ - Run a development server for aiohttp apps. + Run a development server for an aiohttp apps. Takes one argument "app-path" which should be a path to either a directory containing a recognized default file ("app.py" or "main.py") or to a specific file. Defaults to the environment variable "AIO_APP_PATH" or ".". diff --git a/aiohttp_devtools/runserver/config.py b/aiohttp_devtools/runserver/config.py index 729ce617..4aaeba42 100644 --- a/aiohttp_devtools/runserver/config.py +++ b/aiohttp_devtools/runserver/config.py @@ -1,3 +1,4 @@ +import inspect import re import sys from importlib import import_module @@ -175,19 +176,30 @@ def check(self, loop): raise AdevConfigError('app_factory "{.app_factory_name}" is not callable or an ' 'instance of aiohttp.web.Application'.format(self)) + loop.run_until_complete(self._startup_cleanup(loop)) + + def load_app(self, loop): if isinstance(self.app_factory, Application): app = self.app_factory else: # app_factory should be a proper factory with signature (loop): -> Application - app = self.app_factory(loop) + signature = inspect.signature(self.app_factory) + if 'loop' in signature.parameters: + app = self.app_factory(loop=loop) + else: + # loop argument missing, assume no arguments + app = self.app_factory() + if not isinstance(app, Application): raise AdevConfigError('app factory "{.app_factory_name}" returned "{.__class__.__name__}" not an ' 'aiohttp.web.Application'.format(self, app)) - logger.debug('app "%s" successfully created', app) - loop.run_until_complete(self._startup_cleanup(app)) + return app - async def _startup_cleanup(self, app): + async def _startup_cleanup(self, loop): + app = self.load_app(loop) + app._set_loop(loop) + logger.debug('app "%s" successfully created', app) logger.debug('running app startup...') await app.startup() logger.debug('running app cleanup...') diff --git a/aiohttp_devtools/runserver/serve.py b/aiohttp_devtools/runserver/serve.py index e2b6a661..53794d0d 100644 --- a/aiohttp_devtools/runserver/serve.py +++ b/aiohttp_devtools/runserver/serve.py @@ -95,10 +95,7 @@ def serve_main_app(config: Config, loop: asyncio.AbstractEventLoop=None): loop = loop or asyncio.get_event_loop() - if isinstance(config.app_factory, Application): - app = config.app_factory - else: - app = config.app_factory(loop=loop) + app = config.load_app(loop) modify_main_app(app, config) diff --git a/tests/test_runserver_main.py b/tests/test_runserver_main.py index 16575606..ef24dd80 100644 --- a/tests/test_runserver_main.py +++ b/tests/test_runserver_main.py @@ -124,6 +124,42 @@ async def check_callback(session): code_event_handler._process.terminate() +@if_boxed +@slow +def test_start_runserver_no_loop_argument(tmpworkdir, loop): + mktree(tmpworkdir, { + 'app.py': """\ +from aiohttp import web + +async def hello(request): + return web.Response(text='

hello world

', content_type='text/html') + +def app(): + a = web.Application() + a.router.add_get('/', hello) + return a +""" + }) + asyncio.set_event_loop(loop) + aux_app, observer, aux_port, _ = runserver(app_path='app.py') + assert len(observer._handlers) == 1 + event_handlers = list(observer._handlers.values())[0] + code_event_handler = next(eh for eh in event_handlers if isinstance(eh, PyCodeEventHandler)) + + async def check_callback(session): + async with session.get('http://localhost:8000/') as r: + assert r.status == 200 + assert r.headers['content-type'].startswith('text/html') + text = await r.text() + assert '

hello world

' in text + assert '' in text + + try: + loop.run_until_complete(check_server_running(loop, check_callback)) + finally: + code_event_handler._process.terminate() + + def kill_parent_soon(pid): time.sleep(0.2) os.kill(pid, signal.SIGINT) From bdc23518bcc93a29cb893f94c0f58894aaeddd01 Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 28 Jun 2017 10:32:53 +0100 Subject: [PATCH 2/3] history and uprev --- HISTORY.rst | 4 ++++ aiohttp_devtools/version.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index ff2dae2d..21c72402 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,10 @@ History ------- +0.5.0 (2017-XX-XX) +------------------ +* set loop before running app check #96 +* allow app factory with simpler signature ``app_factory()`` #96 0.4.1 (2017-06-03) ------------------ diff --git a/aiohttp_devtools/version.py b/aiohttp_devtools/version.py index 27957026..1e0f2542 100644 --- a/aiohttp_devtools/version.py +++ b/aiohttp_devtools/version.py @@ -2,4 +2,4 @@ __all__ = ['VERSION'] -VERSION = StrictVersion('0.4.1') +VERSION = StrictVersion('0.5.0') From ac7bb7d7b9299c9b24118bb8fa380ad7d71ee3dc Mon Sep 17 00:00:00 2001 From: Samuel Colvin Date: Wed, 28 Jun 2017 10:59:42 +0100 Subject: [PATCH 3/3] fix linting and tests --- aiohttp_devtools/runserver/serve.py | 2 +- tests/test_cli.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aiohttp_devtools/runserver/serve.py b/aiohttp_devtools/runserver/serve.py index 53794d0d..287dd667 100644 --- a/aiohttp_devtools/runserver/serve.py +++ b/aiohttp_devtools/runserver/serve.py @@ -6,7 +6,7 @@ import aiohttp_debugtoolbar from aiohttp import WSMsgType, web from aiohttp.hdrs import LAST_MODIFIED -from aiohttp.web import Application, FileResponse, Response +from aiohttp.web import FileResponse, Response from aiohttp.web_exceptions import HTTPNotFound, HTTPNotModified from aiohttp.web_urldispatcher import StaticResource from yarl import unquote diff --git a/tests/test_cli.py b/tests/test_cli.py index e0edb0d5..ccb3c101 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,7 @@ def test_cli_help(): runner = CliRunner() result = runner.invoke(cli, ['--help']) assert result.exit_code == 0 - assert 'Run a development server for aiohttp apps.' in result.output + assert 'Run a development server for an aiohttp apps.' in result.output assert 'Serve static files from a directory.' in result.output assert 'Create a new aiohttp app.' in result.output