Recovery the issue 659

This commit is contained in:
lizheao 2017-04-27 17:50:04 +08:00
parent 472face796
commit 240f5b7c9f
3 changed files with 48 additions and 8 deletions

View File

@ -1,6 +1,8 @@
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from types import MethodType
from sanic.constants import HTTP_METHODS from sanic.constants import HTTP_METHODS
from sanic.exceptions import SanicTypeException
from sanic.views import CompositionView from sanic.views import CompositionView
FutureRoute = namedtuple('Route', FutureRoute = namedtuple('Route',
@ -48,7 +50,7 @@ class Blueprint:
methods=future.methods, methods=future.methods,
host=future.host or self.host, host=future.host or self.host,
strict_slashes=future.strict_slashes strict_slashes=future.strict_slashes
)(future.handler) )(future.handler)
for future in self.websocket_routes: for future in self.websocket_routes:
# attach the blueprint name to the handler so that it can be # attach the blueprint name to the handler so that it can be
@ -60,7 +62,7 @@ class Blueprint:
uri=uri, uri=uri,
host=future.host or self.host, host=future.host or self.host,
strict_slashes=future.strict_slashes strict_slashes=future.strict_slashes
)(future.handler) )(future.handler)
# Middleware # Middleware
for future in self.middlewares: for future in self.middlewares:
@ -93,10 +95,14 @@ class Blueprint:
:param uri: endpoint at which the route will be accessible. :param uri: endpoint at which the route will be accessible.
:param methods: list of acceptable HTTP methods. :param methods: list of acceptable HTTP methods.
""" """
def decorator(handler): def decorator(handler):
if isinstance(handler, MethodType):
raise SanicTypeException("You can`t add a instance method as a blueprint router hander")
route = FutureRoute(handler, uri, methods, host, strict_slashes) route = FutureRoute(handler, uri, methods, host, strict_slashes)
self.routes.append(route) self.routes.append(route)
return handler return handler
return decorator return decorator
def add_route(self, handler, uri, methods=frozenset({'GET'}), host=None, def add_route(self, handler, uri, methods=frozenset({'GET'}), host=None,
@ -120,6 +126,8 @@ class Blueprint:
# handle composition view differently # handle composition view differently
if isinstance(handler, CompositionView): if isinstance(handler, CompositionView):
methods = handler.handlers.keys() methods = handler.handlers.keys()
if isinstance(handler, MethodType):
raise SanicTypeException("You can`t add a instance method as a blueprint router hander")
self.route(uri=uri, methods=methods, host=host, self.route(uri=uri, methods=methods, host=host,
strict_slashes=strict_slashes)(handler) strict_slashes=strict_slashes)(handler)
@ -130,10 +138,12 @@ class Blueprint:
:param uri: endpoint at which the route will be accessible. :param uri: endpoint at which the route will be accessible.
""" """
def decorator(handler): def decorator(handler):
route = FutureRoute(handler, uri, [], host, strict_slashes) route = FutureRoute(handler, uri, [], host, strict_slashes)
self.websocket_routes.append(route) self.websocket_routes.append(route)
return handler return handler
return decorator return decorator
def add_websocket_route(self, handler, uri, host=None): def add_websocket_route(self, handler, uri, host=None):
@ -152,13 +162,16 @@ class Blueprint:
:param event: Event to listen to. :param event: Event to listen to.
""" """
def decorator(listener): def decorator(listener):
self.listeners[event].append(listener) self.listeners[event].append(listener)
return listener return listener
return decorator return decorator
def middleware(self, *args, **kwargs): def middleware(self, *args, **kwargs):
"""Create a blueprint middleware from a decorated function.""" """Create a blueprint middleware from a decorated function."""
def register_middleware(_middleware): def register_middleware(_middleware):
future_middleware = FutureMiddleware(_middleware, args, kwargs) future_middleware = FutureMiddleware(_middleware, args, kwargs)
self.middlewares.append(future_middleware) self.middlewares.append(future_middleware)
@ -174,10 +187,12 @@ class Blueprint:
def exception(self, *args, **kwargs): def exception(self, *args, **kwargs):
"""Create a blueprint exception from a decorated function.""" """Create a blueprint exception from a decorated function."""
def decorator(handler): def decorator(handler):
exception = FutureException(handler, args, kwargs) exception = FutureException(handler, args, kwargs)
self.exceptions.append(exception) self.exceptions.append(exception)
return handler return handler
return decorator return decorator
def static(self, uri, file_or_directory, *args, **kwargs): def static(self, uri, file_or_directory, *args, **kwargs):

View File

@ -97,7 +97,6 @@ INTERNAL_SERVER_ERROR_HTML = '''
class SanicException(Exception): class SanicException(Exception):
def __init__(self, message, status_code=None): def __init__(self, message, status_code=None):
super().__init__(message) super().__init__(message)
@ -105,6 +104,10 @@ class SanicException(Exception):
self.status_code = status_code self.status_code = status_code
class SanicTypeException(Exception):
pass
class NotFound(SanicException): class NotFound(SanicException):
status_code = 404 status_code = 404

View File

@ -1,10 +1,12 @@
import asyncio import asyncio
import inspect import inspect
from sanic import Sanic import pytest
from sanic import Sanic, response
from sanic.blueprints import Blueprint from sanic.blueprints import Blueprint
from sanic.response import json, text from sanic.exceptions import NotFound, ServerError, InvalidUsage, SanicTypeException
from sanic.exceptions import NotFound, ServerError, InvalidUsage from sanic.response import text
# ------------------------------------------------------------ # # ------------------------------------------------------------ #
@ -134,7 +136,6 @@ def test_several_bp_with_host():
def handler2(request): def handler2(request):
return text('Hello3') return text('Hello3')
app.blueprint(bp) app.blueprint(bp)
app.blueprint(bp2) app.blueprint(bp2)
@ -201,7 +202,6 @@ def test_bp_exception_handler():
request, response = app.test_client.get('/1') request, response = app.test_client.get('/1')
assert response.status == 400 assert response.status == 400
request, response = app.test_client.get('/2') request, response = app.test_client.get('/2')
assert response.status == 200 assert response.status == 200
assert response.text == 'OK' assert response.text == 'OK'
@ -349,3 +349,25 @@ def test_bp_shorthand():
'Sec-WebSocket-Version': '13'}) 'Sec-WebSocket-Version': '13'})
assert response.status == 101 assert response.status == 101
assert ev.is_set() assert ev.is_set()
def test_blueprint_handler_type_error():
class Manage(object):
def __init__(self):
self.blueprint = Blueprint(str(type(self).__name__))
self.blueprint.add_route(self.info, '/info')
async def info(self, request):
return response.json({'id': id(self)})
def register(self, app: Sanic):
app.blueprint(self.blueprint)
def myfunc():
app = Sanic()
manager = Manage()
manager.register(app)
with pytest.raises(SanicTypeException) as execinfo:
myfunc()
execinfo.match(r'.*?instance method.*?')