Merge pull request #408 from agoose77/master

Use app decorator instead of run arguments for before_start
This commit is contained in:
Eli Uriegas 2017-02-13 12:54:46 -06:00 committed by GitHub
commit 1660041470
13 changed files with 91 additions and 61 deletions

View File

@ -7,15 +7,6 @@ keyword arguments:
- `host` *(default `"127.0.0.1"`)*: Address to host the server on.
- `port` *(default `8000`)*: Port to host the server on.
- `debug` *(default `False`)*: Enables debug output (slows server).
- `before_start` *(default `None`)*: Function or list of functions to be executed
before the server starts accepting connections.
- `after_start` *(default `None`)*: Function or list of functions to be executed
after the server starts accepting connections.
- `before_stop` *(default `None`)*: Function or list of functions to be
executed when a stop signal is received before it is
respected.
- `after_stop` *(default `None`)*: Function or list of functions to be executed
when all requests are complete.
- `ssl` *(default `None`)*: `SSLContext` for SSL encryption of worker(s).
- `sock` *(default `None`)*: Socket for the server to accept connections from.
- `workers` *(default `1`)*: Number of worker processes to spawn.

View File

@ -8,6 +8,7 @@ app = Sanic(__name__)
sem = None
@app.listener('before_server_start')
def init(sanic, loop):
global sem
CONCURRENCY_PER_WORKER = 4
@ -33,4 +34,4 @@ async def test(request):
return json(response)
app.run(host="0.0.0.0", port=8000, workers=2, before_start=init)
app.run(host="0.0.0.0", port=8000, workers=2)

View File

@ -26,6 +26,7 @@ async def get_pool():
app = Sanic(name=__name__)
@app.listener('before_server_start')
async def prepare_db(app, loop):
"""
Let's create some table and add some data
@ -61,5 +62,4 @@ async def handle(request):
if __name__ == '__main__':
app.run(host='0.0.0.0',
port=8000,
debug=True,
before_start=prepare_db)
debug=True)

View File

@ -32,7 +32,7 @@ polls = sa.Table('sanic_polls', metadata,
app = Sanic(name=__name__)
@app.listener('before_server_start')
async def prepare_db(app, loop):
""" Let's add some data
@ -58,9 +58,10 @@ async def handle(request):
async with engine.acquire() as conn:
result = []
async for row in conn.execute(polls.select()):
result.append({"question": row.question, "pub_date": row.pub_date})
result.append({"question": row.question,
"pub_date": row.pub_date})
return json({"polls": result})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, before_start=prepare_db)
app.run(host='0.0.0.0', port=8000)

View File

@ -27,6 +27,7 @@ def jsonify(records):
app = Sanic(__name__)
@app.listener('before_server_start')
async def create_db(app, loop):
"""
Create some table and add some data
@ -55,4 +56,4 @@ async def handler(request):
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, before_start=create_db)
app.run(host='0.0.0.0', port=8000)

View File

@ -14,14 +14,6 @@ from peewee_async import Manager, PostgresqlDatabase
# we instantiate a custom loop so we can pass it to our db manager
def setup(app, loop):
database = PostgresqlDatabase(database='test',
host='127.0.0.1',
user='postgres',
password='mysecretpassword')
objects = Manager(database, loop=loop)
## from peewee_async docs:
# Also theres no need to connect and re-connect before executing async queries
# with manager! Its all automatic. But you can run Manager.connect() or
@ -48,6 +40,15 @@ objects.database.allow_sync = False # this will raise AssertionError on ANY sync
app = Sanic('peewee_example')
@app.listener('before_server_start')
def setup(app, loop):
database = PostgresqlDatabase(database='test',
host='127.0.0.1',
user='postgres',
password='mysecretpassword')
objects = Manager(database, loop=loop)
@app.route('/post/<key>/<value>')
async def post(request, key, value):
"""
@ -75,4 +76,4 @@ async def get(request):
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8000, before_start=setup)
app.run(host='0.0.0.0', port=8000)

View File

@ -64,12 +64,14 @@ def query_string(request):
# Run Server
# ----------------------------------------------- #
@app.listener('after_server_start')
def after_start(app, loop):
log.info("OH OH OH OH OHHHHHHHH")
@app.listener('before_server_stop')
def before_stop(app, loop):
log.info("TRIED EVERYTHING")
app.run(host="0.0.0.0", port=8000, debug=True, after_start=after_start, before_stop=before_stop)
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@ -65,6 +65,11 @@ class Blueprint:
app.static(uri, future.file_or_directory,
*future.args, **future.kwargs)
# Event listeners
for event, listeners in self.listeners.items():
for listener in listeners:
app.listener(event)(listener)
def route(self, uri, methods=frozenset({'GET'}), host=None):
"""
Creates a blueprint route from a decorated function.

View File

@ -2,7 +2,7 @@ import logging
import re
import warnings
from asyncio import get_event_loop
from collections import deque
from collections import deque, defaultdict
from functools import partial
from inspect import isawaitable, stack, getmodulename
from traceback import format_exc
@ -10,8 +10,8 @@ from urllib.parse import urlencode, urlunparse
from .config import Config
from .constants import HTTP_METHODS
from .handlers import ErrorHandler
from .exceptions import ServerError, URLBuildError
from .handlers import ErrorHandler
from .log import log
from .response import HTTPResponse
from .router import Router
@ -21,6 +21,7 @@ from .views import CompositionView
class Sanic:
def __init__(self, name=None, router=None,
error_handler=None):
# Only set up a default log handler if the
@ -46,6 +47,7 @@ class Sanic:
self.debug = None
self.sock = None
self.processes = None
self.listeners = defaultdict(list)
# Register alternative method names
self.go_fast = self.run
@ -61,6 +63,18 @@ class Sanic:
# Registration
# -------------------------------------------------------------------- #
# Decorator
def listener(self, event):
"""
Create a listener from a decorated function.
:param event: Event to listen to.
"""
def decorator(listener):
self.listeners[event].append(listener)
return listener
return decorator
# Decorator
def route(self, uri, methods=frozenset({'GET'}), host=None):
"""
@ -419,6 +433,7 @@ class Sanic:
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)
try:
if workers == 1:
serve(**server_settings)
@ -473,6 +488,16 @@ class Sanic:
"pull/335 has more information.",
DeprecationWarning)
# Deprecate this
if any(arg is not None for arg in (after_stop, after_start,
before_start, before_stop)):
if debug:
warnings.simplefilter('default')
warnings.warn("Passing a before_start, before_stop, after_start or"
"after_stop callback will be deprecated in next "
"major version after 0.4.0",
DeprecationWarning)
self.error_handler.debug = debug
self.debug = debug
loop = self.loop
@ -497,19 +522,18 @@ class Sanic:
# Register start/stop events
# -------------------------------------------- #
for event_name, settings_name, args, reverse in (
("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),
for event_name, settings_name, reverse, args in (
("before_server_start", "before_start", False, before_start),
("after_server_start", "after_start", False, after_start),
("before_server_stop", "before_stop", True, before_stop),
("after_server_stop", "after_stop", True, after_stop),
):
listeners = []
for blueprint in self.blueprints.values():
listeners += blueprint.listeners[event_name]
listeners = self.listeners[event_name].copy()
if args:
if callable(args):
args = [args]
listeners += args
listeners.append(args)
else:
listeners.extend(args)
if reverse:
listeners.reverse()
# Prepend sanic to the arguments when listeners are triggered

View File

@ -28,6 +28,7 @@ def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
results[0] = request
app.request_middleware.appendleft(_collect_request)
@app.listener('after_server_start')
async def _collect_response(sanic, loop):
try:
response = await local_request(method, uri, *request_args,
@ -37,8 +38,8 @@ def sanic_endpoint_test(app, method='get', uri='/', gather_request=True,
exceptions.append(e)
app.stop()
app.run(host=HOST, debug=debug, port=PORT,
after_start=_collect_response, **server_kwargs)
app.run(host=HOST, debug=debug, port=PORT, **server_kwargs)
app.listeners['after_server_start'].pop()
if exceptions:
raise ValueError("Exception during request: {}".format(exceptions))

View File

@ -5,6 +5,7 @@ from sanic import Sanic
def test_bad_request_response():
app = Sanic('test_bad_request_response')
lines = []
@app.listener('after_server_start')
async def _request(sanic, loop):
connect = asyncio.open_connection('127.0.0.1', 42101)
reader, writer = await connect
@ -15,6 +16,6 @@ def test_bad_request_response():
break
lines.append(line)
app.stop()
app.run(host='127.0.0.1', port=42101, debug=False, after_start=_request)
app.run(host='127.0.0.1', port=42101, debug=False)
assert lines[0] == b'HTTP/1.1 400 Bad Request\r\n'
assert lines[-1] == b'Error: Bad Request'

View File

@ -9,10 +9,10 @@ from sanic import Sanic
from sanic.utils import HOST, PORT
AVAILABLE_LISTENERS = [
'before_start',
'after_start',
'before_stop',
'after_stop'
'before_server_start',
'after_server_start',
'before_server_stop',
'after_server_stop'
]
@ -42,9 +42,10 @@ def test_single_listener(listener_name):
random_name_app = Sanic(''.join(
[choice(ascii_letters) for _ in range(choice(range(5, 10)))]))
output = list()
start_stop_app(
random_name_app,
**{listener_name: create_listener(listener_name, output)})
# Register listener
random_name_app.listener(listener_name)(
create_listener(listener_name, output))
start_stop_app(random_name_app)
assert random_name_app.name + listener_name == output.pop()
@ -52,9 +53,9 @@ def test_all_listeners():
random_name_app = Sanic(''.join(
[choice(ascii_letters) for _ in range(choice(range(5, 10)))]))
output = list()
start_stop_app(
random_name_app,
**{listener_name: create_listener(listener_name, output)
for listener_name in AVAILABLE_LISTENERS})
for listener_name in AVAILABLE_LISTENERS:
listener = create_listener(listener_name, output)
random_name_app.listener(listener_name)(listener)
start_stop_app(random_name_app)
for listener_name in AVAILABLE_LISTENERS:
assert random_name_app.name + listener_name == output.pop()

View File

@ -27,10 +27,11 @@ def test_register_system_signals():
async def hello_route(request):
return HTTPResponse()
app.run(HOST, PORT,
before_start=set_loop,
after_start=stop,
after_stop=after)
app.listener('after_server_start')(stop)
app.listener('before_server_start')(set_loop)
app.listener('after_server_stop')(after)
app.run(HOST, PORT)
assert calledq.get() == True
@ -42,9 +43,9 @@ def test_dont_register_system_signals():
async def hello_route(request):
return HTTPResponse()
app.run(HOST, PORT,
before_start=set_loop,
after_start=stop,
after_stop=after,
register_sys_signals=False)
app.listener('after_server_start')(stop)
app.listener('before_server_start')(set_loop)
app.listener('after_server_stop')(after)
app.run(HOST, PORT, register_sys_signals=False)
assert calledq.get() == False