fix merge conflicts
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from collections import ChainMap
|
||||
from mimetypes import guess_type
|
||||
from os import path
|
||||
from ujson import dumps as json_dumps
|
||||
@@ -98,17 +97,15 @@ class HTTPResponse:
|
||||
def output(self, version="1.1", keep_alive=False, keep_alive_timeout=None):
|
||||
# This is all returned in a kind-of funky way
|
||||
# We tried to make this as fast as possible in pure python
|
||||
default_header = dict()
|
||||
if keep_alive:
|
||||
if keep_alive_timeout:
|
||||
default_header['Keep-Alive'] = keep_alive_timeout
|
||||
default_header['Connection'] = 'keep-alive'
|
||||
else:
|
||||
default_header['Connection'] = 'close'
|
||||
default_header['Content-Length'] = len(self.body)
|
||||
default_header['Content-Type'] = self.content_type
|
||||
timeout_header = b''
|
||||
if keep_alive and keep_alive_timeout is not None:
|
||||
timeout_header = b'Keep-Alive: %d\r\n' % keep_alive_timeout
|
||||
self.headers['Content-Length'] = self.headers.get(
|
||||
'Content-Length', len(self.body))
|
||||
self.headers['Content-Type'] = self.headers.get(
|
||||
'Content-Type', self.content_type)
|
||||
headers = b''
|
||||
for name, value in ChainMap(self.headers, default_header).items():
|
||||
for name, value in self.headers.items():
|
||||
try:
|
||||
headers += (
|
||||
b'%b: %b\r\n' % (
|
||||
@@ -117,6 +114,7 @@ class HTTPResponse:
|
||||
headers += (
|
||||
b'%b: %b\r\n' % (
|
||||
str(name).encode(), str(value).encode('utf-8')))
|
||||
|
||||
# Try to pull from the common codes first
|
||||
# Speeds up response rate 6% over pulling from all
|
||||
status = COMMON_STATUS_CODES.get(self.status)
|
||||
@@ -124,11 +122,15 @@ class HTTPResponse:
|
||||
status = ALL_STATUS_CODES.get(self.status)
|
||||
|
||||
return (b'HTTP/%b %d %b\r\n'
|
||||
b'Connection: %b\r\n'
|
||||
b'%b'
|
||||
b'%b\r\n'
|
||||
b'%b') % (
|
||||
version.encode(),
|
||||
self.status,
|
||||
status,
|
||||
b'keep-alive' if keep_alive else b'close',
|
||||
timeout_header,
|
||||
headers,
|
||||
self.body
|
||||
)
|
||||
|
||||
@@ -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,16 +10,18 @@ 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
|
||||
from .server import serve, serve_multiple, HttpProtocol
|
||||
from .static import register as static_register
|
||||
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
|
||||
@@ -44,11 +46,18 @@ class Sanic:
|
||||
self._blueprint_order = []
|
||||
self.debug = None
|
||||
self.sock = None
|
||||
self.before_start = []
|
||||
self.listeners = defaultdict(list)
|
||||
|
||||
# Register alternative method names
|
||||
self.go_fast = self.run
|
||||
|
||||
@property
|
||||
def loop(self):
|
||||
"""
|
||||
Synonymous with asyncio.get_event_loop()
|
||||
"""
|
||||
return get_event_loop()
|
||||
|
||||
# -------------------------------------------------------------------- #
|
||||
# Registration
|
||||
# -------------------------------------------------------------------- #
|
||||
@@ -62,13 +71,24 @@ class Sanic:
|
||||
|
||||
:param task: A future, couroutine or awaitable.
|
||||
"""
|
||||
@self.listener('before_server_start')
|
||||
def run(app, loop):
|
||||
if callable(task):
|
||||
loop.create_task(task())
|
||||
else:
|
||||
loop.create_task(task)
|
||||
|
||||
self.before_start.append(run)
|
||||
# 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):
|
||||
@@ -130,7 +150,16 @@ class Sanic:
|
||||
"""
|
||||
# Handle HTTPMethodView differently
|
||||
if hasattr(handler, 'view_class'):
|
||||
methods = frozenset(HTTP_METHODS)
|
||||
methods = set()
|
||||
|
||||
for method in HTTP_METHODS:
|
||||
if getattr(handler.view_class, method.lower(), None):
|
||||
methods.add(method)
|
||||
|
||||
# handle composition view differently
|
||||
if isinstance(handler, CompositionView):
|
||||
methods = handler.handlers.keys()
|
||||
|
||||
self.route(uri=uri, methods=methods, host=host)(handler)
|
||||
return handler
|
||||
|
||||
@@ -154,14 +183,12 @@ class Sanic:
|
||||
return response
|
||||
|
||||
# Decorator
|
||||
def middleware(self, *args, **kwargs):
|
||||
def middleware(self, middleware_or_request):
|
||||
"""
|
||||
Decorates and registers middleware to be called before a request
|
||||
can either be called as @app.middleware or @app.middleware('request')
|
||||
"""
|
||||
attach_to = 'request'
|
||||
|
||||
def register_middleware(middleware):
|
||||
def register_middleware(middleware, attach_to='request'):
|
||||
if attach_to == 'request':
|
||||
self.request_middleware.append(middleware)
|
||||
if attach_to == 'response':
|
||||
@@ -169,11 +196,12 @@ class Sanic:
|
||||
return middleware
|
||||
|
||||
# Detect which way this was called, @middleware or @middleware('AT')
|
||||
if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
|
||||
return register_middleware(args[0])
|
||||
if callable(middleware_or_request):
|
||||
return register_middleware(middleware_or_request)
|
||||
|
||||
else:
|
||||
attach_to = args[0]
|
||||
return register_middleware
|
||||
return partial(register_middleware,
|
||||
attach_to=middleware_or_request)
|
||||
|
||||
# Static Files
|
||||
def static(self, uri, file_or_directory, pattern='.+',
|
||||
@@ -414,19 +442,13 @@ class Sanic:
|
||||
:param protocol: Subclass of asyncio protocol class
|
||||
:return: Nothing
|
||||
"""
|
||||
if before_start is not None:
|
||||
if not isinstance(before_start, list):
|
||||
before_start = [before_start]
|
||||
before_start.extend(self.before_start)
|
||||
else:
|
||||
before_start = self.before_start
|
||||
|
||||
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, 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)
|
||||
@@ -481,9 +503,19 @@ 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
|
||||
self.loop = loop = get_event_loop()
|
||||
loop = self.loop
|
||||
|
||||
server_settings = {
|
||||
'protocol': protocol,
|
||||
@@ -505,19 +537,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
|
||||
|
||||
@@ -346,7 +346,11 @@ def serve(host, port, request_handler, error_handler, before_start=None,
|
||||
# Register signals for graceful termination
|
||||
if register_sys_signals:
|
||||
for _signal in (SIGINT, SIGTERM):
|
||||
loop.add_signal_handler(_signal, loop.stop)
|
||||
try:
|
||||
loop.add_signal_handler(_signal, loop.stop)
|
||||
except NotImplementedError:
|
||||
log.warn(('Sanic tried to use loop.add_signal_handler')
|
||||
('but it is not implemented on this platform.'))
|
||||
|
||||
pid = os.getpid()
|
||||
try:
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from .exceptions import InvalidUsage
|
||||
from .constants import HTTP_METHODS
|
||||
|
||||
|
||||
class HTTPMethodView:
|
||||
@@ -40,11 +41,7 @@ class HTTPMethodView:
|
||||
|
||||
def dispatch_request(self, request, *args, **kwargs):
|
||||
handler = getattr(self, request.method.lower(), None)
|
||||
if handler:
|
||||
return handler(request, *args, **kwargs)
|
||||
raise InvalidUsage(
|
||||
'Method {} not allowed for URL {}'.format(
|
||||
request.method, request.url), status_code=405)
|
||||
return handler(request, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def as_view(cls, *class_args, **class_kwargs):
|
||||
@@ -89,15 +86,15 @@ class CompositionView:
|
||||
|
||||
def add(self, methods, handler):
|
||||
for method in methods:
|
||||
if method not in HTTP_METHODS:
|
||||
raise InvalidUsage(
|
||||
'{} is not a valid HTTP method.'.format(method))
|
||||
|
||||
if method in self.handlers:
|
||||
raise KeyError(
|
||||
'Method {} already is registered.'.format(method))
|
||||
raise InvalidUsage(
|
||||
'Method {} is already registered.'.format(method))
|
||||
self.handlers[method] = handler
|
||||
|
||||
def __call__(self, request, *args, **kwargs):
|
||||
handler = self.handlers.get(request.method.upper(), None)
|
||||
if handler is None:
|
||||
raise InvalidUsage(
|
||||
'Method {} not allowed for URL {}'.format(
|
||||
request.method, request.url), status_code=405)
|
||||
handler = self.handlers[request.method.upper()]
|
||||
return handler(request, *args, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user