From ee27c689e12e1074cbd7ae235f0b0c076130422a Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 23 Mar 2017 20:06:39 +0800 Subject: [PATCH 01/21] commented aiohttp load response body in testing --- sanic/testing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sanic/testing.py b/sanic/testing.py index 4fde428c..611f709d 100644 --- a/sanic/testing.py +++ b/sanic/testing.py @@ -22,8 +22,8 @@ class SanicTestClient: cookies=cookies, connector=conn) as session: async with getattr( session, method.lower())(url, *args, **kwargs) as response: - response.text = await response.text() - response.body = await response.read() + # response.text = await response.text() + # response.body = await response.read() return response def _sanic_endpoint_test( From 1562b81522d827539545a28e592aed1966ce0099 Mon Sep 17 00:00:00 2001 From: ivan Date: Thu, 23 Mar 2017 20:48:57 +0800 Subject: [PATCH 02/21] add arg load_body in testing --- sanic/testing.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sanic/testing.py b/sanic/testing.py index 611f709d..d7e73e56 100644 --- a/sanic/testing.py +++ b/sanic/testing.py @@ -20,10 +20,12 @@ class SanicTestClient: conn = aiohttp.TCPConnector(verify_ssl=False) async with aiohttp.ClientSession( cookies=cookies, connector=conn) as session: + load_body = 'load_body' not in kwargs or kwargs.pop('load_body') async with getattr( session, method.lower())(url, *args, **kwargs) as response: - # response.text = await response.text() - # response.body = await response.read() + if load_body: + response.text = await response.text() + response.body = await response.read() return response def _sanic_endpoint_test( From 833b14e3531e2c7a61634652607621ea24b918ad Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Thu, 6 Apr 2017 13:33:29 -0400 Subject: [PATCH 03/21] Updated aiohttp example. --- examples/aiohttp_example.py | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/aiohttp_example.py b/examples/aiohttp_example.py index a8fb20f0..0762f5d4 100644 --- a/examples/aiohttp_example.py +++ b/examples/aiohttp_example.py @@ -1,28 +1,26 @@ from sanic import Sanic -from sanic.response import json +from sanic import response import aiohttp -app = Sanic(__name__) +app = Sanic() async def fetch(session, url): """ Use session object to perform 'get' request on url """ - async with session.get(url) as response: - return await response.json() + async with session.get(url) as result: + return await result.text() -@app.route("/") -async def test(request): - """ - Download and serve example JSON - """ +@app.route('/') +async def handle_request(request): url = "https://api.github.com/repos/channelcat/sanic" - + async with aiohttp.ClientSession() as session: - response = await fetch(session, url) - return json(response) + result = await fetch(session, url) + return response.json(result) -app.run(host="0.0.0.0", port=8000, workers=2) +if __name__ == '__main__': + app.run(host="0.0.0.0", port=8000, workers=2) From 46ac79f4dcd62fcbcb39a689e48f9f3ef947d6d9 Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Thu, 6 Apr 2017 14:39:54 -0400 Subject: [PATCH 04/21] Update run_async demo --- examples/run_async.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/run_async.py b/examples/run_async.py index d514c7d0..1fb232c3 100644 --- a/examples/run_async.py +++ b/examples/run_async.py @@ -1,5 +1,5 @@ from sanic import Sanic -from sanic.response import json +from sanic import response from multiprocessing import Event from signal import signal, SIGINT import asyncio @@ -9,10 +9,10 @@ app = Sanic(__name__) @app.route("/") async def test(request): - return json({"answer": "42"}) + return response.json({"answer": "42"}) asyncio.set_event_loop(uvloop.new_event_loop()) -server = app.create_server(host="0.0.0.0", port=8001) +server = app.create_server(host="0.0.0.0", port=8080) loop = asyncio.get_event_loop() task = asyncio.ensure_future(server) signal(SIGINT, lambda s, f: loop.stop()) From c30437448bf5e35924bec7401cba5634720047ae Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Thu, 6 Apr 2017 19:42:05 +0000 Subject: [PATCH 05/21] Updated aiohttp & run_async examples, added redirect --- examples/aiohttp_example.py | 2 +- examples/redirect_example.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 examples/redirect_example.py diff --git a/examples/aiohttp_example.py b/examples/aiohttp_example.py index 0762f5d4..f8043d5c 100644 --- a/examples/aiohttp_example.py +++ b/examples/aiohttp_example.py @@ -3,7 +3,7 @@ from sanic import response import aiohttp -app = Sanic() +app = Sanic(__name__) async def fetch(session, url): """ diff --git a/examples/redirect_example.py b/examples/redirect_example.py new file mode 100644 index 00000000..c062a76f --- /dev/null +++ b/examples/redirect_example.py @@ -0,0 +1,17 @@ +from sanic import Sanic +from sanic import response + +app = Sanic(__name__) + + +@app.route('/') +def handle_request(request): + return response.redirect('/redirect') + +@app.route('/redirect') +async def test(request): + return response.json({"Redirected": True}) + + +if __name__ == '__main__': + app.run(host="0.0.0.0", port=8080) \ No newline at end of file From 9d3bb4a37ad2edcededc9c79108d1c5892de3f9a Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Thu, 6 Apr 2017 19:47:25 +0000 Subject: [PATCH 06/21] Updated examples in-line with response docs --- examples/aiohttp_example.py | 2 +- examples/redirect_example.py | 2 +- examples/run_async.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/aiohttp_example.py b/examples/aiohttp_example.py index f8043d5c..853ea959 100644 --- a/examples/aiohttp_example.py +++ b/examples/aiohttp_example.py @@ -10,7 +10,7 @@ async def fetch(session, url): Use session object to perform 'get' request on url """ async with session.get(url) as result: - return await result.text() + return await result.json() @app.route('/') diff --git a/examples/redirect_example.py b/examples/redirect_example.py index c062a76f..acc7d1ff 100644 --- a/examples/redirect_example.py +++ b/examples/redirect_example.py @@ -14,4 +14,4 @@ async def test(request): if __name__ == '__main__': - app.run(host="0.0.0.0", port=8080) \ No newline at end of file + app.run(host="0.0.0.0", port=8000) \ No newline at end of file diff --git a/examples/run_async.py b/examples/run_async.py index 1fb232c3..b6f6d76d 100644 --- a/examples/run_async.py +++ b/examples/run_async.py @@ -12,7 +12,7 @@ async def test(request): return response.json({"answer": "42"}) asyncio.set_event_loop(uvloop.new_event_loop()) -server = app.create_server(host="0.0.0.0", port=8080) +server = app.create_server(host="0.0.0.0", port=8000) loop = asyncio.get_event_loop() task = asyncio.ensure_future(server) signal(SIGINT, lambda s, f: loop.stop()) From 2ef8120073d97aef30da51d65e08e1f0069fe21b Mon Sep 17 00:00:00 2001 From: aryeh Date: Sun, 9 Apr 2017 13:29:21 -0400 Subject: [PATCH 07/21] Allow a custom Request class to be passed in to Sonic Allowing a custom Request class to be defined would enable either a different Request class or a subclass of Request to be used, providing more flexibility. --- sanic/app.py | 4 +++- sanic/server.py | 11 +++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sanic/app.py b/sanic/app.py index ad4d7923..d2894ff2 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -26,7 +26,7 @@ from sanic.websocket import WebSocketProtocol, ConnectionClosed class Sanic: def __init__(self, name=None, router=None, error_handler=None, - load_env=True): + load_env=True, request_class=None): # Only set up a default log handler if the # end-user application didn't set anything up. if not logging.root.handlers and log.level == logging.NOTSET: @@ -44,6 +44,7 @@ class Sanic: self.name = name self.router = router or Router() + self.request_class = request_class self.error_handler = error_handler or ErrorHandler() self.config = Config(load_env=load_env) self.request_middleware = deque() @@ -668,6 +669,7 @@ class Sanic: server_settings = { 'protocol': protocol, + 'request_class': self.request_class, 'host': host, 'port': port, 'sock': sock, diff --git a/sanic/server.py b/sanic/server.py index 976503a6..04dffefd 100644 --- a/sanic/server.py +++ b/sanic/server.py @@ -63,13 +63,13 @@ class HttpProtocol(asyncio.Protocol): # request params 'parser', 'request', 'url', 'headers', # request config - 'request_handler', 'request_timeout', 'request_max_size', + 'request_handler', 'request_timeout', 'request_max_size', 'request_class', # connection management '_total_request_size', '_timeout_handler', '_last_communication_time') def __init__(self, *, loop, request_handler, error_handler, signal=Signal(), connections=set(), request_timeout=60, - request_max_size=None): + request_max_size=None, request_class=None): self.loop = loop self.transport = None self.request = None @@ -82,6 +82,7 @@ class HttpProtocol(asyncio.Protocol): self.error_handler = error_handler self.request_timeout = request_timeout self.request_max_size = request_max_size + self.request_class = request_class or Request self._total_request_size = 0 self._timeout_handler = None self._last_request_time = None @@ -151,7 +152,7 @@ class HttpProtocol(asyncio.Protocol): self.headers.append((name.decode().casefold(), value.decode())) def on_headers_complete(self): - self.request = Request( + self.request = self.request_class( url_bytes=self.url, headers=CIDict(self.headers), version=self.parser.get_http_version(), @@ -320,7 +321,7 @@ def serve(host, port, request_handler, error_handler, before_start=None, request_timeout=60, ssl=None, sock=None, request_max_size=None, reuse_port=False, loop=None, protocol=HttpProtocol, backlog=100, register_sys_signals=True, run_async=False, connections=None, - signal=Signal()): + signal=Signal(), request_class=None): """Start asynchronous HTTP Server on an individual process. :param host: Address to host on @@ -345,6 +346,7 @@ def serve(host, port, request_handler, error_handler, before_start=None, :param reuse_port: `True` for multiple workers :param loop: asyncio compatible event loop :param protocol: subclass of asyncio protocol class + :param request_class: Request class to use :return: Nothing """ if not run_async: @@ -366,6 +368,7 @@ def serve(host, port, request_handler, error_handler, before_start=None, error_handler=error_handler, request_timeout=request_timeout, request_max_size=request_max_size, + request_class=request_class, ) server_coroutine = loop.create_server( From b9dfec38c2c77fd98ce6dffb909de85b4c423514 Mon Sep 17 00:00:00 2001 From: aryeh Date: Sun, 9 Apr 2017 13:38:36 -0400 Subject: [PATCH 08/21] Break long line (> 80 chars) into 2 lines --- sanic/server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sanic/server.py b/sanic/server.py index 04dffefd..7868836c 100644 --- a/sanic/server.py +++ b/sanic/server.py @@ -63,7 +63,8 @@ class HttpProtocol(asyncio.Protocol): # request params 'parser', 'request', 'url', 'headers', # request config - 'request_handler', 'request_timeout', 'request_max_size', 'request_class', + 'request_handler', 'request_timeout', 'request_max_size', + 'request_class', # connection management '_total_request_size', '_timeout_handler', '_last_communication_time') From 09885534c686d490733f9cc6c59f4a66859bc32d Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 10 Apr 2017 18:31:28 +0800 Subject: [PATCH 09/21] fixed #615 --- sanic/response.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/response.py b/sanic/response.py index 4eecaf79..bebb8071 100644 --- a/sanic/response.py +++ b/sanic/response.py @@ -129,7 +129,7 @@ class StreamingHTTPResponse(BaseHTTPResponse): data = self._encode_body(data) self.transport.write( - b"%b\r\n%b\r\n" % (str(len(data)).encode(), data)) + b"%x\r\n%b\r\n" % (len(data), data)) async def stream( self, version="1.1", keep_alive=False, keep_alive_timeout=None): From 084f0d27a3dbb5b93f0e544b9f0c762fba31acc3 Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Tue, 11 Apr 2017 15:19:00 -0500 Subject: [PATCH 10/21] Increment to 0.5.0 --- sanic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/__init__.py b/sanic/__init__.py index b67a3a6a..7bf0994a 100644 --- a/sanic/__init__.py +++ b/sanic/__init__.py @@ -1,6 +1,6 @@ from sanic.app import Sanic from sanic.blueprints import Blueprint -__version__ = '0.4.1' +__version__ = '0.5.0' __all__ = ['Sanic', 'Blueprint'] From adb73316709748ad812dfd2312edee8195b7fa30 Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Tue, 11 Apr 2017 20:34:55 +0000 Subject: [PATCH 11/21] Updated examples for 0.5.0 --- examples/exception_monitoring.py | 8 +++----- examples/jinja_example.py | 6 +++--- examples/modify_header_example.py | 26 ++++++++++++++++++++++++++ examples/override_logging.py | 5 ++--- examples/request_timeout.py | 10 +++++----- examples/simple_server.py | 4 ++-- examples/try_everything.py | 20 ++++++++++---------- examples/vhosts.py | 14 +++++++------- 8 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 examples/modify_header_example.py diff --git a/examples/exception_monitoring.py b/examples/exception_monitoring.py index 37d5c89d..76d16d90 100644 --- a/examples/exception_monitoring.py +++ b/examples/exception_monitoring.py @@ -1,9 +1,7 @@ """ Example intercepting uncaught exceptions using Sanic's error handler framework. - This may be useful for developers wishing to use Sentry, Airbrake, etc. or a custom system to log and monitor unexpected errors in production. - First we create our own class inheriting from Handler in sanic.exceptions, and pass in an instance of it when we create our Sanic instance. Inside this class' default handler, we can do anything including sending exceptions to @@ -39,7 +37,7 @@ server's error_handler to an instance of our CustomHandler """ from sanic import Sanic -from sanic.response import json +from sanic import response app = Sanic(__name__) @@ -52,7 +50,7 @@ async def test(request): # Here, something occurs which causes an unexpected exception # This exception will flow to our custom handler. 1 / 0 - return json({"test": True}) + return response.json({"test": True}) -app.run(host="0.0.0.0", port=8000, debug=True) +app.run(host="0.0.0.0", port=8000, debug=True) \ No newline at end of file diff --git a/examples/jinja_example.py b/examples/jinja_example.py index 1f9bb1ba..ba8b3354 100644 --- a/examples/jinja_example.py +++ b/examples/jinja_example.py @@ -2,7 +2,7 @@ # curl -d '{"name": "John Doe"}' localhost:8000 from sanic import Sanic -from sanic.response import html +from sanic import response from jinja2 import Template template = Template('Hello {{ name }}!') @@ -12,7 +12,7 @@ app = Sanic(__name__) @app.route('/') async def test(request): data = request.json - return html(template.render(**data)) + return response.html(template.render(**data)) -app.run(host="0.0.0.0", port=8000) +app.run(host="0.0.0.0", port=8080, debug=True) \ No newline at end of file diff --git a/examples/modify_header_example.py b/examples/modify_header_example.py new file mode 100644 index 00000000..bb5efe8e --- /dev/null +++ b/examples/modify_header_example.py @@ -0,0 +1,26 @@ +""" +Modify header or status in response +""" + +from sanic import Sanic +from sanic import response + +app = Sanic(__name__) + +@app.route('/') +def handle_request(request): + return response.json( + {'message': 'Hello world!'}, + headers={'X-Served-By': 'sanic'}, + status=200 + ) + +@app.route('/unauthorized') +def handle_request(request): + return response.json( + {'message': 'You are not authorized'}, + headers={'X-Served-By': 'sanic'}, + status=404 + ) + +app.run(host="0.0.0.0", port=8000, debug=True) diff --git a/examples/override_logging.py b/examples/override_logging.py index 117d63bf..e4d529e8 100644 --- a/examples/override_logging.py +++ b/examples/override_logging.py @@ -1,6 +1,5 @@ from sanic import Sanic -from sanic.response import text -import json +from sanic import response import logging logging_format = "[%(asctime)s] %(process)d-%(levelname)s " @@ -18,6 +17,6 @@ sanic = Sanic() @sanic.route("/") def test(request): log.info("received request; responding with 'hey'") - return text("hey") + return response.text("hey") sanic.run(host="0.0.0.0", port=8000) diff --git a/examples/request_timeout.py b/examples/request_timeout.py index 261f423a..fb2822ee 100644 --- a/examples/request_timeout.py +++ b/examples/request_timeout.py @@ -1,6 +1,6 @@ -from sanic import Sanic import asyncio -from sanic.response import text +from sanic import Sanic +from sanic import response from sanic.config import Config from sanic.exceptions import RequestTimeout @@ -11,11 +11,11 @@ app = Sanic(__name__) @app.route('/') async def test(request): await asyncio.sleep(3) - return text('Hello, world!') + return response.text('Hello, world!') @app.exception(RequestTimeout) def timeout(request, exception): - return text('RequestTimeout from error_handler.', 408) + return response.text('RequestTimeout from error_handler.', 408) -app.run(host='0.0.0.0', port=8000) +app.run(host='0.0.0.0', port=8000) \ No newline at end of file diff --git a/examples/simple_server.py b/examples/simple_server.py index a803feb8..948090c4 100644 --- a/examples/simple_server.py +++ b/examples/simple_server.py @@ -1,12 +1,12 @@ from sanic import Sanic -from sanic.response import json +from sanic import response app = Sanic(__name__) @app.route("/") async def test(request): - return json({"test": True}) + return response.json({"test": True}) if __name__ == '__main__': diff --git a/examples/try_everything.py b/examples/try_everything.py index da3cc515..d46b832e 100644 --- a/examples/try_everything.py +++ b/examples/try_everything.py @@ -2,7 +2,7 @@ import os from sanic import Sanic from sanic.log import log -from sanic.response import json, text, file +from sanic import response from sanic.exceptions import ServerError app = Sanic(__name__) @@ -10,17 +10,17 @@ app = Sanic(__name__) @app.route("/") async def test_async(request): - return json({"test": True}) + return response.json({"test": True}) @app.route("/sync", methods=['GET', 'POST']) def test_sync(request): - return json({"test": True}) + return response.json({"test": True}) @app.route("/dynamic//") def test_params(request, name, id): - return text("yeehaww {} {}".format(name, id)) + return response.text("yeehaww {} {}".format(name, id)) @app.route("/exception") @@ -31,11 +31,11 @@ def exception(request): async def test_await(request): import asyncio await asyncio.sleep(5) - return text("I'm feeling sleepy") + return response.text("I'm feeling sleepy") @app.route("/file") async def test_file(request): - return await file(os.path.abspath("setup.py")) + return await response.file(os.path.abspath("setup.py")) # ----------------------------------------------- # @@ -44,7 +44,7 @@ async def test_file(request): @app.exception(ServerError) async def test(request, exception): - return json({"exception": "{}".format(exception), "status": exception.status_code}, status=exception.status_code) + return response.json({"exception": "{}".format(exception), "status": exception.status_code}, status=exception.status_code) # ----------------------------------------------- # @@ -53,17 +53,17 @@ async def test(request, exception): @app.route("/json") def post_json(request): - return json({"received": True, "message": request.json}) + return response.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')}) + return response.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}) + return response.json({"parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string}) # ----------------------------------------------- # diff --git a/examples/vhosts.py b/examples/vhosts.py index 810dc513..50c9b6f6 100644 --- a/examples/vhosts.py +++ b/examples/vhosts.py @@ -1,4 +1,4 @@ -from sanic.response import text +from sanic import response from sanic import Sanic from sanic.blueprints import Blueprint @@ -15,25 +15,25 @@ bp = Blueprint("bp", host="bp.example.com") "somethingelse.com", "therestofyourdomains.com"]) async def hello(request): - return text("Some defaults") + return response.text("Some defaults") @app.route('/', host="example.com") async def hello(request): - return text("Answer") + return response.text("Answer") @app.route('/', host="sub.example.com") async def hello(request): - return text("42") + return response.text("42") @bp.route("/question") async def hello(request): - return text("What is the meaning of life?") + return response.text("What is the meaning of life?") @bp.route("/answer") async def hello(request): - return text("42") + return response.text("42") app.register_blueprint(bp) if __name__ == '__main__': - app.run(host="0.0.0.0", port=8000) + app.run(host="0.0.0.0", port=8000) \ No newline at end of file From d20a49e5006a0ee3c6e64a11feb253fadcd840df Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Tue, 11 Apr 2017 16:02:49 -0500 Subject: [PATCH 12/21] Lock chardet for now... --- requirements-dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-dev.txt b/requirements-dev.txt index 28014eb6..163df025 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,6 @@ aiofiles aiohttp==1.3.5 +chardet<=2.3.0 beautifulsoup4 coverage httptools From 015c87b5e1c3023a3fea229d235273093b17496d Mon Sep 17 00:00:00 2001 From: Eli Uriegas Date: Tue, 11 Apr 2017 16:02:57 -0500 Subject: [PATCH 13/21] Add traceback for better debugging --- sanic/testing.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sanic/testing.py b/sanic/testing.py index 1cad6a7b..787106a6 100644 --- a/sanic/testing.py +++ b/sanic/testing.py @@ -1,3 +1,5 @@ +import traceback + from sanic.log import log HOST = '127.0.0.1' @@ -50,6 +52,8 @@ class SanicTestClient: **request_kwargs) results[-1] = response except Exception as e: + log.error( + 'Exception:\n{}'.format(traceback.format_exc())) exceptions.append(e) self.app.stop() From 3c45c9170fc3b6a8be89e3f47047e1d9038fbc01 Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Tue, 11 Apr 2017 21:55:45 +0000 Subject: [PATCH 14/21] Fixed to merge with #626 --- examples/sanic_motor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/sanic_motor.py b/examples/sanic_motor.py index 495875a4..c7d2b60f 100644 --- a/examples/sanic_motor.py +++ b/examples/sanic_motor.py @@ -5,7 +5,7 @@ motor==1.1 sanic==0.2.0 """ from sanic import Sanic -from sanic.response import json +from sanic import response app = Sanic('motor_mongodb') @@ -25,7 +25,7 @@ async def get(request): for doc in docs: doc['id'] = str(doc['_id']) del doc['_id'] - return json(docs) + return response.json(docs) @app.route('/post', methods=['POST']) @@ -34,8 +34,8 @@ async def new(request): print(doc) db = get_db() object_id = await db.test_col.save(doc) - return json({'object_id': str(object_id)}) + return response.json({'object_id': str(object_id)}) if __name__ == "__main__": - app.run(host='127.0.0.1', port=8000) + app.run(host='0.0.0.0', port=8000, debug=True) From 0f10a36b4046f544869aa24d722336c00324fcde Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Wed, 12 Apr 2017 06:20:35 +0000 Subject: [PATCH 15/21] Added url_for example --- examples/url_for_example.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 examples/url_for_example.py diff --git a/examples/url_for_example.py b/examples/url_for_example.py new file mode 100644 index 00000000..c26debf4 --- /dev/null +++ b/examples/url_for_example.py @@ -0,0 +1,18 @@ +from sanic import Sanic +from sanic import response + +app = Sanic(__name__) + +@app.route('/') +async def index(request): + # generate a URL for the endpoint `post_handler` + url = app.url_for('post_handler', post_id=5) + # the URL is `/posts/5`, redirect to it + return response.redirect(url) + +@app.route('/posts/') +async def post_handler(request, post_id): + return response.text('Post - {}'.format(post_id)) + +if __name__ == '__main__': + app.run(host="0.0.0.0", port=8000, debug=True) \ No newline at end of file From 7fe418d1b7c0d6fd03104f8a641da5c08a114da6 Mon Sep 17 00:00:00 2001 From: 38elements Date: Wed, 12 Apr 2017 17:55:22 +0900 Subject: [PATCH 16/21] Refactor keep_alive --- sanic/server.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sanic/server.py b/sanic/server.py index 7868836c..40c3ee69 100644 --- a/sanic/server.py +++ b/sanic/server.py @@ -89,6 +89,10 @@ class HttpProtocol(asyncio.Protocol): self._last_request_time = None self._request_handler_task = None + @property + def keep_alive(self): + return self.parser.should_keep_alive() and not self.signal.stopped + # -------------------------------------------- # # Connection # -------------------------------------------- # @@ -182,9 +186,7 @@ class HttpProtocol(asyncio.Protocol): Writes response content synchronously to the transport. """ try: - keep_alive = ( - self.parser.should_keep_alive() and not self.signal.stopped) - + keep_alive = self.keep_alive self.transport.write( response.output( self.request.version, keep_alive, @@ -218,9 +220,7 @@ class HttpProtocol(asyncio.Protocol): """ try: - keep_alive = ( - self.parser.should_keep_alive() and not self.signal.stopped) - + keep_alive = self.keep_alive response.transport = self.transport await response.stream( self.request.version, keep_alive, self.request_timeout) From 6b2883074be3279734b11d3f2666e383ae42b744 Mon Sep 17 00:00:00 2001 From: "adam.serafini" Date: Wed, 12 Apr 2017 10:59:03 +0200 Subject: [PATCH 17/21] Fix installation on Ubuntu 16.10 Fixes issue #629. Printing a unicode string at the end of the setup.py script is asking for trouble. It's also redundant: the pip tool itself tells the user whether the installation was successful or not. --- setup.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/setup.py b/setup.py index deb52c27..aa5f2b08 100644 --- a/setup.py +++ b/setup.py @@ -64,7 +64,3 @@ except DistutilsPlatformError as exception: print("Installing without uJSON or uvLoop") setup_kwargs['install_requires'] = requirements setup(**setup_kwargs) - -# Installation was successful -print(u"\n\n\U0001F680 " - "Sanic version {} installation suceeded.\n".format(version)) From 235e5511ebee6fcd53ad1e056d44df55bea3d44b Mon Sep 17 00:00:00 2001 From: "adam.serafini" Date: Wed, 12 Apr 2017 11:02:13 +0200 Subject: [PATCH 18/21] Bump version --- sanic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/__init__.py b/sanic/__init__.py index 7bf0994a..7ddeb1ea 100644 --- a/sanic/__init__.py +++ b/sanic/__init__.py @@ -1,6 +1,6 @@ from sanic.app import Sanic from sanic.blueprints import Blueprint -__version__ = '0.5.0' +__version__ = '0.5.1' __all__ = ['Sanic', 'Blueprint'] From afd51e0823524eec683b226a20f40d958253064f Mon Sep 17 00:00:00 2001 From: lazydog Date: Fri, 14 Apr 2017 02:55:39 +0800 Subject: [PATCH 19/21] fix directory traversal flaw --- sanic/static.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sanic/static.py b/sanic/static.py index adbdd0ea..3f95253c 100644 --- a/sanic/static.py +++ b/sanic/static.py @@ -48,14 +48,18 @@ def register(app, uri, file_or_directory, pattern, # Merge served directory and requested file if provided # Strip all / that in the beginning of the URL to help prevent python # from herping a derp and treating the uri as an absolute path - file_path = file_or_directory + root_path = file_or_directory if file_uri: file_path = path.join( file_or_directory, sub('^[/]*', '', file_uri)) # URL decode the path sent by the browser otherwise we won't be able to # match filenames which got encoded (filenames with spaces etc) - file_path = unquote(file_path) + file_path = path.abspath(unquote(file_path)) + if not file_path.startswith(root_path): + raise FileNotFound('File not found', + path=file_or_directory, + relative_url=file_uri) try: headers = {} # Check if the client has been sent this file before From ae09dec05e10816b37eed425c87e193d230c5a73 Mon Sep 17 00:00:00 2001 From: lazydog Date: Fri, 14 Apr 2017 03:38:55 +0800 Subject: [PATCH 20/21] fixed `UnboundLocalError` --- sanic/static.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/static.py b/sanic/static.py index 3f95253c..24fce4ff 100644 --- a/sanic/static.py +++ b/sanic/static.py @@ -48,7 +48,7 @@ def register(app, uri, file_or_directory, pattern, # Merge served directory and requested file if provided # Strip all / that in the beginning of the URL to help prevent python # from herping a derp and treating the uri as an absolute path - root_path = file_or_directory + root_path = file_path = file_or_directory if file_uri: file_path = path.join( file_or_directory, sub('^[/]*', '', file_uri)) From 5796f211c164c74da78ac5a28567b52af06e16ad Mon Sep 17 00:00:00 2001 From: Shawn Niederriter Date: Fri, 14 Apr 2017 17:17:23 +0000 Subject: [PATCH 21/21] Added detailed plotly example project --- examples/plotly_example/plotlyjs_example.py | 85 ++++++++++++++++++++ examples/plotly_example/requirements.txt | 5 ++ examples/plotly_example/templates/index.html | 0 3 files changed, 90 insertions(+) create mode 100644 examples/plotly_example/plotlyjs_example.py create mode 100644 examples/plotly_example/requirements.txt create mode 100644 examples/plotly_example/templates/index.html diff --git a/examples/plotly_example/plotlyjs_example.py b/examples/plotly_example/plotlyjs_example.py new file mode 100644 index 00000000..f536067c --- /dev/null +++ b/examples/plotly_example/plotlyjs_example.py @@ -0,0 +1,85 @@ +from sanic import Sanic + +from sanic_session import InMemorySessionInterface +from sanic_jinja2 import SanicJinja2 + +import json +import plotly + +import pandas as pd +import numpy as np + +app = Sanic(__name__) + +jinja = SanicJinja2(app) +session = InMemorySessionInterface(cookie_name=app.name, prefix=app.name) + +@app.middleware('request') +async def print_on_request(request): + print(request.headers) + await session.open(request) + +@app.middleware('response') +async def print_on_response(request, response): + await session.save(request, response) + + + +@app.route('/') +async def index(request): + rng = pd.date_range('1/1/2011', periods=7500, freq='H') + ts = pd.Series(np.random.randn(len(rng)), index=rng) + + graphs = [ + dict( + data=[ + dict( + x=[1, 2, 3], + y=[10, 20, 30], + type='scatter' + ), + ], + layout=dict( + title='first graph' + ) + ), + + dict( + data=[ + dict( + x=[1, 3, 5], + y=[10, 50, 30], + type='bar' + ), + ], + layout=dict( + title='second graph' + ) + ), + + dict( + data=[ + dict( + x=ts.index, # Can use the pandas data structures directly + y=ts + ) + ] + ) + ] + + # Add "ids" to each of the graphs to pass up to the client + # for templating + ids = ['graph-{}'.format(i) for i, _ in enumerate(graphs)] + + # Convert the figures to JSON + # PlotlyJSONEncoder appropriately converts pandas, datetime, etc + # objects to their JSON equivalents + graphJSON = json.dumps(graphs, cls=plotly.utils.PlotlyJSONEncoder) + + return jinja.render('index.html', request, + ids=ids, + graphJSON=graphJSON) + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=8000, debug=True) \ No newline at end of file diff --git a/examples/plotly_example/requirements.txt b/examples/plotly_example/requirements.txt new file mode 100644 index 00000000..91875907 --- /dev/null +++ b/examples/plotly_example/requirements.txt @@ -0,0 +1,5 @@ +pandas==0.19.2 +plotly==2.0.7 +sanic==0.5.0 +sanic-jinja2==0.5.1 +sanic-session==0.1.3 \ No newline at end of file diff --git a/examples/plotly_example/templates/index.html b/examples/plotly_example/templates/index.html new file mode 100644 index 00000000..e69de29b