From 7f85be43c6ba1658f877487410600b4aaca5d9f0 Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Tue, 31 Jan 2017 14:34:26 -0600 Subject: [PATCH] Removes the need for asycnio global settings Also moves sanic.py -> app.py and removes the need for us to relative import anymore. This is a step towards allowing people to use things like `sanic.get_event_loop()` instead of having to set global asyncio settings. Does not seem to work on 3.5.1 but works fine on every version after that. --- sanic/__init__.py | 5 ++- sanic/{sanic.py => app.py} | 78 ++++++++++++-------------------------- sanic/policy.py | 13 +++++++ sanic/server.py | 25 ++++++------ sanic/utils.py | 5 ++- 5 files changed, 55 insertions(+), 71 deletions(-) rename sanic/{sanic.py => app.py} (87%) create mode 100644 sanic/policy.py diff --git a/sanic/__init__.py b/sanic/__init__.py index a0d0552f..dec71a7f 100644 --- a/sanic/__init__.py +++ b/sanic/__init__.py @@ -1,5 +1,6 @@ -from .sanic import Sanic -from .blueprints import Blueprint +from sanic.app import Sanic +from sanic.blueprints import Blueprint + __version__ = '0.3.0' diff --git a/sanic/sanic.py b/sanic/app.py similarity index 87% rename from sanic/sanic.py rename to sanic/app.py index 1d3e252e..22c1a38f 100644 --- a/sanic/sanic.py +++ b/sanic/app.py @@ -1,23 +1,25 @@ import logging -from asyncio import get_event_loop +import multiprocessing from collections import deque from functools import partial from inspect import isawaitable, stack, getmodulename from traceback import format_exc import warnings -from .config import Config -from .constants import HTTP_METHODS -from .exceptions import Handler -from .exceptions import ServerError -from .log import log -from .response import HTTPResponse -from .router import Router -from .server import serve, serve_multiple, HttpProtocol -from .static import register as static_register +from sanic.policy import get_event_loop +from sanic.config import Config +from sanic.constants import HTTP_METHODS +from sanic.exceptions import Handler +from sanic.exceptions import ServerError +from sanic.log import log +from sanic.response import HTTPResponse +from sanic.router import Router +from sanic.server import serve, serve_multiple, HttpProtocol +from sanic.static import register as static_register class Sanic: + def __init__(self, name=None, router=None, error_handler=None): # Only set up a default log handler if the @@ -306,63 +308,43 @@ class Sanic: :param protocol: Subclass of asyncio protocol class :return: Nothing """ - server_settings = self._helper( + server_settings = self._get_server_settings( host=host, port=port, debug=debug, before_start=before_start, after_start=after_start, before_stop=before_stop, after_stop=after_stop, ssl=ssl, sock=sock, workers=workers, loop=loop, protocol=protocol, backlog=backlog, stop_event=stop_event, register_sys_signals=register_sys_signals) + log.info( + 'Goin\' Fast @ {}://{}:{}'.format( + 'https' if ssl else 'http', host, port)) try: if workers == 1: serve(**server_settings) else: serve_multiple(server_settings, workers, stop_event) - except Exception as e: log.exception( 'Experienced exception while trying to serve') - log.info("Server Stopped") def stop(self): """This kills the Sanic""" + for process in multiprocessing.active_children(): + process.terminate() get_event_loop().stop() - async def create_server(self, host="127.0.0.1", port=8000, debug=False, - before_start=None, after_start=None, - before_stop=None, after_stop=None, ssl=None, - sock=None, loop=None, protocol=HttpProtocol, - backlog=100, stop_event=None): - """ - Asynchronous version of `run`. - """ - server_settings = self._helper( - host=host, port=port, debug=debug, before_start=before_start, - after_start=after_start, before_stop=before_stop, - after_stop=after_stop, ssl=ssl, sock=sock, loop=loop, - protocol=protocol, backlog=backlog, stop_event=stop_event, - async_run=True) - - # Serve - proto = "http" - if ssl is not None: - proto = "https" - log.info('Goin\' Fast @ {}://{}:{}'.format(proto, host, port)) - - return await serve(**server_settings) - - def _helper(self, host="127.0.0.1", port=8000, debug=False, - before_start=None, after_start=None, before_stop=None, - after_stop=None, ssl=None, sock=None, workers=1, loop=None, - protocol=HttpProtocol, backlog=100, stop_event=None, - register_sys_signals=True, run_async=False): + def _get_server_settings( + self, host="127.0.0.1", port=8000, debug=False, + before_start=None, after_start=None, before_stop=None, + after_stop=None, ssl=None, sock=None, workers=1, loop=None, + protocol=HttpProtocol, backlog=100, stop_event=None, + register_sys_signals=True, run_async=False): """ Helper function used by `run` and `create_server`. """ self.error_handler.debug = debug self.debug = debug - self.loop = loop = get_event_loop() if loop is not None: if self.debug: @@ -396,8 +378,7 @@ class Sanic: ("before_server_start", "before_start", before_start, False), ("after_server_start", "after_start", after_start, False), ("before_server_stop", "before_stop", before_stop, True), - ("after_server_stop", "after_stop", after_stop, True), - ): + ("after_server_stop", "after_stop", after_stop, True)): listeners = [] for blueprint in self.blueprints.values(): listeners += blueprint.listeners[event_name] @@ -415,13 +396,4 @@ class Sanic: log.setLevel(logging.DEBUG) log.debug(self.config.LOGO) - if run_async: - server_settings['run_async'] = True - - # Serve - proto = "http" - if ssl is not None: - proto = "https" - log.info('Goin\' Fast @ {}://{}:{}'.format(proto, host, port)) - return server_settings diff --git a/sanic/policy.py b/sanic/policy.py new file mode 100644 index 00000000..d554d76c --- /dev/null +++ b/sanic/policy.py @@ -0,0 +1,13 @@ +import uvloop + +_policy = uvloop.EventLoopPolicy() + +def get_event_loop(): + return _policy.get_event_loop() + +def new_event_loop(): + return _policy.new_event_loop() + +def set_event_loop(loop): + _policy.set_event_loop(loop) + diff --git a/sanic/server.py b/sanic/server.py index 48c3827e..8345c114 100644 --- a/sanic/server.py +++ b/sanic/server.py @@ -14,16 +14,11 @@ import warnings from httptools import HttpRequestParser from httptools.parser.errors import HttpParserError -from .exceptions import ServerError - -try: - import uvloop as async_loop -except ImportError: - async_loop = asyncio - -from .log import log -from .request import Request -from .exceptions import RequestTimeout, PayloadTooLarge, InvalidUsage +from sanic.policy import new_event_loop, set_event_loop +from sanic.log import log +from sanic.request import Request +from sanic.exceptions import ( + RequestTimeout, PayloadTooLarge, InvalidUsage, ServerError) current_time = None @@ -297,8 +292,8 @@ def serve(host, port, request_handler, error_handler, before_start=None, :param protocol: Subclass of asyncio protocol class :return: Nothing """ - loop = async_loop.new_event_loop() - asyncio.set_event_loop(loop) + loop = new_event_loop() + set_event_loop(loop) if debug: loop.set_debug(debug) @@ -371,6 +366,8 @@ def serve(host, port, request_handler, error_handler, before_start=None, trigger_events(after_stop, loop) + loop.stop() + loop.close() @@ -396,6 +393,8 @@ def serve_multiple(server_settings, workers, stop_event=None): sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sock.bind((server_settings['host'], server_settings['port'])) set_inheritable(sock.fileno(), True) + host = server_settings['host'] + port = server_settings['port'] server_settings['sock'] = sock server_settings['host'] = None server_settings['port'] = None @@ -420,5 +419,3 @@ def serve_multiple(server_settings, workers, stop_event=None): for process in processes: process.terminate() sock.close() - - asyncio.get_event_loop().stop() diff --git a/sanic/utils.py b/sanic/utils.py index 644a2a22..e9b4ec32 100644 --- a/sanic/utils.py +++ b/sanic/utils.py @@ -29,10 +29,11 @@ def sanic_endpoint_test(app, method='get', uri='/', gather_request=True, async def _collect_response(sanic, loop): try: - response = await local_request(method, uri, *request_args, - **request_kwargs) + response = await local_request( + method, uri, *request_args, **request_kwargs) results.append(response) except Exception as e: + log.exception('Exception occured when collecting response') exceptions.append(e) app.stop()