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.
This commit is contained in:
Eli Uriegas 2017-01-31 14:34:26 -06:00
parent c91d264ff1
commit 7f85be43c6
5 changed files with 55 additions and 71 deletions

View File

@ -1,5 +1,6 @@
from .sanic import Sanic from sanic.app import Sanic
from .blueprints import Blueprint from sanic.blueprints import Blueprint
__version__ = '0.3.0' __version__ = '0.3.0'

View File

@ -1,23 +1,25 @@
import logging import logging
from asyncio import get_event_loop import multiprocessing
from collections import deque from collections import deque
from functools import partial from functools import partial
from inspect import isawaitable, stack, getmodulename from inspect import isawaitable, stack, getmodulename
from traceback import format_exc from traceback import format_exc
import warnings import warnings
from .config import Config from sanic.policy import get_event_loop
from .constants import HTTP_METHODS from sanic.config import Config
from .exceptions import Handler from sanic.constants import HTTP_METHODS
from .exceptions import ServerError from sanic.exceptions import Handler
from .log import log from sanic.exceptions import ServerError
from .response import HTTPResponse from sanic.log import log
from .router import Router from sanic.response import HTTPResponse
from .server import serve, serve_multiple, HttpProtocol from sanic.router import Router
from .static import register as static_register from sanic.server import serve, serve_multiple, HttpProtocol
from sanic.static import register as static_register
class Sanic: class Sanic:
def __init__(self, name=None, router=None, def __init__(self, name=None, router=None,
error_handler=None): error_handler=None):
# Only set up a default log handler if the # Only set up a default log handler if the
@ -306,63 +308,43 @@ class Sanic:
:param protocol: Subclass of asyncio protocol class :param protocol: Subclass of asyncio protocol class
:return: Nothing :return: Nothing
""" """
server_settings = self._helper( server_settings = self._get_server_settings(
host=host, port=port, debug=debug, before_start=before_start, host=host, port=port, debug=debug, before_start=before_start,
after_start=after_start, before_stop=before_stop, after_start=after_start, before_stop=before_stop,
after_stop=after_stop, ssl=ssl, sock=sock, workers=workers, after_stop=after_stop, ssl=ssl, sock=sock, workers=workers,
loop=loop, protocol=protocol, backlog=backlog, loop=loop, protocol=protocol, backlog=backlog,
stop_event=stop_event, register_sys_signals=register_sys_signals) stop_event=stop_event, register_sys_signals=register_sys_signals)
log.info(
'Goin\' Fast @ {}://{}:{}'.format(
'https' if ssl else 'http', host, port))
try: try:
if workers == 1: if workers == 1:
serve(**server_settings) serve(**server_settings)
else: else:
serve_multiple(server_settings, workers, stop_event) serve_multiple(server_settings, workers, stop_event)
except Exception as e: except Exception as e:
log.exception( log.exception(
'Experienced exception while trying to serve') 'Experienced exception while trying to serve')
log.info("Server Stopped") log.info("Server Stopped")
def stop(self): def stop(self):
"""This kills the Sanic""" """This kills the Sanic"""
for process in multiprocessing.active_children():
process.terminate()
get_event_loop().stop() get_event_loop().stop()
async def create_server(self, host="127.0.0.1", port=8000, debug=False, def _get_server_settings(
before_start=None, after_start=None, self, host="127.0.0.1", port=8000, debug=False,
before_stop=None, after_stop=None, ssl=None, before_start=None, after_start=None, before_stop=None,
sock=None, loop=None, protocol=HttpProtocol, after_stop=None, ssl=None, sock=None, workers=1, loop=None,
backlog=100, stop_event=None): protocol=HttpProtocol, backlog=100, stop_event=None,
""" register_sys_signals=True, run_async=False):
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):
""" """
Helper function used by `run` and `create_server`. Helper function used by `run` and `create_server`.
""" """
self.error_handler.debug = debug self.error_handler.debug = debug
self.debug = debug self.debug = debug
self.loop = loop = get_event_loop()
if loop is not None: if loop is not None:
if self.debug: if self.debug:
@ -396,8 +378,7 @@ class Sanic:
("before_server_start", "before_start", before_start, False), ("before_server_start", "before_start", before_start, False),
("after_server_start", "after_start", after_start, False), ("after_server_start", "after_start", after_start, False),
("before_server_stop", "before_stop", before_stop, True), ("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 = [] listeners = []
for blueprint in self.blueprints.values(): for blueprint in self.blueprints.values():
listeners += blueprint.listeners[event_name] listeners += blueprint.listeners[event_name]
@ -415,13 +396,4 @@ class Sanic:
log.setLevel(logging.DEBUG) log.setLevel(logging.DEBUG)
log.debug(self.config.LOGO) 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 return server_settings

13
sanic/policy.py Normal file
View File

@ -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)

View File

@ -14,16 +14,11 @@ import warnings
from httptools import HttpRequestParser from httptools import HttpRequestParser
from httptools.parser.errors import HttpParserError from httptools.parser.errors import HttpParserError
from .exceptions import ServerError from sanic.policy import new_event_loop, set_event_loop
from sanic.log import log
try: from sanic.request import Request
import uvloop as async_loop from sanic.exceptions import (
except ImportError: RequestTimeout, PayloadTooLarge, InvalidUsage, ServerError)
async_loop = asyncio
from .log import log
from .request import Request
from .exceptions import RequestTimeout, PayloadTooLarge, InvalidUsage
current_time = None 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 :param protocol: Subclass of asyncio protocol class
:return: Nothing :return: Nothing
""" """
loop = async_loop.new_event_loop() loop = new_event_loop()
asyncio.set_event_loop(loop) set_event_loop(loop)
if debug: if debug:
loop.set_debug(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) trigger_events(after_stop, loop)
loop.stop()
loop.close() loop.close()
@ -396,6 +393,8 @@ def serve_multiple(server_settings, workers, stop_event=None):
sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock.bind((server_settings['host'], server_settings['port'])) sock.bind((server_settings['host'], server_settings['port']))
set_inheritable(sock.fileno(), True) set_inheritable(sock.fileno(), True)
host = server_settings['host']
port = server_settings['port']
server_settings['sock'] = sock server_settings['sock'] = sock
server_settings['host'] = None server_settings['host'] = None
server_settings['port'] = None server_settings['port'] = None
@ -420,5 +419,3 @@ def serve_multiple(server_settings, workers, stop_event=None):
for process in processes: for process in processes:
process.terminate() process.terminate()
sock.close() sock.close()
asyncio.get_event_loop().stop()

View File

@ -29,10 +29,11 @@ def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
async def _collect_response(sanic, loop): async def _collect_response(sanic, loop):
try: try:
response = await local_request(method, uri, *request_args, response = await local_request(
**request_kwargs) method, uri, *request_args, **request_kwargs)
results.append(response) results.append(response)
except Exception as e: except Exception as e:
log.exception('Exception occured when collecting response')
exceptions.append(e) exceptions.append(e)
app.stop() app.stop()