Merge pull request #5 from channelcat/reformat_code

Reformatted code to use spaces instead of tabs
This commit is contained in:
channelcat 2016-10-14 19:55:03 -07:00 committed by GitHub
commit 385158b84d
21 changed files with 344 additions and 266 deletions

View File

@ -3,8 +3,10 @@ from sanic.response import json
app = Sanic(__name__)
@app.route("/")
async def test(request):
return json({"test": True})
app.run(host="0.0.0.0", port=8000)

View File

@ -5,22 +5,27 @@ from sanic.exceptions import ServerError
app = Sanic(__name__)
@app.route("/")
async def test_async(request):
return json({"test": True})
@app.route("/sync", methods=['GET', 'POST'])
def test_sync(request):
return json({"test": True})
@app.route("/dynamic/<name>/<id:int>")
def test_params(request, name, id):
return text("yeehaww {} {}".format(name, id))
@app.route("/exception")
def exception(request):
raise ServerError("It's dead jim")
# ----------------------------------------------- #
# Exceptions
# ----------------------------------------------- #
@ -29,6 +34,7 @@ def exception(request):
async def test(request, exception):
return json({"exception": "{}".format(exception), "status": exception.status_code}, status=exception.status_code)
# ----------------------------------------------- #
# Read from request
# ----------------------------------------------- #
@ -37,23 +43,27 @@ async def test(request, exception):
def post_json(request):
return json({"received": True, "message": request.json})
@app.route("/form")
def post_json(request):
return json({"received": True, "form_data": request.form, "test": request.form.get('test')})
@app.route("/query_string")
def query_string(request):
return json({"parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string})
# ----------------------------------------------- #
# Run Server
# ----------------------------------------------- #
def after_start(loop):
log.info("OH OH OH OH OHHHHHHHH")
def before_stop(loop):
log.info("TRIED EVERYTHING")
app.run(host="0.0.0.0", port=8000, debug=True, after_start=after_start, before_stop=before_stop)

View File

@ -1,21 +1,29 @@
from .response import text
from traceback import format_exc
class SanicException(Exception):
def __init__(self, message, status_code=None):
super().__init__(message)
if status_code is not None:
self.status_code = status_code
class NotFound(SanicException):
status_code = 404
class InvalidUsage(SanicException):
status_code = 400
class ServerError(SanicException):
status_code = 500
class Handler:
handlers = None
def __init__(self, sanic):
self.handlers = {}
self.sanic = sanic

View File

@ -6,20 +6,25 @@ from ujson import loads as json_loads
from .log import log
class RequestParameters(dict):
"""
Hosts a dict with lists as values where get returns the first
value of the list and getlist returns the whole shebang
"""
def __init__(self, *args, **kwargs):
self.super = super()
self.super.__init__(*args, **kwargs)
def get(self, name, default=None):
values = self.super.get(name)
return values[0] if values else default
def getlist(self, name, default=None):
return self.super.get(name, default)
class Request:
__slots__ = (
'url', 'headers', 'version', 'method',
@ -89,7 +94,10 @@ class Request:
return self.parsed_args
File = namedtuple('File', ['type', 'body', 'name'])
def parse_multipart_form(body, boundary):
"""
Parses a request body and returns fields and files
@ -126,7 +134,6 @@ def parse_multipart_form(body, boundary):
elif form_header_field == 'Content-Type':
file_type = form_header_value
post_data = form_part[line_index:-4]
if file_name or file_type:
files[field_name] = File(type=file_type, name=file_name, body=post_data)

View File

@ -18,6 +18,7 @@ STATUS_CODES = {
504: 'Gateway Timeout',
}
class HTTPResponse:
__slots__ = ('body', 'status', 'content_type', 'headers')
@ -43,7 +44,8 @@ class HTTPResponse:
additional_headers.append('{}: {}\r\n'.format(name, value).encode('utf-8'))
return b''.join([
'HTTP/{} {} {}\r\n'.format(version, self.status, STATUS_CODES.get(self.status, 'FAIL')).encode(),
'HTTP/{} {} {}\r\n'.format(version, self.status,
STATUS_CODES.get(self.status, 'FAIL')).encode(),
b'Content-Type: ', self.content_type.encode(), b'\r\n',
b'Content-Length: ', str(len(self.body)).encode(), b'\r\n',
b'Connection: ', ('keep-alive' if keep_alive else 'close').encode(), b'\r\n',
@ -52,9 +54,15 @@ class HTTPResponse:
self.body,
])
def json(body, status=200, headers=None):
return HTTPResponse(ujson.dumps(body), headers=headers, status=status, content_type="application/json; charset=utf-8")
return HTTPResponse(ujson.dumps(body), headers=headers, status=status,
content_type="application/json; charset=utf-8")
def text(body, status=200, headers=None):
return HTTPResponse(body, status=status, headers=headers, content_type="text/plain; charset=utf-8")
def html(body, status=200, headers=None):
return HTTPResponse(body, status=status, headers=headers, content_type="text/html; charset=utf-8")

View File

@ -5,6 +5,7 @@ from .exceptions import NotFound, InvalidUsage
Route = namedtuple("Route", ['handler', 'methods', 'pattern', 'parameters'])
Parameter = namedtuple("Parameter", ['name', 'cast'])
class Router:
"""
Router supports basic routing with parameters and method checks
@ -45,6 +46,7 @@ class Router:
methods_dict = {method: True for method in methods} if methods else None
parameters = []
def add_parameter(match):
# We could receive NAME or NAME:PATTERN
parts = match.group(1).split(':')
@ -93,11 +95,13 @@ class Router:
if route:
if route.methods and not request.method in route.methods:
raise InvalidUsage("Method {} not allowed for URL {}".format(request.method, request.url), status_code=405)
raise InvalidUsage("Method {} not allowed for URL {}".format(request.method, request.url),
status_code=405)
return route.handler, args, kwargs
else:
raise NotFound("Requested URL {} not found".format(request.url))
class SimpleRouter:
"""
Simple router records and reads all routes from a dictionary
@ -117,7 +121,8 @@ class SimpleRouter:
route = self.routes.get(request.url)
if route:
if route.methods and not request.method in route.methods:
raise InvalidUsage("Method {} not allowed for URL {}".format(request.method, request.url), status_code=405)
raise InvalidUsage("Method {} not allowed for URL {}".format(request.method, request.url),
status_code=405)
return route.handler, [], {}
else:
raise NotFound("Requested URL {} not found".format(request.url))

View File

@ -12,6 +12,7 @@ from .router import Router
from .server import serve
from .exceptions import ServerError
class Sanic:
def __init__(self, name, router=None, error_handler=None):
self.name = name
@ -34,6 +35,7 @@ class Sanic:
:param methods: list or tuple of methods allowed
:return: decorated function
"""
def response(handler):
self.router.add(uri=uri, methods=methods, handler=handler)
return handler
@ -48,6 +50,7 @@ class Sanic:
:param methods: list or tuple of methods allowed
:return: decorated function
"""
def response(handler):
for exception in exceptions:
self.error_handler.add(exception, handler)
@ -63,6 +66,7 @@ class Sanic:
"""
middleware = None
attach_to = 'request'
def register_middleware(middleware):
if attach_to == 'request':
self.request_middleware.append(middleware)

View File

@ -3,6 +3,7 @@ from inspect import isawaitable
from signal import SIGINT, SIGTERM
import httptools
try:
import uvloop as async_loop
except:
@ -11,17 +12,19 @@ except:
from .log import log
from .request import Request
class Signal:
stopped = False
class HttpProtocol(asyncio.Protocol):
class HttpProtocol(asyncio.Protocol):
__slots__ = ('loop', 'transport', 'connections', 'signal', # event loop, connection
'parser', 'request', 'url', 'headers', # request params
'request_handler', 'request_timeout', 'request_max_size', # request config
'_total_request_size', '_timeout_handler') # connection management
def __init__(self, *, loop, request_handler, signal=Signal(), connections={}, request_timeout=60, request_max_size=None):
def __init__(self, *, loop, request_handler, signal=Signal(), connections={}, request_timeout=60,
request_max_size=None):
self.loop = loop
self.transport = None
self.request = None
@ -37,6 +40,7 @@ class HttpProtocol(asyncio.Protocol):
self._timeout_handler = None
# -------------------------------------------- #
# Connection
# -------------------------------------------- #
@ -54,6 +58,7 @@ class HttpProtocol(asyncio.Protocol):
self.bail_out("Request timed out, connection closed")
# -------------------------------------------- #
# Parsing
# -------------------------------------------- #
@ -94,6 +99,7 @@ class HttpProtocol(asyncio.Protocol):
def on_body(self, body):
self.request.body = body
def on_message_complete(self):
self.loop.create_task(self.request_handler(self.request, self.write_response))
@ -133,7 +139,9 @@ class HttpProtocol(asyncio.Protocol):
return True
return False
def serve(host, port, request_handler, after_start=None, before_stop=None, debug=False, request_timeout=60, request_max_size=None):
def serve(host, port, request_handler, after_start=None, before_stop=None, debug=False, request_timeout=60,
request_max_size=None):
# Create Event Loop
loop = async_loop.new_event_loop()
asyncio.set_event_loop(loop)

View File

@ -10,8 +10,10 @@ from sanic.response import json
app = Sanic("test")
@app.route("/")
async def test(request):
return json({"test": True})
app.run(host="0.0.0.0", port=sys.argv[1])

View File

@ -11,10 +11,12 @@ from sanic.exceptions import ServerError
app = Sanic("test")
@app.route("/")
async def test(request):
return json({"test": True})
@app.route("/sync", methods=['GET', 'POST'])
def test(request):
return json({"test": True})
@ -24,23 +26,29 @@ def test(request):
def rtext(request, name, butt):
return text("yeehaww {} {}".format(name, butt))
@app.route("/exception")
def exception(request):
raise ServerError("yep")
@app.route("/exception/async")
async def test(request):
raise ServerError("asunk")
@app.route("/post_json")
def post_json(request):
return json({"received": True, "message": request.json})
@app.route("/query_string")
def query_string(request):
return json({"parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string})
import sys
app.run(host="0.0.0.0", port=sys.argv[1])

View File

@ -49,5 +49,3 @@ def test_invalid_usage_exception():
def test_not_found_exception():
request, response = sanic_endpoint_test(exception_app, uri='/404')
assert response.status == 404

View File

@ -4,6 +4,7 @@ from sanic.request import Request
from sanic.response import json, text, HTTPResponse
from sanic.utils import sanic_endpoint_test
# ------------------------------------------------------------ #
# GET
# ------------------------------------------------------------ #
@ -12,6 +13,7 @@ def test_middleware_request():
app = Sanic('test_middleware_request')
results = []
@app.middleware
async def handler(request):
results.append(request)
@ -25,13 +27,16 @@ def test_middleware_request():
assert response.text == 'OK'
assert type(results[0]) is Request
def test_middleware_response():
app = Sanic('test_middleware_response')
results = []
@app.middleware('request')
async def process_response(request):
results.append(request)
@app.middleware('response')
async def process_response(request, response):
results.append(request)
@ -48,6 +53,7 @@ def test_middleware_response():
assert type(results[1]) is Request
assert issubclass(type(results[2]), HTTPResponse)
def test_middleware_override_request():
app = Sanic('test_middleware_override_request')
@ -64,6 +70,7 @@ def test_middleware_override_request():
assert response.status == 200
assert response.text == 'OK'
def test_middleware_override_response():
app = Sanic('test_middleware_override_response')

View File

@ -3,6 +3,7 @@ from sanic import Sanic
from sanic.response import json, text
from sanic.utils import sanic_endpoint_test
# ------------------------------------------------------------ #
# GET
# ------------------------------------------------------------ #
@ -18,6 +19,7 @@ def test_sync():
assert response.text == 'Hello'
def test_text():
app = Sanic('test_text')
@ -59,6 +61,7 @@ def test_query_string():
assert request.args.get('test1') == '1'
assert request.args.get('test2') == 'false'
# ------------------------------------------------------------ #
# POST
# ------------------------------------------------------------ #

View File

@ -3,6 +3,7 @@ from sanic import Sanic
from sanic.response import json, text
from sanic.utils import sanic_endpoint_test
# ------------------------------------------------------------ #
# UTF-8
# ------------------------------------------------------------ #
@ -22,6 +23,7 @@ def test_dynamic_route():
assert response.text == 'OK'
assert results[0] == 'test123'
def test_dynamic_route_string():
app = Sanic('test_dynamic_route_string')
@ -37,6 +39,7 @@ def test_dynamic_route_string():
assert response.text == 'OK'
assert results[0] == 'test123'
def test_dynamic_route_int():
app = Sanic('test_dynamic_route_int')
@ -75,6 +78,7 @@ def test_dynamic_route_number():
request, response = sanic_endpoint_test(app, uri='/weight/1234-56')
assert response.status == 404
def test_dynamic_route_regex():
app = Sanic('test_dynamic_route_int')

View File

@ -3,6 +3,7 @@ from sanic import Sanic
from sanic.response import json, text
from sanic.utils import sanic_endpoint_test
# ------------------------------------------------------------ #
# UTF-8
# ------------------------------------------------------------ #
@ -17,6 +18,7 @@ def test_utf8_query_string():
request, response = sanic_endpoint_test(app, params=[("utf8", '')])
assert request.args.get('utf8') == ''
def test_utf8_response():
app = Sanic('test_utf8_response')
@ -27,6 +29,7 @@ def test_utf8_response():
request, response = sanic_endpoint_test(app)
assert response.text == ''
def skip_test_utf8_route():
app = Sanic('skip_test_utf8_route')
@ -38,6 +41,7 @@ def skip_test_utf8_route():
request, response = sanic_endpoint_test(app, route='/✓', uri='/✓')
assert response.text == 'OK'
def test_utf8_post_json():
app = Sanic('test_utf8_post_json')