From 15b1c875f5058f66a24c3c7462244a90839fe27d Mon Sep 17 00:00:00 2001 From: Harsha Narayana Date: Fri, 28 Dec 2018 11:30:17 +0530 Subject: [PATCH 1/9] fix minor type and pip install instruction mismatch --- README.rst | 2 +- docs/sanic/contributing.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index a1406a14..73b59f68 100644 --- a/README.rst +++ b/README.rst @@ -57,7 +57,7 @@ To install sanic without uvloop or ujson using bash, you can provide either or b using any truthy string like `'y', 'yes', 't', 'true', 'on', '1'` and setting the ``SANIC_NO_X`` (``X`` = ``UVLOOP``/``UJSON``) to true will stop that features installation. -- ``SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip install sanic`` +- ``SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip3 install sanic`` Hello World Example diff --git a/docs/sanic/contributing.rst b/docs/sanic/contributing.rst index f500b4ca..ce4278eb 100644 --- a/docs/sanic/contributing.rst +++ b/docs/sanic/contributing.rst @@ -16,7 +16,7 @@ directory with a virtual environment already set up, then run: .. code:: bash - pip3 install -e . '[.dev]' + pip3 install -e '.[dev]' Dependency Changes ------------------ @@ -35,7 +35,7 @@ the document that explains the way ``sanic`` manages dependencies inside the ``s | extras_require['test'] | for ``sanic`` | | +------------------------+-----------------------------------------------+--------------------------------+ | extras_require['dev'] | Additional Development requirements to add | ``pip3 install -e '.[dev]'`` | -| | contributing | | +| | for contributing | | +------------------------+-----------------------------------------------+--------------------------------+ | extras_require['docs'] | Dependencies required to enable building and | ``pip3 install -e '.[docs]'`` | | | enhancing sanic documentation | | From 50b359fdb20d1be93bd27ca6633aaf5f256932aa Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Sun, 30 Dec 2018 11:40:48 +0200 Subject: [PATCH 2/9] Update README.rst Add new logo and update contents of README. Update README.rst Fix image syntax. Update README.rst Fix README links. --- README.rst | 86 +++++++++++++++++++++++++----------------------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/README.rst b/README.rst index 73b59f68..9141d4f6 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,8 @@ -Sanic -===== +.. image:: https://raw.githubusercontent.com/huge-success/sanic-assets/master/png/sanic-framework-logo-400x97.png + :alt: Sanic | Build fast. Run fast. + +Sanic | Build fast. Run fast. +============================= .. start-badges @@ -13,8 +16,10 @@ Sanic * - Package - | |PyPI| |PyPI version| |Wheel| |Supported implementations| |Code style black| * - Support - - |Join the chat at https://gitter.im/sanic-python/Lobby| + - | |Forums| |Join the chat at https://gitter.im/sanic-python/Lobby| +.. |Forums| image:: https://img.shields.io/badge/forums-community-ff0068.svg + :target: https://community.sanicframework.org/ .. |Join the chat at https://gitter.im/sanic-python/Lobby| image:: https://badges.gitter.im/sanic-python/Lobby.svg :target: https://gitter.im/sanic-python/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge .. |Codecov| image:: https://codecov.io/gh/huge-success/sanic/branch/master/graph/badge.svg @@ -40,24 +45,22 @@ Sanic .. end-badges -Sanic is a Flask-like Python 3.5+ web server that's written to go fast. It's based on the work done by the amazing folks at magicstack, and was inspired by `this article `_. +Sanic is a Python web server that's written to go fast. It allows usage the `async` and `await` syntax added in Python 3.5, which makes your code non-blocking and speedy. -On top of being Flask-like, Sanic supports async request handlers. This means you can use the new shiny async/await syntax from Python 3.5, making your code non-blocking and speedy. +`Source code on GitHub `_ | `Help and discussion board `_. -Sanic is developed `on GitHub `_. We also have `a community discussion board `_. Contributions are welcome! +The project is maintained by the community, for the community **Contributions are welcome!** -If you have a project that utilizes Sanic make sure to comment on the `issue `_ that we use to track those projects! +The goal of the project is to provide a simple way to get up and running a highly performant HTTP server that is easy to build, to expand, and ultimately to scale. Installation ------------ -- ``pip3 install sanic`` +``pip3 install sanic`` -To install sanic without uvloop or ujson using bash, you can provide either or both of these environmental variables -using any truthy string like `'y', 'yes', 't', 'true', 'on', '1'` and setting the ``SANIC_NO_X`` (``X`` = ``UVLOOP``/``UJSON``) -to true will stop that features installation. - -- ``SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip3 install sanic`` + Sanic makes use of ``uvloop`` and ``ujson`` to help with performance. If you do not want to use those packages, simply add an environmental variable ``SANIC_NO_UVLOOP=true`` or ``SANIC_NO_UJSON=true`` at install time. + + ``SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip3 install sanic`` Hello World Example @@ -76,6 +79,27 @@ Hello World Example if __name__ == '__main__': app.run(host='0.0.0.0', port=8000) + +Sanic can now be easily run using ``python3 hello.py``. + +.. code:: + + [2018-12-30 11:37:41 +0200] [13564] [INFO] Goin' Fast @ http://0.0.0.0:8000 + [2018-12-30 11:37:41 +0200] [13564] [INFO] Starting worker [13564] + +And, we can verify it is working: ``curl localhost:8000 -i`` + +.. code:: + + HTTP/1.1 200 OK + Connection: keep-alive + Keep-Alive: 5 + Content-Length: 17 + Content-Type: application/json + + {"hello":"world"} + +**Now, let's go build something fast!** Documentation @@ -89,37 +113,7 @@ Questions and Discussion `Ask a question or join the conversation `_. +Contribution +------------ -Examples --------- -`Non-Core examples `_. Examples of plugins and Sanic that are outside the scope of Sanic core. - -`Extensions `_. Sanic extensions created by the community. - -`Projects `_. Sanic in production use. - - -Final Thoughts --------------- - -:: - - ▄▄▄▄▄ - ▀▀▀██████▄▄▄ _______________ - ▄▄▄▄▄ █████████▄ / \ - ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Gotta go fast! | - ▀▀█████▄▄ ▀██████▄██ | _________________/ - ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/ - ▀▀▀▄ ▀▀███ ▀ ▄▄ - ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ - ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ - ▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀ - ▌ ▐▀████▐███▒▒▒▒▒▐██▌ - ▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀ - ▀▀█████████▀ - ▄▄██▀██████▀█ - ▄██▀ ▀▀▀ █ - ▄█ ▐▌ - ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄ - ▌ ▐ ▀▀▄▄▄▀ - ▀▀▄▄▀ +We are always happy to have new contributions. We have `marked issues good for anyone looking to get started `_, and welcome `questions on the forums `_. Please take a look at our `Contribution guidelines `_. From 040468755c8010435ba7383ca7ec66bc9f3abe48 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Sun, 30 Dec 2018 12:22:27 +0200 Subject: [PATCH 3/9] Change ASCII Logo Update logo text Reformat app.py --- sanic/app.py | 10 +++++++--- sanic/config.py | 28 +++++++--------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/sanic/app.py b/sanic/app.py index d3c98ba2..811597c7 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -13,7 +13,7 @@ from traceback import format_exc from urllib.parse import urlencode, urlunparse from sanic import reloader_helpers -from sanic.config import Config +from sanic.config import Config, BASE_LOGO from sanic.constants import HTTP_METHODS from sanic.exceptions import SanicException, ServerError, URLBuildError from sanic.handlers import ErrorHandler @@ -1256,10 +1256,14 @@ class Sanic: logger.setLevel(logging.DEBUG) if ( - self.config.LOGO is not None + self.config.LOGO and os.environ.get("SANIC_SERVER_RUNNING") != "true" ): - logger.debug(self.config.LOGO) + logger.debug( + self.config.LOGO + if isinstance(self.config.LOGO, str) + else BASE_LOGO + ) if run_async: server_settings["run_async"] = True diff --git a/sanic/config.py b/sanic/config.py index 15341829..dda377f8 100644 --- a/sanic/config.py +++ b/sanic/config.py @@ -5,32 +5,18 @@ from sanic.exceptions import PyFileError SANIC_PREFIX = "SANIC_" +BASE_LOGO = """ + + Sanic + Build Fast. Run Fast. + +""" class Config(dict): def __init__(self, defaults=None, load_env=True, keep_alive=True): super().__init__(defaults or {}) - self.LOGO = """ - ▄▄▄▄▄ - ▀▀▀██████▄▄▄ _______________ - ▄▄▄▄▄ █████████▄ / \\ - ▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Gotta go fast! | - ▀▀█████▄▄ ▀██████▄██ | _________________/ - ▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/ - ▀▀▀▄ ▀▀███ ▀ ▄▄ - ▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌ - ██▀▄▄▄██▀▄███▀ ▀▀████ ▄██ -▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀ -▌ ▐▀████▐███▒▒▒▒▒▐██▌ -▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀ - ▀▀█████████▀ - ▄▄██▀██████▀█ - ▄██▀ ▀▀▀ █ - ▄█ ▐▌ - ▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄ -▌ ▐ ▀▀▄▄▄▀ - ▀▀▄▄▀ -""" + self.LOGO = BASE_LOGO self.REQUEST_MAX_SIZE = 100000000 # 100 megabytes self.REQUEST_BUFFER_QUEUE_SIZE = 100 self.REQUEST_TIMEOUT = 60 # 60 seconds From 05dd3b2e9db4db07a3c6f9e2fb86443553262a21 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Sun, 30 Dec 2018 13:18:06 +0200 Subject: [PATCH 4/9] Run linter --- sanic/app.py | 2 +- tests/conftest.py | 2 +- tests/performance/aiohttp/simple_server.py | 9 +- tests/performance/bottle/simple_server.py | 5 +- tests/performance/falcon/simple_server.py | 4 +- tests/performance/kyoukai/simple_server.py | 10 +- tests/performance/sanic/http_response.py | 18 +- tests/performance/sanic/simple_server.py | 9 +- tests/performance/sanic/varied_server.py | 18 +- tests/performance/tornado/simple_server.py | 10 +- tests/performance/wheezy/simple_server.py | 24 +- tests/test_app.py | 107 +-- tests/test_bad_request.py | 13 +- tests/test_blueprints.py | 478 ++++++------- tests/test_config.py | 52 +- tests/test_cookies.py | 160 ++--- tests/test_create_task.py | 18 +- tests/test_custom_protocol.py | 19 +- tests/test_dynamic_routes.py | 40 +- tests/test_exceptions.py | 129 ++-- tests/test_exceptions_handler.py | 80 +-- tests/test_helpers.py | 28 +- tests/test_keep_alive_timeout.py | 163 +++-- tests/test_logging.py | 109 +-- tests/test_logo.py | 60 ++ tests/test_middleware.py | 111 ++- tests/test_multiprocessing.py | 35 +- tests/test_named_routes.py | 322 +++++---- tests/test_payload_too_large.py | 30 +- tests/test_redirect.py | 61 +- tests/test_request_cancel.py | 12 +- tests/test_request_data.py | 34 +- tests/test_request_stream.py | 284 ++++---- tests/test_request_timeout.py | 104 +-- tests/test_requests.py | 547 ++++++++------- tests/test_response.py | 486 ++++++------- tests/test_response_timeout.py | 32 +- tests/test_routes.py | 771 +++++++++++---------- tests/test_server_events.py | 30 +- tests/test_signal_handlers.py | 17 +- tests/test_static.py | 436 ++++++------ tests/test_url_building.py | 239 ++++--- tests/test_url_for_static.py | 542 ++++++++------- tests/test_utf8.py | 45 +- tests/test_vhosts.py | 34 +- tests/test_views.py | 170 +++-- tests/test_worker.py | 35 +- 47 files changed, 3092 insertions(+), 2852 deletions(-) create mode 100644 tests/test_logo.py diff --git a/sanic/app.py b/sanic/app.py index 811597c7..e4e142ca 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -13,7 +13,7 @@ from traceback import format_exc from urllib.parse import urlencode, urlunparse from sanic import reloader_helpers -from sanic.config import Config, BASE_LOGO +from sanic.config import BASE_LOGO, Config from sanic.constants import HTTP_METHODS from sanic.exceptions import SanicException, ServerError, URLBuildError from sanic.handlers import ErrorHandler diff --git a/tests/conftest.py b/tests/conftest.py index ac47aceb..2bab4890 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,7 @@ import pytest from sanic import Sanic -if sys.platform in ['win32', 'cygwin']: +if sys.platform in ["win32", "cygwin"]: collect_ignore = ["test_worker.py"] diff --git a/tests/performance/aiohttp/simple_server.py b/tests/performance/aiohttp/simple_server.py index 7c61f723..c781f070 100644 --- a/tests/performance/aiohttp/simple_server.py +++ b/tests/performance/aiohttp/simple_server.py @@ -9,10 +9,15 @@ import ujson as json loop = uvloop.new_event_loop() asyncio.set_event_loop(loop) + async def handle(request): - return web.Response(body=json.dumps({"test":True}).encode('utf-8'), content_type='application/json') + return web.Response( + body=json.dumps({"test": True}).encode("utf-8"), + content_type="application/json", + ) + app = web.Application(loop=loop) -app.router.add_route('GET', '/', handle) +app.router.add_route("GET", "/", handle) web.run_app(app, port=sys.argv[1], access_log=None) diff --git a/tests/performance/bottle/simple_server.py b/tests/performance/bottle/simple_server.py index d562350a..58605fae 100644 --- a/tests/performance/bottle/simple_server.py +++ b/tests/performance/bottle/simple_server.py @@ -4,8 +4,9 @@ from bottle import route, run import ujson -@route('/') +@route("/") def index(): - return ujson.dumps({'test': True}) + return ujson.dumps({"test": True}) + app = bottle.default_app() diff --git a/tests/performance/falcon/simple_server.py b/tests/performance/falcon/simple_server.py index 4403ac14..86656ab8 100644 --- a/tests/performance/falcon/simple_server.py +++ b/tests/performance/falcon/simple_server.py @@ -3,9 +3,11 @@ import falcon import ujson as json + class TestResource: def on_get(self, req, resp): resp.body = json.dumps({"test": True}) + app = falcon.API() -app.add_route('/', TestResource()) +app.add_route("/", TestResource()) diff --git a/tests/performance/kyoukai/simple_server.py b/tests/performance/kyoukai/simple_server.py index 058514f7..4b901978 100644 --- a/tests/performance/kyoukai/simple_server.py +++ b/tests/performance/kyoukai/simple_server.py @@ -13,8 +13,14 @@ kyk = Kyoukai("example_app") logger = logging.getLogger("Kyoukai") logger.setLevel(logging.ERROR) + @kyk.route("/") async def index(ctx: HTTPRequestContext): - return ujson.dumps({"test":True}), 200, {"Content-Type": "application/json"} + return ( + ujson.dumps({"test": True}), + 200, + {"Content-Type": "application/json"}, + ) -kyk.run() \ No newline at end of file + +kyk.run() diff --git a/tests/performance/sanic/http_response.py b/tests/performance/sanic/http_response.py index 40557ab7..8d864f53 100644 --- a/tests/performance/sanic/http_response.py +++ b/tests/performance/sanic/http_response.py @@ -3,8 +3,10 @@ import sys import os import inspect -currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) -sys.path.insert(0, currentdir + '/../../../') +currentdir = os.path.dirname( + os.path.abspath(inspect.getfile(inspect.currentframe())) +) +sys.path.insert(0, currentdir + "/../../../") import timeit @@ -16,7 +18,11 @@ print("Running New 100,000 times") times = 0 total_time = 0 for n in range(6): - time = timeit.timeit('json({ "test":True }).output()', setup='from sanic.response import json', number=100000) + time = timeit.timeit( + 'json({ "test":True }).output()', + setup="from sanic.response import json", + number=100000, + ) print("Took {} seconds".format(time)) total_time += time times += 1 @@ -26,7 +32,11 @@ print("Running Old 100,000 times") times = 0 total_time = 0 for n in range(6): - time = timeit.timeit('json({ "test":True }).output_old()', setup='from sanic.response import json', number=100000) + time = timeit.timeit( + 'json({ "test":True }).output_old()', + setup="from sanic.response import json", + number=100000, + ) print("Took {} seconds".format(time)) total_time += time times += 1 diff --git a/tests/performance/sanic/simple_server.py b/tests/performance/sanic/simple_server.py index 5cf86afd..33d1e52a 100644 --- a/tests/performance/sanic/simple_server.py +++ b/tests/performance/sanic/simple_server.py @@ -2,8 +2,10 @@ import sys import os import inspect -currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) -sys.path.insert(0, currentdir + '/../../../') +currentdir = os.path.dirname( + os.path.abspath(inspect.getfile(inspect.currentframe())) +) +sys.path.insert(0, currentdir + "/../../../") from sanic import Sanic from sanic.response import json @@ -15,5 +17,6 @@ app = Sanic("test") async def test(request): return json({"test": True}) -if __name__ == '__main__': + +if __name__ == "__main__": app.run(host="0.0.0.0", port=sys.argv[1]) diff --git a/tests/performance/sanic/varied_server.py b/tests/performance/sanic/varied_server.py index a83e3044..af919693 100644 --- a/tests/performance/sanic/varied_server.py +++ b/tests/performance/sanic/varied_server.py @@ -2,8 +2,10 @@ import sys import os import inspect -currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) -sys.path.insert(0, currentdir + '/../../../') +currentdir = os.path.dirname( + os.path.abspath(inspect.getfile(inspect.currentframe())) +) +sys.path.insert(0, currentdir + "/../../../") from sanic import Sanic from sanic.response import json, text @@ -17,7 +19,7 @@ async def test(request): return json({"test": True}) -@app.route("/sync", methods=['GET', 'POST']) +@app.route("/sync", methods=["GET", "POST"]) def test(request): return json({"test": True}) @@ -44,7 +46,14 @@ def post_json(request): @app.route("/query_string") def query_string(request): - return json({"parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string}) + return json( + { + "parsed": True, + "args": request.args, + "url": request.url, + "query_string": request.query_string, + } + ) import sys @@ -52,7 +61,6 @@ import sys app.run(host="0.0.0.0", port=sys.argv[1]) - # import asyncio_redis # import asyncpg # async def setup(sanic, loop): diff --git a/tests/performance/tornado/simple_server.py b/tests/performance/tornado/simple_server.py index 32192900..a326eeaf 100644 --- a/tests/performance/tornado/simple_server.py +++ b/tests/performance/tornado/simple_server.py @@ -5,14 +5,14 @@ from tornado import ioloop, web class MainHandler(web.RequestHandler): def get(self): - self.write(ujson.dumps({'test': True})) + self.write(ujson.dumps({"test": True})) -app = web.Application([ - (r'/', MainHandler) -], debug=False, +app = web.Application( + [(r"/", MainHandler)], + debug=False, compress_response=False, - static_hash_cache=True + static_hash_cache=True, ) app.listen(8000) diff --git a/tests/performance/wheezy/simple_server.py b/tests/performance/wheezy/simple_server.py index 99a9f1e4..cbeeee6a 100644 --- a/tests/performance/wheezy/simple_server.py +++ b/tests/performance/wheezy/simple_server.py @@ -12,16 +12,17 @@ from wheezy.web.middleware import path_routing_middleware_factory import ujson -class WelcomeHandler(BaseHandler): +class WelcomeHandler(BaseHandler): def get(self): - response = HTTPResponse(content_type='application/json; charset=UTF-8') - response.write(ujson.dumps({"test":True})) + response = HTTPResponse(content_type="application/json; charset=UTF-8") + response.write(ujson.dumps({"test": True})) return response + all_urls = [ - url('', WelcomeHandler, name='default'), -# url('', welcome, name='welcome') + url("", WelcomeHandler, name="default"), + # url('', welcome, name='welcome') ] @@ -29,18 +30,19 @@ options = {} main = WSGIApplication( middleware=[ bootstrap_defaults(url_mapping=all_urls), - path_routing_middleware_factory + path_routing_middleware_factory, ], - options=options + options=options, ) -if __name__ == '__main__': +if __name__ == "__main__": import sys from wsgiref.simple_server import make_server + try: - print('Visit http://localhost:{}/'.format(sys.argv[-1])) - make_server('', int(sys.argv[-1]), main).serve_forever() + print("Visit http://localhost:{}/".format(sys.argv[-1])) + make_server("", int(sys.argv[-1]), main).serve_forever() except KeyboardInterrupt: pass - print('\nThanks!') + print("\nThanks!") diff --git a/tests/test_app.py b/tests/test_app.py index be881845..dbe5b9d9 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -8,14 +8,13 @@ from sanic.response import text def test_app_loop_running(app): - - @app.get('/test') + @app.get("/test") async def handler(request): assert isinstance(app.loop, asyncio.AbstractEventLoop) - return text('pass') + return text("pass") - request, response = app.test_client.get('/test') - assert response.text == 'pass' + request, response = app.test_client.get("/test") + assert response.text == "pass" def test_app_loop_not_running(app): @@ -23,105 +22,117 @@ def test_app_loop_not_running(app): app.loop assert str(excinfo.value) == ( - 'Loop can only be retrieved after the app has started ' - 'running. Not supported with `create_server` function' + "Loop can only be retrieved after the app has started " + "running. Not supported with `create_server` function" ) def test_app_run_raise_type_error(app): with pytest.raises(TypeError) as excinfo: - app.run(loop='loop') + app.run(loop="loop") assert str(excinfo.value) == ( - 'loop is not a valid argument. To use an existing loop, ' - 'change to create_server().\nSee more: ' - 'https://sanic.readthedocs.io/en/latest/sanic/deploying.html' - '#asynchronous-support' + "loop is not a valid argument. To use an existing loop, " + "change to create_server().\nSee more: " + "https://sanic.readthedocs.io/en/latest/sanic/deploying.html" + "#asynchronous-support" ) def test_app_route_raise_value_error(app): with pytest.raises(ValueError) as excinfo: - @app.route('/test') - async def handler(): - return text('test') - assert str(excinfo.value) == 'Required parameter `request` missing in the handler() route?' + @app.route("/test") + async def handler(): + return text("test") + + assert ( + str(excinfo.value) + == "Required parameter `request` missing in the handler() route?" + ) def test_app_handle_request_handler_is_none(app, monkeypatch): - def mockreturn(*args, **kwargs): - return None, [], {}, '' + return None, [], {}, "" # Not sure how to make app.router.get() return None, so use mock here. - monkeypatch.setattr(app.router, 'get', mockreturn) + monkeypatch.setattr(app.router, "get", mockreturn) - @app.get('/test') + @app.get("/test") def handler(request): - return text('test') + return text("test") - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") - assert response.text == 'Error: \'None\' was returned while requesting a handler from the router' + assert ( + response.text + == "Error: 'None' was returned while requesting a handler from the router" + ) -@pytest.mark.parametrize('websocket_enabled', [True, False]) -@pytest.mark.parametrize('enable', [True, False]) +@pytest.mark.parametrize("websocket_enabled", [True, False]) +@pytest.mark.parametrize("enable", [True, False]) def test_app_enable_websocket(app, websocket_enabled, enable): app.websocket_enabled = websocket_enabled app.enable_websocket(enable=enable) assert app.websocket_enabled == enable - @app.websocket('/ws') + @app.websocket("/ws") async def handler(request, ws): - await ws.send('test') + await ws.send("test") assert app.websocket_enabled == True def test_handle_request_with_nested_exception(app, monkeypatch): - err_msg = 'Mock Exception' + err_msg = "Mock Exception" # Not sure how to raise an exception in app.error_handler.response(), use mock here def mock_error_handler_response(*args, **kwargs): raise Exception(err_msg) - monkeypatch.setattr(app.error_handler, 'response', mock_error_handler_response) + monkeypatch.setattr( + app.error_handler, "response", mock_error_handler_response + ) - @app.get('/') + @app.get("/") def handler(request): raise Exception - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 500 - assert response.text == 'An error occurred while handling an error' + assert response.text == "An error occurred while handling an error" def test_handle_request_with_nested_exception_debug(app, monkeypatch): - err_msg = 'Mock Exception' + err_msg = "Mock Exception" # Not sure how to raise an exception in app.error_handler.response(), use mock here def mock_error_handler_response(*args, **kwargs): raise Exception(err_msg) - monkeypatch.setattr(app.error_handler, 'response', mock_error_handler_response) + monkeypatch.setattr( + app.error_handler, "response", mock_error_handler_response + ) - @app.get('/') + @app.get("/") def handler(request): raise Exception - return text('OK') + return text("OK") - request, response = app.test_client.get('/', debug=True) + request, response = app.test_client.get("/", debug=True) assert response.status == 500 assert response.text.startswith( - 'Error while handling error: {}\nStack: Traceback (most recent call last):\n'.format(err_msg) + "Error while handling error: {}\nStack: Traceback (most recent call last):\n".format( + err_msg + ) ) @@ -129,21 +140,23 @@ def test_handle_request_with_nested_sanic_exception(app, monkeypatch, caplog): # Not sure how to raise an exception in app.error_handler.response(), use mock here def mock_error_handler_response(*args, **kwargs): - raise SanicException('Mock SanicException') + raise SanicException("Mock SanicException") - monkeypatch.setattr(app.error_handler, 'response', mock_error_handler_response) + monkeypatch.setattr( + app.error_handler, "response", mock_error_handler_response + ) - @app.get('/') + @app.get("/") def handler(request): raise Exception - return text('OK') + return text("OK") with caplog.at_level(logging.ERROR): - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 500 - assert response.text == 'Error: Mock SanicException' + assert response.text == "Error: Mock SanicException" assert caplog.record_tuples[0] == ( - 'sanic.root', + "sanic.root", logging.ERROR, - "Exception occurred while handling uri: 'http://127.0.0.1:42101/'" + "Exception occurred while handling uri: 'http://127.0.0.1:42101/'", ) diff --git a/tests/test_bad_request.py b/tests/test_bad_request.py index d1c305f0..f27642b9 100644 --- a/tests/test_bad_request.py +++ b/tests/test_bad_request.py @@ -4,17 +4,18 @@ import asyncio def test_bad_request_response(app): lines = [] - @app.listener('after_server_start') + @app.listener("after_server_start") async def _request(sanic, loop): - connect = asyncio.open_connection('127.0.0.1', 42101) + connect = asyncio.open_connection("127.0.0.1", 42101) reader, writer = await connect - writer.write(b'not http') + writer.write(b"not http") while True: line = await reader.readline() if not line: break lines.append(line) app.stop() - 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' + + 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" diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 3a7e0fc4..397216d0 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -17,12 +17,13 @@ from sanic.views import CompositionView # GET # ------------------------------------------------------------ # -@pytest.fixture(scope='module') + +@pytest.fixture(scope="module") def static_file_directory(): """The static directory to serve""" current_file = inspect.getfile(inspect.currentframe()) current_directory = os.path.dirname(os.path.abspath(current_file)) - static_directory = os.path.join(current_directory, 'static') + static_directory = os.path.join(current_directory, "static") return static_directory @@ -32,21 +33,23 @@ def get_file_path(static_file_directory, file_name): def get_file_content(static_file_directory, file_name): """The content of the static file to check""" - with open(get_file_path(static_file_directory, file_name), 'rb') as file: + with open(get_file_path(static_file_directory, file_name), "rb") as file: return file.read() -@pytest.mark.parametrize('method', HTTP_METHODS) +@pytest.mark.parametrize("method", HTTP_METHODS) def test_versioned_routes_get(app, method): - bp = Blueprint('test_text') + bp = Blueprint("test_text") method = method.lower() func = getattr(bp, method) if callable(func): - @func('/{}'.format(method), version=1) + + @func("/{}".format(method), version=1) def handler(request): - return text('OK') + return text("OK") + else: print(func) raise Exception("{} is not callable".format(func)) @@ -55,245 +58,231 @@ def test_versioned_routes_get(app, method): client_method = getattr(app.test_client, method) - request, response = client_method('/v1/{}'.format(method)) + request, response = client_method("/v1/{}".format(method)) assert response.status == 200 def test_bp(app): - bp = Blueprint('test_text') + bp = Blueprint("test_text") - @bp.route('/') + @bp.route("/") def handler(request): - return text('Hello') + return text("Hello") app.blueprint(bp) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert app.is_request_stream is False - assert response.text == 'Hello' + assert response.text == "Hello" def test_bp_strict_slash(app): - bp = Blueprint('test_text') + bp = Blueprint("test_text") - @bp.get('/get', strict_slashes=True) + @bp.get("/get", strict_slashes=True) def get_handler(request): - return text('OK') + return text("OK") - @bp.post('/post/', strict_slashes=True) + @bp.post("/post/", strict_slashes=True) def post_handler(request): - return text('OK') + return text("OK") app.blueprint(bp) - request, response = app.test_client.get('/get') - assert response.text == 'OK' + request, response = app.test_client.get("/get") + assert response.text == "OK" assert response.json is None - request, response = app.test_client.get('/get/') + request, response = app.test_client.get("/get/") assert response.status == 404 - request, response = app.test_client.post('/post/') - assert response.text == 'OK' + request, response = app.test_client.post("/post/") + assert response.text == "OK" - request, response = app.test_client.post('/post') + request, response = app.test_client.post("/post") assert response.status == 404 def test_bp_strict_slash_default_value(app): - bp = Blueprint('test_text', strict_slashes=True) + bp = Blueprint("test_text", strict_slashes=True) - @bp.get('/get') + @bp.get("/get") def get_handler(request): - return text('OK') + return text("OK") - @bp.post('/post/') + @bp.post("/post/") def post_handler(request): - return text('OK') + return text("OK") app.blueprint(bp) - request, response = app.test_client.get('/get/') + request, response = app.test_client.get("/get/") assert response.status == 404 - request, response = app.test_client.post('/post') + request, response = app.test_client.post("/post") assert response.status == 404 def test_bp_strict_slash_without_passing_default_value(app): - bp = Blueprint('test_text') + bp = Blueprint("test_text") - @bp.get('/get') + @bp.get("/get") def get_handler(request): - return text('OK') + return text("OK") - @bp.post('/post/') + @bp.post("/post/") def post_handler(request): - return text('OK') + return text("OK") app.blueprint(bp) - request, response = app.test_client.get('/get/') - assert response.text == 'OK' + request, response = app.test_client.get("/get/") + assert response.text == "OK" - request, response = app.test_client.post('/post') - assert response.text == 'OK' + request, response = app.test_client.post("/post") + assert response.text == "OK" def test_bp_strict_slash_default_value_can_be_overwritten(app): - bp = Blueprint('test_text', strict_slashes=True) + bp = Blueprint("test_text", strict_slashes=True) - @bp.get('/get', strict_slashes=False) + @bp.get("/get", strict_slashes=False) def get_handler(request): - return text('OK') + return text("OK") - @bp.post('/post/', strict_slashes=False) + @bp.post("/post/", strict_slashes=False) def post_handler(request): - return text('OK') + return text("OK") app.blueprint(bp) - request, response = app.test_client.get('/get/') - assert response.text == 'OK' + request, response = app.test_client.get("/get/") + assert response.text == "OK" - request, response = app.test_client.post('/post') - assert response.text == 'OK' + request, response = app.test_client.post("/post") + assert response.text == "OK" def test_bp_with_url_prefix(app): - bp = Blueprint('test_text', url_prefix='/test1') + bp = Blueprint("test_text", url_prefix="/test1") - @bp.route('/') + @bp.route("/") def handler(request): - return text('Hello') + return text("Hello") app.blueprint(bp) - request, response = app.test_client.get('/test1/') + request, response = app.test_client.get("/test1/") - assert response.text == 'Hello' + assert response.text == "Hello" def test_several_bp_with_url_prefix(app): - bp = Blueprint('test_text', url_prefix='/test1') - bp2 = Blueprint('test_text2', url_prefix='/test2') + bp = Blueprint("test_text", url_prefix="/test1") + bp2 = Blueprint("test_text2", url_prefix="/test2") - @bp.route('/') + @bp.route("/") def handler(request): - return text('Hello') + return text("Hello") - @bp2.route('/') + @bp2.route("/") def handler2(request): - return text('Hello2') + return text("Hello2") app.blueprint(bp) app.blueprint(bp2) - request, response = app.test_client.get('/test1/') - assert response.text == 'Hello' + request, response = app.test_client.get("/test1/") + assert response.text == "Hello" - request, response = app.test_client.get('/test2/') - assert response.text == 'Hello2' + request, response = app.test_client.get("/test2/") + assert response.text == "Hello2" def test_bp_with_host(app): - bp = Blueprint('test_bp_host', url_prefix='/test1', host="example.com") + bp = Blueprint("test_bp_host", url_prefix="/test1", host="example.com") - @bp.route('/') + @bp.route("/") def handler1(request): - return text('Hello') + return text("Hello") - @bp.route('/', host="sub.example.com") + @bp.route("/", host="sub.example.com") def handler2(request): - return text('Hello subdomain!') + return text("Hello subdomain!") app.blueprint(bp) headers = {"Host": "example.com"} - request, response = app.test_client.get( - '/test1/', - headers=headers) - assert response.text == 'Hello' + request, response = app.test_client.get("/test1/", headers=headers) + assert response.text == "Hello" headers = {"Host": "sub.example.com"} - request, response = app.test_client.get( - '/test1/', - headers=headers) + request, response = app.test_client.get("/test1/", headers=headers) - assert response.text == 'Hello subdomain!' + assert response.text == "Hello subdomain!" def test_several_bp_with_host(app): - bp = Blueprint('test_text', - url_prefix='/test', - host="example.com") - bp2 = Blueprint('test_text2', - url_prefix='/test', - host="sub.example.com") + bp = Blueprint("test_text", url_prefix="/test", host="example.com") + bp2 = Blueprint("test_text2", url_prefix="/test", host="sub.example.com") - @bp.route('/') + @bp.route("/") def handler(request): - return text('Hello') + return text("Hello") - @bp2.route('/') + @bp2.route("/") def handler1(request): - return text('Hello2') + return text("Hello2") - @bp2.route('/other/') + @bp2.route("/other/") def handler2(request): - return text('Hello3') + return text("Hello3") app.blueprint(bp) app.blueprint(bp2) assert bp.host == "example.com" headers = {"Host": "example.com"} - request, response = app.test_client.get( - '/test/', - headers=headers) - assert response.text == 'Hello' + request, response = app.test_client.get("/test/", headers=headers) + assert response.text == "Hello" assert bp2.host == "sub.example.com" headers = {"Host": "sub.example.com"} - request, response = app.test_client.get( - '/test/', - headers=headers) + request, response = app.test_client.get("/test/", headers=headers) - assert response.text == 'Hello2' - request, response = app.test_client.get( - '/test/other/', - headers=headers) - assert response.text == 'Hello3' + assert response.text == "Hello2" + request, response = app.test_client.get("/test/other/", headers=headers) + assert response.text == "Hello3" def test_bp_middleware(app): - blueprint = Blueprint('test_middleware') + blueprint = Blueprint("test_middleware") - @blueprint.middleware('response') + @blueprint.middleware("response") async def process_response(request, response): - return text('OK') + return text("OK") - @app.route('/') + @app.route("/") async def handler(request): - return text('FAIL') + return text("FAIL") app.blueprint(blueprint) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_bp_exception_handler(app): - blueprint = Blueprint('test_middleware') + blueprint = Blueprint("test_middleware") - @blueprint.route('/1') + @blueprint.route("/1") def handler_1(request): raise InvalidUsage("OK") - @blueprint.route('/2') + @blueprint.route("/2") def handler_2(request): raise ServerError("OK") - @blueprint.route('/3') + @blueprint.route("/3") def handler_3(request): raise NotFound("OK") @@ -303,131 +292,131 @@ def test_bp_exception_handler(app): app.blueprint(blueprint) - request, response = app.test_client.get('/1') + request, response = app.test_client.get("/1") assert response.status == 400 - request, response = app.test_client.get('/2') + request, response = app.test_client.get("/2") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.get('/3') + request, response = app.test_client.get("/3") assert response.status == 200 def test_bp_listeners(app): - blueprint = Blueprint('test_middleware') + blueprint = Blueprint("test_middleware") order = [] - @blueprint.listener('before_server_start') + @blueprint.listener("before_server_start") def handler_1(sanic, loop): order.append(1) - @blueprint.listener('after_server_start') + @blueprint.listener("after_server_start") def handler_2(sanic, loop): order.append(2) - @blueprint.listener('after_server_start') + @blueprint.listener("after_server_start") def handler_3(sanic, loop): order.append(3) - @blueprint.listener('before_server_stop') + @blueprint.listener("before_server_stop") def handler_4(sanic, loop): order.append(5) - @blueprint.listener('before_server_stop') + @blueprint.listener("before_server_stop") def handler_5(sanic, loop): order.append(4) - @blueprint.listener('after_server_stop') + @blueprint.listener("after_server_stop") def handler_6(sanic, loop): order.append(6) app.blueprint(blueprint) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert order == [1, 2, 3, 4, 5, 6] def test_bp_static(app): current_file = inspect.getfile(inspect.currentframe()) - with open(current_file, 'rb') as file: + with open(current_file, "rb") as file: current_file_contents = file.read() - blueprint = Blueprint('test_static') + blueprint = Blueprint("test_static") - blueprint.static('/testing.file', current_file) + blueprint.static("/testing.file", current_file) app.blueprint(blueprint) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.get("/testing.file") assert response.status == 200 assert response.body == current_file_contents -@pytest.mark.parametrize('file_name', ['test.html']) +@pytest.mark.parametrize("file_name", ["test.html"]) def test_bp_static_content_type(app, file_name): # This is done here, since no other test loads a file here current_file = inspect.getfile(inspect.currentframe()) current_directory = os.path.dirname(os.path.abspath(current_file)) - static_directory = os.path.join(current_directory, 'static') + static_directory = os.path.join(current_directory, "static") - blueprint = Blueprint('test_static') + blueprint = Blueprint("test_static") blueprint.static( - '/testing.file', + "/testing.file", get_file_path(static_directory, file_name), - content_type='text/html; charset=utf-8' + content_type="text/html; charset=utf-8", ) app.blueprint(blueprint) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.get("/testing.file") assert response.status == 200 assert response.body == get_file_content(static_directory, file_name) - assert response.headers['Content-Type'] == 'text/html; charset=utf-8' + assert response.headers["Content-Type"] == "text/html; charset=utf-8" def test_bp_shorthand(app): - blueprint = Blueprint('test_shorhand_routes') + blueprint = Blueprint("test_shorhand_routes") ev = asyncio.Event() - @blueprint.get('/get') + @blueprint.get("/get") def handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.put('/put') + @blueprint.put("/put") def put_handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.post('/post') + @blueprint.post("/post") def post_handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.head('/head') + @blueprint.head("/head") def head_handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.options('/options') + @blueprint.options("/options") def options_handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.patch('/patch') + @blueprint.patch("/patch") def patch_handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.delete('/delete') + @blueprint.delete("/delete") def delete_handler(request): assert request.stream is None - return text('OK') + return text("OK") - @blueprint.websocket('/ws/', strict_slashes=True) + @blueprint.websocket("/ws/", strict_slashes=True) async def websocket_handler(request, ws): assert request.stream is None ev.set() @@ -436,137 +425,146 @@ def test_bp_shorthand(app): assert app.is_request_stream is False - request, response = app.test_client.get('/get') - assert response.text == 'OK' + request, response = app.test_client.get("/get") + assert response.text == "OK" - request, response = app.test_client.post('/get') + request, response = app.test_client.post("/get") assert response.status == 405 - request, response = app.test_client.put('/put') - assert response.text == 'OK' + request, response = app.test_client.put("/put") + assert response.text == "OK" - request, response = app.test_client.get('/post') + request, response = app.test_client.get("/post") assert response.status == 405 - request, response = app.test_client.post('/post') - assert response.text == 'OK' + request, response = app.test_client.post("/post") + assert response.text == "OK" - request, response = app.test_client.get('/post') + request, response = app.test_client.get("/post") assert response.status == 405 - request, response = app.test_client.head('/head') + request, response = app.test_client.head("/head") assert response.status == 200 - request, response = app.test_client.get('/head') + request, response = app.test_client.get("/head") assert response.status == 405 - request, response = app.test_client.options('/options') - assert response.text == 'OK' + request, response = app.test_client.options("/options") + assert response.text == "OK" - request, response = app.test_client.get('/options') + request, response = app.test_client.get("/options") assert response.status == 405 - request, response = app.test_client.patch('/patch') - assert response.text == 'OK' + request, response = app.test_client.patch("/patch") + assert response.text == "OK" - request, response = app.test_client.get('/patch') + request, response = app.test_client.get("/patch") assert response.status == 405 - request, response = app.test_client.delete('/delete') - assert response.text == 'OK' + request, response = app.test_client.delete("/delete") + assert response.text == "OK" - request, response = app.test_client.get('/delete') + request, response = app.test_client.get("/delete") assert response.status == 405 - request, response = app.test_client.get('/ws/', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13'}) + request, response = app.test_client.get( + "/ws/", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + }, + ) assert response.status == 101 assert ev.is_set() def test_bp_group(app): - deep_0 = Blueprint('deep_0', url_prefix='/deep') - deep_1 = Blueprint('deep_1', url_prefix='/deep1') + deep_0 = Blueprint("deep_0", url_prefix="/deep") + deep_1 = Blueprint("deep_1", url_prefix="/deep1") - @deep_0.route('/') + @deep_0.route("/") def handler(request): - return text('D0_OK') + return text("D0_OK") - @deep_1.route('/bottom') + @deep_1.route("/bottom") def bottom_handler(request): - return text('D1B_OK') + return text("D1B_OK") - mid_0 = Blueprint.group(deep_0, deep_1, url_prefix='/mid') - mid_1 = Blueprint('mid_tier', url_prefix='/mid1') + mid_0 = Blueprint.group(deep_0, deep_1, url_prefix="/mid") + mid_1 = Blueprint("mid_tier", url_prefix="/mid1") - @mid_1.route('/') + @mid_1.route("/") def handler1(request): - return text('M1_OK') + return text("M1_OK") top = Blueprint.group(mid_0, mid_1) app.blueprint(top) - @app.route('/') + @app.route("/") def handler2(request): - return text('TOP_OK') + return text("TOP_OK") - request, response = app.test_client.get('/') - assert response.text == 'TOP_OK' + request, response = app.test_client.get("/") + assert response.text == "TOP_OK" - request, response = app.test_client.get('/mid1') - assert response.text == 'M1_OK' + request, response = app.test_client.get("/mid1") + assert response.text == "M1_OK" - request, response = app.test_client.get('/mid/deep') - assert response.text == 'D0_OK' + request, response = app.test_client.get("/mid/deep") + assert response.text == "D0_OK" - request, response = app.test_client.get('/mid/deep1/bottom') - assert response.text == 'D1B_OK' + request, response = app.test_client.get("/mid/deep1/bottom") + assert response.text == "D1B_OK" def test_bp_group_with_default_url_prefix(app): from sanic.response import json - bp_resources = Blueprint('bp_resources') - @bp_resources.get('/') + bp_resources = Blueprint("bp_resources") + + @bp_resources.get("/") def list_resources_handler(request): resource = {} return json([resource]) - bp_resource = Blueprint('bp_resource', url_prefix='/') + bp_resource = Blueprint("bp_resource", url_prefix="/") - @bp_resource.get('/') + @bp_resource.get("/") def get_resource_hander(request, resource_id): - resource = {'resource_id': resource_id} + resource = {"resource_id": resource_id} return json(resource) - bp_resources_group = Blueprint.group(bp_resources, bp_resource, - url_prefix='/resources') - bp_api_v1 = Blueprint('bp_api_v1') + bp_resources_group = Blueprint.group( + bp_resources, bp_resource, url_prefix="/resources" + ) + bp_api_v1 = Blueprint("bp_api_v1") - @bp_api_v1.get('/info') + @bp_api_v1.get("/info") def api_v1_info(request): - return text('api_version: v1') + return text("api_version: v1") - bp_api_v1_group = Blueprint.group(bp_api_v1, bp_resources_group, - url_prefix='/v1') - bp_api_group = Blueprint.group(bp_api_v1_group, url_prefix='/api') + bp_api_v1_group = Blueprint.group( + bp_api_v1, bp_resources_group, url_prefix="/v1" + ) + bp_api_group = Blueprint.group(bp_api_v1_group, url_prefix="/api") app.blueprint(bp_api_group) - request, response = app.test_client.get('/api/v1/info') - assert response.text == 'api_version: v1' + request, response = app.test_client.get("/api/v1/info") + assert response.text == "api_version: v1" - request, response = app.test_client.get('/api/v1/resources') + request, response = app.test_client.get("/api/v1/resources") assert response.json == [{}] from uuid import uuid4 + resource_id = str(uuid4()) request, response = app.test_client.get( - '/api/v1/resources/{0}'.format(resource_id)) - assert response.json == {'resource_id': resource_id} + "/api/v1/resources/{0}".format(resource_id) + ) + assert response.json == {"resource_id": resource_id} def test_blueprint_middleware_with_args(app: Sanic): @@ -588,19 +586,22 @@ def test_blueprint_middleware_with_args(app: Sanic): app.blueprint(bp) - _, response = app.test_client.get("/wa", headers={"content-type": "application/json"}) + _, response = app.test_client.get( + "/wa", headers={"content-type": "application/json"} + ) assert response.text == "value" - _, response = app.test_client.get("/wa", headers={"content-type": "plain/text"}) + _, response = app.test_client.get( + "/wa", headers={"content-type": "plain/text"} + ) assert response.json.get("test") == "value" d = {} -@pytest.mark.parametrize('file_name', - ['test.file']) +@pytest.mark.parametrize("file_name", ["test.file"]) def test_static_blueprint_name(app: Sanic, static_file_directory, file_name): current_file = inspect.getfile(inspect.currentframe()) - with open(current_file, 'rb') as file: + with open(current_file, "rb") as file: current_file_contents = file.read() bp = Blueprint(name="static", url_prefix="/static", strict_slashes=False) @@ -609,11 +610,12 @@ def test_static_blueprint_name(app: Sanic, static_file_directory, file_name): "/test.file/", get_file_path(static_file_directory, file_name), name="static.testing", - strict_slashes=True) + strict_slashes=True, + ) app.blueprint(bp) - uri = app.url_for('static', name='static.testing') + uri = app.url_for("static", name="static.testing") assert uri == "/static/test.file" _, response = app.test_client.get("/static/test.file") @@ -627,9 +629,7 @@ def test_route_handler_add(app: Sanic): view = CompositionView() async def get_handler(request): - return json({ - "response": "OK" - }) + return json({"response": "OK"}) view.add(["GET"], get_handler, stream=False) @@ -637,10 +637,7 @@ def test_route_handler_add(app: Sanic): return text("OK") bp = Blueprint(name="handler", url_prefix="/handler") - bp.add_route( - default_handler, - uri="/default/", - strict_slashes=True) + bp.add_route(default_handler, uri="/default/", strict_slashes=True) bp.add_route(view, uri="/view", name="test") @@ -665,18 +662,21 @@ def test_websocket_route(app: Sanic): app.blueprint(bp) - _, response = app.test_client.get("/ws/test", headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13' - }) + _, response = app.test_client.get( + "/ws/test", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + }, + ) assert response.status == 101 assert event.is_set() def test_duplicate_blueprint(app): - bp_name = 'bp' + bp_name = "bp" bp = Blueprint(bp_name) bp1 = Blueprint(bp_name) @@ -687,18 +687,18 @@ def test_duplicate_blueprint(app): assert str(excinfo.value) == ( 'A blueprint with the name "{}" is already registered. ' - 'Blueprint names must be unique.' + "Blueprint names must be unique." ).format(bp_name) -@pytest.mark.parametrize('debug', [True, False, None]) +@pytest.mark.parametrize("debug", [True, False, None]) def test_register_blueprint(app, debug): - bp = Blueprint('bp') + bp = Blueprint("bp") app.debug = debug with pytest.warns(DeprecationWarning) as record: app.register_blueprint(bp) - + assert record[0].message.args[0] == ( "Use of register_blueprint will be deprecated in " "version 1.0. Please use the blueprint method" diff --git a/tests/test_config.py b/tests/test_config.py index 8cac5dfc..c509b34c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -13,18 +13,18 @@ from sanic.exceptions import PyFileError def temp_path(): """ a simple cross platform replacement for NamedTemporaryFile """ with TemporaryDirectory() as td: - yield Path(td, 'file') + yield Path(td, "file") def test_load_from_object(app): class Config: - not_for_config = 'should not be used' - CONFIG_VALUE = 'should be used' + not_for_config = "should not be used" + CONFIG_VALUE = "should be used" app.config.from_object(Config) - assert 'CONFIG_VALUE' in app.config - assert app.config.CONFIG_VALUE == 'should be used' - assert 'not_for_config' not in app.config + assert "CONFIG_VALUE" in app.config + assert app.config.CONFIG_VALUE == "should be used" + assert "not_for_config" not in app.config def test_auto_load_env(): @@ -37,13 +37,13 @@ def test_auto_load_env(): def test_dont_load_env(): environ["SANIC_TEST_ANSWER"] = "42" app = Sanic(load_env=False) - assert getattr(app.config, 'TEST_ANSWER', None) is None + assert getattr(app.config, "TEST_ANSWER", None) is None del environ["SANIC_TEST_ANSWER"] def test_load_env_prefix(): environ["MYAPP_TEST_ANSWER"] = "42" - app = Sanic(load_env='MYAPP_') + app = Sanic(load_env="MYAPP_") assert app.config.TEST_ANSWER == 42 del environ["MYAPP_TEST_ANSWER"] @@ -63,43 +63,47 @@ def test_load_env_prefix_string_value(): def test_load_from_file(app): - config = dedent(""" + config = dedent( + """ VALUE = 'some value' condition = 1 == 1 if condition: CONDITIONAL = 'should be set' - """) + """ + ) with temp_path() as config_path: config_path.write_text(config) app.config.from_pyfile(str(config_path)) - assert 'VALUE' in app.config - assert app.config.VALUE == 'some value' - assert 'CONDITIONAL' in app.config - assert app.config.CONDITIONAL == 'should be set' - assert 'condition' not in app.config + assert "VALUE" in app.config + assert app.config.VALUE == "some value" + assert "CONDITIONAL" in app.config + assert app.config.CONDITIONAL == "should be set" + assert "condition" not in app.config def test_load_from_missing_file(app): with pytest.raises(IOError): - app.config.from_pyfile('non-existent file') + app.config.from_pyfile("non-existent file") def test_load_from_envvar(app): config = "VALUE = 'some value'" with temp_path() as config_path: config_path.write_text(config) - environ['APP_CONFIG'] = str(config_path) - app.config.from_envvar('APP_CONFIG') - assert 'VALUE' in app.config - assert app.config.VALUE == 'some value' + environ["APP_CONFIG"] = str(config_path) + app.config.from_envvar("APP_CONFIG") + assert "VALUE" in app.config + assert app.config.VALUE == "some value" def test_load_from_missing_envvar(app): with pytest.raises(RuntimeError) as e: - app.config.from_envvar('non-existent variable') - assert str(e.value) == ("The environment variable 'non-existent " - "variable' is not set and thus configuration " - "could not be loaded.") + app.config.from_envvar("non-existent variable") + assert str(e.value) == ( + "The environment variable 'non-existent " + "variable' is not set and thus configuration " + "could not be loaded." + ) def test_load_config_from_file_invalid_syntax(app): diff --git a/tests/test_cookies.py b/tests/test_cookies.py index 648135b6..4a7d4e18 100644 --- a/tests/test_cookies.py +++ b/tests/test_cookies.py @@ -8,109 +8,99 @@ from sanic.cookies import Cookie # GET # ------------------------------------------------------------ # + def test_cookies(app): - - @app.route('/') + @app.route("/") def handler(request): - response = text('Cookies are: {}'.format(request.cookies['test'])) - response.cookies['right_back'] = 'at you' + response = text("Cookies are: {}".format(request.cookies["test"])) + response.cookies["right_back"] = "at you" return response - request, response = app.test_client.get('/', cookies={"test": "working!"}) + request, response = app.test_client.get("/", cookies={"test": "working!"}) response_cookies = SimpleCookie() - response_cookies.load(response.headers.get('Set-Cookie', {})) + response_cookies.load(response.headers.get("Set-Cookie", {})) - assert response.text == 'Cookies are: working!' - assert response_cookies['right_back'].value == 'at you' + assert response.text == "Cookies are: working!" + assert response_cookies["right_back"].value == "at you" -@pytest.mark.parametrize("httponly,expected", [ - (False, False), - (True, True), -]) +@pytest.mark.parametrize("httponly,expected", [(False, False), (True, True)]) def test_false_cookies_encoded(app, httponly, expected): - - @app.route('/') + @app.route("/") def handler(request): - response = text('hello cookies') - response.cookies['hello'] = 'world' - response.cookies['hello']['httponly'] = httponly - return text(response.cookies['hello'].encode('utf8')) + response = text("hello cookies") + response.cookies["hello"] = "world" + response.cookies["hello"]["httponly"] = httponly + return text(response.cookies["hello"].encode("utf8")) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert ('HttpOnly' in response.text) == expected + assert ("HttpOnly" in response.text) == expected -@pytest.mark.parametrize("httponly,expected", [ - (False, False), - (True, True), -]) +@pytest.mark.parametrize("httponly,expected", [(False, False), (True, True)]) def test_false_cookies(app, httponly, expected): - - @app.route('/') + @app.route("/") def handler(request): - response = text('hello cookies') - response.cookies['right_back'] = 'at you' - response.cookies['right_back']['httponly'] = httponly + response = text("hello cookies") + response.cookies["right_back"] = "at you" + response.cookies["right_back"]["httponly"] = httponly return response - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") response_cookies = SimpleCookie() - response_cookies.load(response.headers.get('Set-Cookie', {})) + response_cookies.load(response.headers.get("Set-Cookie", {})) - assert ('HttpOnly' in response_cookies['right_back'].output()) == expected + assert ("HttpOnly" in response_cookies["right_back"].output()) == expected def test_http2_cookies(app): - - @app.route('/') + @app.route("/") async def handler(request): - response = text('Cookies are: {}'.format(request.cookies['test'])) + response = text("Cookies are: {}".format(request.cookies["test"])) return response - headers = {'cookie': 'test=working!'} - request, response = app.test_client.get('/', headers=headers) + headers = {"cookie": "test=working!"} + request, response = app.test_client.get("/", headers=headers) - assert response.text == 'Cookies are: working!' + assert response.text == "Cookies are: working!" def test_cookie_options(app): - - @app.route('/') + @app.route("/") def handler(request): response = text("OK") - response.cookies['test'] = 'at you' - response.cookies['test']['httponly'] = True - response.cookies['test']['expires'] = (datetime.now() + - timedelta(seconds=10)) + response.cookies["test"] = "at you" + response.cookies["test"]["httponly"] = True + response.cookies["test"]["expires"] = datetime.now() + timedelta( + seconds=10 + ) return response - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") response_cookies = SimpleCookie() - response_cookies.load(response.headers.get('Set-Cookie', {})) + response_cookies.load(response.headers.get("Set-Cookie", {})) - assert response_cookies['test'].value == 'at you' - assert response_cookies['test']['httponly'] is True + assert response_cookies["test"].value == "at you" + assert response_cookies["test"]["httponly"] is True def test_cookie_deletion(app): - - @app.route('/') + @app.route("/") def handler(request): response = text("OK") - del response.cookies['i_want_to_die'] - response.cookies['i_never_existed'] = 'testing' - del response.cookies['i_never_existed'] + del response.cookies["i_want_to_die"] + response.cookies["i_never_existed"] = "testing" + del response.cookies["i_never_existed"] return response - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") response_cookies = SimpleCookie() - response_cookies.load(response.headers.get('Set-Cookie', {})) + response_cookies.load(response.headers.get("Set-Cookie", {})) - assert int(response_cookies['i_want_to_die']['max-age']) == 0 + assert int(response_cookies["i_want_to_die"]["max-age"]) == 0 with pytest.raises(KeyError): - response.cookies['i_never_existed'] + response.cookies["i_never_existed"] def test_cookie_reserved_cookie(): @@ -134,58 +124,58 @@ def test_cookie_set_unknown_property(): def test_cookie_set_same_key(app): - cookies = {'test': 'wait'} + cookies = {"test": "wait"} - @app.get('/') + @app.get("/") def handler(request): - response = text('pass') - response.cookies['test'] = 'modified' - response.cookies['test'] = 'pass' + response = text("pass") + response.cookies["test"] = "modified" + response.cookies["test"] = "pass" return response - request, response = app.test_client.get('/', cookies=cookies) + request, response = app.test_client.get("/", cookies=cookies) assert response.status == 200 - assert response.cookies['test'].value == 'pass' + assert response.cookies["test"].value == "pass" -@pytest.mark.parametrize('max_age', ['0', 30, '30']) +@pytest.mark.parametrize("max_age", ["0", 30, "30"]) def test_cookie_max_age(app, max_age): - cookies = {'test': 'wait'} + cookies = {"test": "wait"} - @app.get('/') + @app.get("/") def handler(request): - response = text('pass') - response.cookies['test'] = 'pass' - response.cookies['test']['max-age'] = max_age + response = text("pass") + response.cookies["test"] = "pass" + response.cookies["test"]["max-age"] = max_age return response - request, response = app.test_client.get('/', cookies=cookies) + request, response = app.test_client.get("/", cookies=cookies) assert response.status == 200 - assert response.cookies['test'].value == 'pass' - assert response.cookies['test']['max-age'] == str(max_age) + assert response.cookies["test"].value == "pass" + assert response.cookies["test"]["max-age"] == str(max_age) -@pytest.mark.parametrize('expires', [ - datetime.now() + timedelta(seconds=60), - 'Fri, 21-Dec-2018 15:30:00 GMT' - ]) +@pytest.mark.parametrize( + "expires", + [datetime.now() + timedelta(seconds=60), "Fri, 21-Dec-2018 15:30:00 GMT"], +) def test_cookie_expires(app, expires): - cookies = {'test': 'wait'} + cookies = {"test": "wait"} - @app.get('/') + @app.get("/") def handler(request): - response = text('pass') - response.cookies['test'] = 'pass' - response.cookies['test']['expires'] = expires + response = text("pass") + response.cookies["test"] = "pass" + response.cookies["test"]["expires"] = expires return response - request, response = app.test_client.get('/', cookies=cookies) + request, response = app.test_client.get("/", cookies=cookies) assert response.status == 200 - assert response.cookies['test'].value == 'pass' + assert response.cookies["test"].value == "pass" if isinstance(expires, datetime): expires = expires.strftime("%a, %d-%b-%Y %T GMT") - assert response.cookies['test']['expires'] == expires + assert response.cookies["test"]["expires"] == expires diff --git a/tests/test_create_task.py b/tests/test_create_task.py index b90558ec..b1c0710a 100644 --- a/tests/test_create_task.py +++ b/tests/test_create_task.py @@ -13,26 +13,26 @@ def test_create_task(app): app.add_task(coro) - @app.route('/early') + @app.route("/early") def not_set(request): return text(e.is_set()) - @app.route('/late') + @app.route("/late") async def set(request): await asyncio.sleep(0.1) return text(e.is_set()) - request, response = app.test_client.get('/early') - assert response.body == b'False' + request, response = app.test_client.get("/early") + assert response.body == b"False" - request, response = app.test_client.get('/late') - assert response.body == b'True' + request, response = app.test_client.get("/late") + assert response.body == b"True" def test_create_task_with_app_arg(app): q = Queue() - @app.route('/') + @app.route("/") def not_set(request): return "hello" @@ -41,5 +41,5 @@ def test_create_task_with_app_arg(app): app.add_task(coro) - request, response = app.test_client.get('/') - assert q.get() == 'test_create_task_with_app_arg' + request, response = app.test_client.get("/") + assert q.get() == "test_create_task_with_app_arg" diff --git a/tests/test_custom_protocol.py b/tests/test_custom_protocol.py index 236eb831..e1e7d589 100644 --- a/tests/test_custom_protocol.py +++ b/tests/test_custom_protocol.py @@ -3,26 +3,19 @@ from sanic.response import text class CustomHttpProtocol(HttpProtocol): - def write_response(self, response): if isinstance(response, str): response = text(response) - self.transport.write( - response.output(self.request.version) - ) + self.transport.write(response.output(self.request.version)) self.transport.close() def test_use_custom_protocol(app): - - @app.route('/1') + @app.route("/1") async def handler_1(request): - return 'OK' + return "OK" - server_kwargs = { - 'protocol': CustomHttpProtocol - } - request, response = app.test_client.get( - '/1', server_kwargs=server_kwargs) + server_kwargs = {"protocol": CustomHttpProtocol} + request, response = app.test_client.get("/1", server_kwargs=server_kwargs) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" diff --git a/tests/test_dynamic_routes.py b/tests/test_dynamic_routes.py index 7aedbd62..e7b3729f 100644 --- a/tests/test_dynamic_routes.py +++ b/tests/test_dynamic_routes.py @@ -3,39 +3,41 @@ from sanic.router import RouteExists import pytest -@pytest.mark.parametrize("method,attr, expected", [ - ("get", "text", "OK1 test"), - ("post", "text", "OK2 test"), - ("put", "text", "OK2 test"), - ("delete", "status", 405), -]) +@pytest.mark.parametrize( + "method,attr, expected", + [ + ("get", "text", "OK1 test"), + ("post", "text", "OK2 test"), + ("put", "text", "OK2 test"), + ("delete", "status", 405), + ], +) def test_overload_dynamic_routes(app, method, attr, expected): - - @app.route('/overload/', methods=['GET']) + @app.route("/overload/", methods=["GET"]) async def handler1(request, param): - return text('OK1 ' + param) + return text("OK1 " + param) - @app.route('/overload/', methods=['POST', 'PUT']) + @app.route("/overload/", methods=["POST", "PUT"]) async def handler2(request, param): - return text('OK2 ' + param) + return text("OK2 " + param) - request, response = getattr(app.test_client, method)('/overload/test') + request, response = getattr(app.test_client, method)("/overload/test") assert getattr(response, attr) == expected def test_overload_dynamic_routes_exist(app): - - @app.route('/overload/', methods=['GET']) + @app.route("/overload/", methods=["GET"]) async def handler1(request, param): - return text('OK1 ' + param) + return text("OK1 " + param) - @app.route('/overload/', methods=['POST', 'PUT']) + @app.route("/overload/", methods=["POST", "PUT"]) async def handler2(request, param): - return text('OK2 ' + param) + return text("OK2 " + param) # if this doesn't raise an error, than at least the below should happen: # assert response.text == 'Duplicated' with pytest.raises(RouteExists): - @app.route('/overload/', methods=['PUT', 'DELETE']) + + @app.route("/overload/", methods=["PUT", "DELETE"]) async def handler3(request): - return text('Duplicated') + return text("Duplicated") diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 6aa4bcb6..5a2f0f8f 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -11,72 +11,74 @@ class SanicExceptionTestException(Exception): pass -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def exception_app(): - app = Sanic('test_exceptions') + app = Sanic("test_exceptions") - @app.route('/') + @app.route("/") def handler(request): - return text('OK') + return text("OK") - @app.route('/error') + @app.route("/error") def handler_error(request): raise ServerError("OK") - @app.route('/404') + @app.route("/404") def handler_404(request): raise NotFound("OK") - @app.route('/403') + @app.route("/403") def handler_403(request): raise Forbidden("Forbidden") - @app.route('/401') + @app.route("/401") def handler_401(request): raise Unauthorized("Unauthorized") - @app.route('/401/basic') + @app.route("/401/basic") def handler_401_basic(request): raise Unauthorized("Unauthorized", scheme="Basic", realm="Sanic") - @app.route('/401/digest') + @app.route("/401/digest") def handler_401_digest(request): - raise Unauthorized("Unauthorized", - scheme="Digest", - realm="Sanic", - qop="auth, auth-int", - algorithm="MD5", - nonce="abcdef", - opaque="zyxwvu") + raise Unauthorized( + "Unauthorized", + scheme="Digest", + realm="Sanic", + qop="auth, auth-int", + algorithm="MD5", + nonce="abcdef", + opaque="zyxwvu", + ) - @app.route('/401/bearer') + @app.route("/401/bearer") def handler_401_bearer(request): raise Unauthorized("Unauthorized", scheme="Bearer") - @app.route('/invalid') + @app.route("/invalid") def handler_invalid(request): raise InvalidUsage("OK") - @app.route('/abort/401') + @app.route("/abort/401") def handler_401_error(request): abort(401) - @app.route('/abort') + @app.route("/abort") def handler_500_error(request): abort(500) return text("OK") - @app.route('/abort/message') + @app.route("/abort/message") def handler_abort_message(request): - abort(500, message='Abort') + abort(500, message="Abort") - @app.route('/divide_by_zero') + @app.route("/divide_by_zero") def handle_unhandled_exception(request): 1 / 0 - @app.route('/error_in_error_handler_handler') + @app.route("/error_in_error_handler_handler") def custom_error_handler(request): - raise SanicExceptionTestException('Dummy message!') + raise SanicExceptionTestException("Dummy message!") @app.exception(SanicExceptionTestException) def error_in_error_handler_handler(request, exception): @@ -86,126 +88,127 @@ def exception_app(): def test_catch_exception_list(app): - @app.exception([SanicExceptionTestException, NotFound]) def exception_list(request, exception): return text("ok") - @app.route('/') + @app.route("/") def exception(request): raise SanicExceptionTestException("You won't see me") - request, response = app.test_client.get('/random') - assert response.text == 'ok' + request, response = app.test_client.get("/random") + assert response.text == "ok" - request, response = app.test_client.get('/') - assert response.text == 'ok' + request, response = app.test_client.get("/") + assert response.text == "ok" def test_no_exception(exception_app): """Test that a route works without an exception""" - request, response = exception_app.test_client.get('/') + request, response = exception_app.test_client.get("/") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_server_error_exception(exception_app): """Test the built-in ServerError exception works""" - request, response = exception_app.test_client.get('/error') + request, response = exception_app.test_client.get("/error") assert response.status == 500 def test_invalid_usage_exception(exception_app): """Test the built-in InvalidUsage exception works""" - request, response = exception_app.test_client.get('/invalid') + request, response = exception_app.test_client.get("/invalid") assert response.status == 400 def test_not_found_exception(exception_app): """Test the built-in NotFound exception works""" - request, response = exception_app.test_client.get('/404') + request, response = exception_app.test_client.get("/404") assert response.status == 404 def test_forbidden_exception(exception_app): """Test the built-in Forbidden exception""" - request, response = exception_app.test_client.get('/403') + request, response = exception_app.test_client.get("/403") assert response.status == 403 def test_unauthorized_exception(exception_app): """Test the built-in Unauthorized exception""" - request, response = exception_app.test_client.get('/401') + request, response = exception_app.test_client.get("/401") assert response.status == 401 - request, response = exception_app.test_client.get('/401/basic') + request, response = exception_app.test_client.get("/401/basic") assert response.status == 401 - assert response.headers.get('WWW-Authenticate') is not None - assert response.headers.get('WWW-Authenticate') == 'Basic realm="Sanic"' + assert response.headers.get("WWW-Authenticate") is not None + assert response.headers.get("WWW-Authenticate") == 'Basic realm="Sanic"' - request, response = exception_app.test_client.get('/401/digest') + request, response = exception_app.test_client.get("/401/digest") assert response.status == 401 - auth_header = response.headers.get('WWW-Authenticate') + auth_header = response.headers.get("WWW-Authenticate") assert auth_header is not None - assert auth_header.startswith('Digest') + assert auth_header.startswith("Digest") assert 'qop="auth, auth-int"' in auth_header assert 'algorithm="MD5"' in auth_header assert 'nonce="abcdef"' in auth_header assert 'opaque="zyxwvu"' in auth_header - request, response = exception_app.test_client.get('/401/bearer') + request, response = exception_app.test_client.get("/401/bearer") assert response.status == 401 - assert response.headers.get('WWW-Authenticate') == "Bearer" + assert response.headers.get("WWW-Authenticate") == "Bearer" def test_handled_unhandled_exception(exception_app): """Test that an exception not built into sanic is handled""" - request, response = exception_app.test_client.get('/divide_by_zero') + request, response = exception_app.test_client.get("/divide_by_zero") assert response.status == 500 - soup = BeautifulSoup(response.body, 'html.parser') - assert soup.h1.text == 'Internal Server Error' + soup = BeautifulSoup(response.body, "html.parser") + assert soup.h1.text == "Internal Server Error" message = " ".join(soup.p.text.split()) assert message == ( "The server encountered an internal error and " - "cannot complete your request.") + "cannot complete your request." + ) def test_exception_in_exception_handler(exception_app): """Test that an exception thrown in an error handler is handled""" request, response = exception_app.test_client.get( - '/error_in_error_handler_handler') + "/error_in_error_handler_handler" + ) assert response.status == 500 - assert response.body == b'An error occurred while handling an error' + assert response.body == b"An error occurred while handling an error" def test_exception_in_exception_handler_debug_off(exception_app): """Test that an exception thrown in an error handler is handled""" request, response = exception_app.test_client.get( - '/error_in_error_handler_handler', - debug=False) + "/error_in_error_handler_handler", debug=False + ) assert response.status == 500 - assert response.body == b'An error occurred while handling an error' + assert response.body == b"An error occurred while handling an error" def test_exception_in_exception_handler_debug_on(exception_app): """Test that an exception thrown in an error handler is handled""" request, response = exception_app.test_client.get( - '/error_in_error_handler_handler', - debug=True) + "/error_in_error_handler_handler", debug=True + ) assert response.status == 500 - assert response.body.startswith(b'Exception raised in exception ') + assert response.body.startswith(b"Exception raised in exception ") def test_abort(exception_app): """Test the abort function""" - request, response = exception_app.test_client.get('/abort/401') + request, response = exception_app.test_client.get("/abort/401") assert response.status == 401 - request, response = exception_app.test_client.get('/abort') + request, response = exception_app.test_client.get("/abort") assert response.status == 500 - request, response = exception_app.test_client.get('/abort/message') + request, response = exception_app.test_client.get("/abort/message") assert response.status == 500 - assert response.text == 'Error: Abort' + assert response.text == "Error: Abort" diff --git a/tests/test_exceptions_handler.py b/tests/test_exceptions_handler.py index 214bcb50..aae99bf9 100644 --- a/tests/test_exceptions_handler.py +++ b/tests/test_exceptions_handler.py @@ -4,38 +4,39 @@ from sanic.exceptions import InvalidUsage, ServerError, NotFound from sanic.handlers import ErrorHandler from bs4 import BeautifulSoup -exception_handler_app = Sanic('test_exception_handler') +exception_handler_app = Sanic("test_exception_handler") -@exception_handler_app.route('/1') +@exception_handler_app.route("/1") def handler_1(request): raise InvalidUsage("OK") -@exception_handler_app.route('/2') +@exception_handler_app.route("/2") def handler_2(request): raise ServerError("OK") -@exception_handler_app.route('/3') +@exception_handler_app.route("/3") def handler_3(request): raise NotFound("OK") -@exception_handler_app.route('/4') +@exception_handler_app.route("/4") def handler_4(request): - foo = bar # noqa -- F821 undefined name 'bar' is done to throw exception + foo = bar # noqa -- F821 undefined name 'bar' is done to throw exception return text(foo) -@exception_handler_app.route('/5') +@exception_handler_app.route("/5") def handler_5(request): class CustomServerError(ServerError): pass - raise CustomServerError('Custom server error') + + raise CustomServerError("Custom server error") -@exception_handler_app.route('/6/') +@exception_handler_app.route("/6/") def handler_6(request, arg): try: foo = 1 / arg @@ -50,67 +51,67 @@ def handler_exception(request, exception): def test_invalid_usage_exception_handler(): - request, response = exception_handler_app.test_client.get('/1') + request, response = exception_handler_app.test_client.get("/1") assert response.status == 400 def test_server_error_exception_handler(): - request, response = exception_handler_app.test_client.get('/2') + request, response = exception_handler_app.test_client.get("/2") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_not_found_exception_handler(): - request, response = exception_handler_app.test_client.get('/3') + request, response = exception_handler_app.test_client.get("/3") assert response.status == 200 def test_text_exception__handler(): - request, response = exception_handler_app.test_client.get('/random') + request, response = exception_handler_app.test_client.get("/random") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_html_traceback_output_in_debug_mode(): - request, response = exception_handler_app.test_client.get( - '/4', debug=True) + request, response = exception_handler_app.test_client.get("/4", debug=True) assert response.status == 500 - soup = BeautifulSoup(response.body, 'html.parser') + soup = BeautifulSoup(response.body, "html.parser") html = str(soup) - assert 'response = handler(request, *args, **kwargs)' in html - assert 'handler_4' in html - assert 'foo = bar' in html + assert "response = handler(request, *args, **kwargs)" in html + assert "handler_4" in html + assert "foo = bar" in html - summary_text = " ".join(soup.select('.summary')[0].text.split()) + summary_text = " ".join(soup.select(".summary")[0].text.split()) assert ( - "NameError: name 'bar' " - "is not defined while handling path /4") == summary_text + "NameError: name 'bar' " "is not defined while handling path /4" + ) == summary_text def test_inherited_exception_handler(): - request, response = exception_handler_app.test_client.get('/5') + request, response = exception_handler_app.test_client.get("/5") assert response.status == 200 def test_chained_exception_handler(): request, response = exception_handler_app.test_client.get( - '/6/0', debug=True) + "/6/0", debug=True + ) assert response.status == 500 - soup = BeautifulSoup(response.body, 'html.parser') + soup = BeautifulSoup(response.body, "html.parser") html = str(soup) - assert 'response = handler(request, *args, **kwargs)' in html - assert 'handler_6' in html - assert 'foo = 1 / arg' in html - assert 'ValueError' in html - assert 'The above exception was the direct cause' in html + assert "response = handler(request, *args, **kwargs)" in html + assert "handler_6" in html + assert "foo = 1 / arg" in html + assert "ValueError" in html + assert "The above exception was the direct cause" in html - summary_text = " ".join(soup.select('.summary')[0].text.split()) + summary_text = " ".join(soup.select(".summary")[0].text.split()) assert ( - "ZeroDivisionError: division by zero " - "while handling path /6/0") == summary_text + "ZeroDivisionError: division by zero " "while handling path /6/0" + ) == summary_text def test_exception_handler_lookup(): @@ -132,6 +133,7 @@ def test_exception_handler_lookup(): try: ModuleNotFoundError except Exception: + class ModuleNotFoundError(ImportError): pass @@ -143,12 +145,12 @@ def test_exception_handler_lookup(): assert handler.lookup(ImportError()) == import_error_handler assert handler.lookup(ModuleNotFoundError()) == import_error_handler assert handler.lookup(CustomError()) == custom_error_handler - assert handler.lookup(ServerError('Error')) == server_error_handler - assert handler.lookup(CustomServerError('Error')) == server_error_handler + assert handler.lookup(ServerError("Error")) == server_error_handler + assert handler.lookup(CustomServerError("Error")) == server_error_handler # once again to ensure there is no caching bug assert handler.lookup(ImportError()) == import_error_handler assert handler.lookup(ModuleNotFoundError()) == import_error_handler assert handler.lookup(CustomError()) == custom_error_handler - assert handler.lookup(ServerError('Error')) == server_error_handler - assert handler.lookup(CustomServerError('Error')) == server_error_handler + assert handler.lookup(ServerError("Error")) == server_error_handler + assert handler.lookup(CustomServerError("Error")) == server_error_handler diff --git a/tests/test_helpers.py b/tests/test_helpers.py index b5f6dd16..7e7c6ddb 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -38,35 +38,19 @@ def test_is_hop_by_hop_header(): def test_remove_entity_headers(): tests = ( - ( - {}, - {} - ), - ( - { - "Allow": "GET, POST, HEAD", - }, - {} - ), + ({}, {}), + ({"Allow": "GET, POST, HEAD"}, {}), ( { "Content-Type": "application/json", "Expires": "Wed, 21 Oct 2015 07:28:00 GMT", - "Foo": "Bar" - }, - { - "Expires": "Wed, 21 Oct 2015 07:28:00 GMT", - "Foo": "Bar" + "Foo": "Bar", }, + {"Expires": "Wed, 21 Oct 2015 07:28:00 GMT", "Foo": "Bar"}, ), ( - { - "Allow": "GET, POST, HEAD", - "Content-Location": "/test" - }, - { - "Content-Location": "/test" - }, + {"Allow": "GET, POST, HEAD", "Content-Location": "/test"}, + {"Content-Location": "/test"}, ), ) diff --git a/tests/test_keep_alive_timeout.py b/tests/test_keep_alive_timeout.py index b486b76d..d928a0ea 100644 --- a/tests/test_keep_alive_timeout.py +++ b/tests/test_keep_alive_timeout.py @@ -16,12 +16,14 @@ class ReuseableTCPConnector(TCPConnector): self.old_proto = None async def connect(self, req, *args, **kwargs): - new_conn = await super(ReuseableTCPConnector, self)\ - .connect(req, *args, **kwargs) + new_conn = await super(ReuseableTCPConnector, self).connect( + req, *args, **kwargs + ) if self.old_proto is not None: if self.old_proto != new_conn._protocol: raise RuntimeError( - "We got a new connection, wanted the same one!") + "We got a new connection, wanted the same one!" + ) print(new_conn.__dict__) self.old_proto = new_conn._protocol return new_conn @@ -40,31 +42,39 @@ class ReuseableSanicTestClient(SanicTestClient): # Copied from SanicTestClient, but with some changes to reuse the # same loop for the same app. def _sanic_endpoint_test( - self, method='get', uri='/', gather_request=True, - debug=False, server_kwargs={}, - *request_args, **request_kwargs): + self, + method="get", + uri="/", + gather_request=True, + debug=False, + server_kwargs={}, + *request_args, + **request_kwargs + ): loop = self._loop results = [None, None] exceptions = [] - do_kill_server = request_kwargs.pop('end_server', False) + do_kill_server = request_kwargs.pop("end_server", False) if gather_request: + def _collect_request(request): if results[0] is None: results[0] = request self.app.request_middleware.appendleft(_collect_request) - @self.app.listener('after_server_start') + @self.app.listener("after_server_start") async def _collect_response(loop): try: if do_kill_server: - request_kwargs['end_session'] = True + request_kwargs["end_session"] = True response = await self._local_request( - method, uri, *request_args, - **request_kwargs) + method, uri, *request_args, **request_kwargs + ) results[-1] = response except Exception as e2: import traceback + traceback.print_tb(e2.__traceback__) exceptions.append(e2) # Don't stop here! self.app.stop() @@ -72,23 +82,25 @@ class ReuseableSanicTestClient(SanicTestClient): if self._server is not None: _server = self._server else: - _server_co = self.app.create_server(host=HOST, debug=debug, - port=PORT, **server_kwargs) + _server_co = self.app.create_server( + host=HOST, debug=debug, port=PORT, **server_kwargs + ) server.trigger_events( - self.app.listeners['before_server_start'], loop) + self.app.listeners["before_server_start"], loop + ) try: loop._stopping = False http_server = loop.run_until_complete(_server_co) except Exception as e1: import traceback + traceback.print_tb(e1.__traceback__) raise e1 self._server = _server = http_server - server.trigger_events( - self.app.listeners['after_server_start'], loop) - self.app.listeners['after_server_start'].pop() + server.trigger_events(self.app.listeners["after_server_start"], loop) + self.app.listeners["after_server_start"].pop() if do_kill_server: try: @@ -98,11 +110,11 @@ class ReuseableSanicTestClient(SanicTestClient): self.app.stop() except Exception as e3: import traceback + traceback.print_tb(e3.__traceback__) exceptions.append(e3) if exceptions: - raise ValueError( - "Exception during request: {}".format(exceptions)) + raise ValueError("Exception during request: {}".format(exceptions)) if gather_request: self.app.request_middleware.pop() @@ -112,28 +124,32 @@ class ReuseableSanicTestClient(SanicTestClient): except Exception: raise ValueError( "Request and response object expected, got ({})".format( - results)) + results + ) + ) else: try: return results[-1] except Exception: raise ValueError( - "Request object expected, got ({})".format(results)) + "Request object expected, got ({})".format(results) + ) # Copied from SanicTestClient, but with some changes to reuse the # same TCPConnection and the sane ClientSession more than once. # Note, you cannot use the same session if you are in a _different_ # loop, so the changes above are required too. - async def _local_request(self, method, uri, cookies=None, *args, - **kwargs): - request_keepalive = kwargs.pop('request_keepalive', - Config.KEEP_ALIVE_TIMEOUT) - if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://' '//')): + async def _local_request(self, method, uri, cookies=None, *args, **kwargs): + request_keepalive = kwargs.pop( + "request_keepalive", Config.KEEP_ALIVE_TIMEOUT + ) + if uri.startswith(("http:", "https:", "ftp:", "ftps://" "//")): url = uri else: - url = 'http://{host}:{port}{uri}'.format( - host=HOST, port=self.port, uri=uri) - do_kill_session = kwargs.pop('end_session', False) + url = "http://{host}:{port}{uri}".format( + host=HOST, port=self.port, uri=uri + ) + do_kill_session = kwargs.pop("end_session", False) if self._session: session = self._session else: @@ -143,16 +159,17 @@ class ReuseableSanicTestClient(SanicTestClient): conn = ReuseableTCPConnector( verify_ssl=False, loop=self._loop, - keepalive_timeout=request_keepalive + keepalive_timeout=request_keepalive, ) self._tcp_connector = conn - session = aiohttp.ClientSession(cookies=cookies, - connector=conn, - loop=self._loop) + session = aiohttp.ClientSession( + cookies=cookies, connector=conn, loop=self._loop + ) self._session = session async with getattr(session, method.lower())( - url, *args, **kwargs) as response: + url, *args, **kwargs + ) as response: try: response.text = await response.text() except UnicodeDecodeError: @@ -160,9 +177,11 @@ class ReuseableSanicTestClient(SanicTestClient): try: response.json = await response.json() - except (JSONDecodeError, - UnicodeDecodeError, - aiohttp.ClientResponseError): + except ( + JSONDecodeError, + UnicodeDecodeError, + aiohttp.ClientResponseError, + ): response.json = None response.body = await response.read() @@ -174,24 +193,24 @@ class ReuseableSanicTestClient(SanicTestClient): Config.KEEP_ALIVE_TIMEOUT = 2 Config.KEEP_ALIVE = True -keep_alive_timeout_app_reuse = Sanic('test_ka_timeout_reuse') -keep_alive_app_client_timeout = Sanic('test_ka_client_timeout') -keep_alive_app_server_timeout = Sanic('test_ka_server_timeout') +keep_alive_timeout_app_reuse = Sanic("test_ka_timeout_reuse") +keep_alive_app_client_timeout = Sanic("test_ka_client_timeout") +keep_alive_app_server_timeout = Sanic("test_ka_server_timeout") -@keep_alive_timeout_app_reuse.route('/1') +@keep_alive_timeout_app_reuse.route("/1") async def handler1(request): - return text('OK') + return text("OK") -@keep_alive_app_client_timeout.route('/1') +@keep_alive_app_client_timeout.route("/1") async def handler2(request): - return text('OK') + return text("OK") -@keep_alive_app_server_timeout.route('/1') +@keep_alive_app_server_timeout.route("/1") async def handler3(request): - return text('OK') + return text("OK") def test_keep_alive_timeout_reuse(): @@ -201,16 +220,14 @@ def test_keep_alive_timeout_reuse(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) client = ReuseableSanicTestClient(keep_alive_timeout_app_reuse, loop) - headers = { - 'Connection': 'keep-alive' - } - request, response = client.get('/1', headers=headers) + headers = {"Connection": "keep-alive"} + request, response = client.get("/1", headers=headers) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" loop.run_until_complete(aio_sleep(1)) - request, response = client.get('/1', end_server=True) + request, response = client.get("/1", end_server=True) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_keep_alive_client_timeout(): @@ -218,20 +235,17 @@ def test_keep_alive_client_timeout(): keep-alive timeout, client will try to create a new connection here.""" loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - client = ReuseableSanicTestClient(keep_alive_app_client_timeout, - loop) - headers = { - 'Connection': 'keep-alive' - } - request, response = client.get('/1', headers=headers, - request_keepalive=1) + client = ReuseableSanicTestClient(keep_alive_app_client_timeout, loop) + headers = {"Connection": "keep-alive"} + request, response = client.get("/1", headers=headers, request_keepalive=1) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" loop.run_until_complete(aio_sleep(2)) exception = None try: - request, response = client.get('/1', end_server=True, - request_keepalive=1) + request, response = client.get( + "/1", end_server=True, request_keepalive=1 + ) except ValueError as e: exception = e assert exception is not None @@ -246,23 +260,22 @@ def test_keep_alive_server_timeout(): broken server connection.""" loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) - client = ReuseableSanicTestClient(keep_alive_app_server_timeout, - loop) - headers = { - 'Connection': 'keep-alive' - } - request, response = client.get('/1', headers=headers, - request_keepalive=60) + client = ReuseableSanicTestClient(keep_alive_app_server_timeout, loop) + headers = {"Connection": "keep-alive"} + request, response = client.get("/1", headers=headers, request_keepalive=60) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" loop.run_until_complete(aio_sleep(3)) exception = None try: - request, response = client.get('/1', request_keepalive=60, - end_server=True) + request, response = client.get( + "/1", request_keepalive=60, end_server=True + ) except ValueError as e: exception = e assert exception is not None assert isinstance(exception, ValueError) - assert "Connection reset" in exception.args[0] or \ - "got a new connection" in exception.args[0] + assert ( + "Connection reset" in exception.args[0] + or "got a new connection" in exception.args[0] + ) diff --git a/tests/test_logging.py b/tests/test_logging.py index 3dabc7f0..b13532b2 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -14,9 +14,9 @@ from sanic import Sanic from sanic.log import logger -logging_format = '''module: %(module)s; \ +logging_format = """module: %(module)s; \ function: %(funcName)s(); \ -message: %(message)s''' +message: %(message)s""" def reset_logging(): @@ -29,19 +29,17 @@ def test_log(app): for handler in logging.root.handlers[:]: logging.root.removeHandler(handler) logging.basicConfig( - format=logging_format, - level=logging.DEBUG, - stream=log_stream + format=logging_format, level=logging.DEBUG, stream=log_stream ) log = logging.getLogger() rand_string = str(uuid.uuid4()) - @app.route('/') + @app.route("/") def handler(request): log.info(rand_string) - return text('hello') + return text("hello") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") log_text = log_stream.getvalue() assert rand_string in log_text @@ -50,59 +48,80 @@ def test_logging_defaults(): # reset_logging() app = Sanic("test_logging") - for fmt in [h.formatter for h in logging.getLogger('sanic.root').handlers]: - assert fmt._fmt == LOGGING_CONFIG_DEFAULTS['formatters']['generic']['format'] + for fmt in [h.formatter for h in logging.getLogger("sanic.root").handlers]: + assert ( + fmt._fmt + == LOGGING_CONFIG_DEFAULTS["formatters"]["generic"]["format"] + ) - for fmt in [h.formatter for h in logging.getLogger('sanic.error').handlers]: - assert fmt._fmt == LOGGING_CONFIG_DEFAULTS['formatters']['generic']['format'] + for fmt in [ + h.formatter for h in logging.getLogger("sanic.error").handlers + ]: + assert ( + fmt._fmt + == LOGGING_CONFIG_DEFAULTS["formatters"]["generic"]["format"] + ) - for fmt in [h.formatter for h in logging.getLogger('sanic.access').handlers]: - assert fmt._fmt == LOGGING_CONFIG_DEFAULTS['formatters']['access']['format'] + for fmt in [ + h.formatter for h in logging.getLogger("sanic.access").handlers + ]: + assert ( + fmt._fmt + == LOGGING_CONFIG_DEFAULTS["formatters"]["access"]["format"] + ) def test_logging_pass_customer_logconfig(): # reset_logging() modified_config = LOGGING_CONFIG_DEFAULTS - modified_config['formatters']['generic']['format'] = '%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s' - modified_config['formatters']['access']['format'] = '%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s' + modified_config["formatters"]["generic"][ + "format" + ] = "%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s" + modified_config["formatters"]["access"][ + "format" + ] = "%(asctime)s - (%(name)s)[%(levelname)s]: %(message)s" app = Sanic("test_logging", log_config=modified_config) - for fmt in [h.formatter for h in logging.getLogger('sanic.root').handlers]: - assert fmt._fmt == modified_config['formatters']['generic']['format'] + for fmt in [h.formatter for h in logging.getLogger("sanic.root").handlers]: + assert fmt._fmt == modified_config["formatters"]["generic"]["format"] - for fmt in [h.formatter for h in logging.getLogger('sanic.error').handlers]: - assert fmt._fmt == modified_config['formatters']['generic']['format'] + for fmt in [ + h.formatter for h in logging.getLogger("sanic.error").handlers + ]: + assert fmt._fmt == modified_config["formatters"]["generic"]["format"] - for fmt in [h.formatter for h in logging.getLogger('sanic.access').handlers]: - assert fmt._fmt == modified_config['formatters']['access']['format'] + for fmt in [ + h.formatter for h in logging.getLogger("sanic.access").handlers + ]: + assert fmt._fmt == modified_config["formatters"]["access"]["format"] -@pytest.mark.parametrize('debug', (True, False, )) +@pytest.mark.parametrize("debug", (True, False)) def test_log_connection_lost(app, debug, monkeypatch): """ Should not log Connection lost exception on non debug """ stream = StringIO() - root = logging.getLogger('sanic.root') + root = logging.getLogger("sanic.root") root.addHandler(logging.StreamHandler(stream)) - monkeypatch.setattr(sanic.server, 'logger', root) + monkeypatch.setattr(sanic.server, "logger", root) - @app.route('/conn_lost') + @app.route("/conn_lost") async def conn_lost(request): - response = text('Ok') + response = text("Ok") response.output = Mock(side_effect=RuntimeError) return response with pytest.raises(ValueError): # catch ValueError: Exception during request - app.test_client.get('/conn_lost', debug=debug) + app.test_client.get("/conn_lost", debug=debug) log = stream.getvalue() if debug: - assert 'Connection lost before response written @' in log + assert "Connection lost before response written @" in log else: - assert 'Connection lost before response written @' not in log + assert "Connection lost before response written @" not in log def test_logger(caplog): @@ -110,26 +129,38 @@ def test_logger(caplog): app = Sanic() - @app.get('/') + @app.get("/") def log_info(request): logger.info(rand_string) - return text('hello') + return text("hello") with caplog.at_level(logging.INFO): - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert caplog.record_tuples[0] == ('sanic.root', logging.INFO, 'Goin\' Fast @ http://127.0.0.1:42101') - assert caplog.record_tuples[1] == ('sanic.root', logging.INFO, 'http://127.0.0.1:42101/') - assert caplog.record_tuples[2] == ('sanic.root', logging.INFO, rand_string) - assert caplog.record_tuples[-1] == ('sanic.root', logging.INFO, 'Server Stopped') + assert caplog.record_tuples[0] == ( + "sanic.root", + logging.INFO, + "Goin' Fast @ http://127.0.0.1:42101", + ) + assert caplog.record_tuples[1] == ( + "sanic.root", + logging.INFO, + "http://127.0.0.1:42101/", + ) + assert caplog.record_tuples[2] == ("sanic.root", logging.INFO, rand_string) + assert caplog.record_tuples[-1] == ( + "sanic.root", + logging.INFO, + "Server Stopped", + ) def test_logging_modified_root_logger_config(): # reset_logging() modified_config = LOGGING_CONFIG_DEFAULTS - modified_config['loggers']['sanic.root']['level'] = 'DEBUG' + modified_config["loggers"]["sanic.root"]["level"] = "DEBUG" app = Sanic("test_logging", log_config=modified_config) - assert logging.getLogger('sanic.root').getEffectiveLevel() == logging.DEBUG + assert logging.getLogger("sanic.root").getEffectiveLevel() == logging.DEBUG diff --git a/tests/test_logo.py b/tests/test_logo.py new file mode 100644 index 00000000..3f39bf3d --- /dev/null +++ b/tests/test_logo.py @@ -0,0 +1,60 @@ +import logging +import asyncio +import pytest + +from sanic.config import BASE_LOGO + + +@pytest.fixture +def server(app): + server = app.create_server(debug=True) + loop = asyncio.get_event_loop() + task = asyncio.ensure_future(server) + return loop, task + + +def test_logo_base(app, server, caplog): + loop, task = server + with caplog.at_level(logging.DEBUG): + runner = loop.run_until_complete(task) + runner.close() + + assert caplog.record_tuples[0] == ("sanic.root", logging.DEBUG, BASE_LOGO) + + +def test_logo_false(app, server, caplog): + app.config.LOGO = False + loop, task = server + with caplog.at_level(logging.DEBUG): + runner = loop.run_until_complete(task) + runner.close() + + assert caplog.record_tuples[0] == ( + "sanic.root", + logging.INFO, + "Goin' Fast @ http://127.0.0.1:8000", + ) + + +def test_logo_true(app, server, caplog): + app.config.LOGO = True + loop, task = server + with caplog.at_level(logging.DEBUG): + runner = loop.run_until_complete(task) + runner.close() + + assert caplog.record_tuples[0] == ("sanic.root", logging.DEBUG, BASE_LOGO) + + +def test_logo_custom(app, server, caplog): + app.config.LOGO = "My Custom Logo" + loop, task = server + with caplog.at_level(logging.DEBUG): + runner = loop.run_until_complete(task) + runner.close() + + assert caplog.record_tuples[0] == ( + "sanic.root", + logging.DEBUG, + "My Custom Logo", + ) diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 4ff142e5..1d0c3e83 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -9,6 +9,7 @@ from sanic.response import HTTPResponse, text # GET # ------------------------------------------------------------ # + def test_middleware_request(app): results = [] @@ -16,168 +17,164 @@ def test_middleware_request(app): async def handler1(request): results.append(request) - @app.route('/') + @app.route("/") async def handler2(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == 'OK' + assert response.text == "OK" assert type(results[0]) is Request def test_middleware_response(app): results = [] - @app.middleware('request') + @app.middleware("request") async def process_request(request): results.append(request) - @app.middleware('response') + @app.middleware("response") async def process_response(request, response): results.append(request) results.append(response) - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == 'OK' + assert response.text == "OK" assert type(results[0]) is Request assert type(results[1]) is Request assert isinstance(results[2], HTTPResponse) def test_middleware_response_exception(app): - result = {'status_code': None} + result = {"status_code": None} - @app.middleware('response') + @app.middleware("response") async def process_response(request, response): - result['status_code'] = response.status + result["status_code"] = response.status return response @app.exception(NotFound) async def error_handler(request, exception): - return text('OK', exception.status_code) + return text("OK", exception.status_code) - @app.route('/') + @app.route("/") async def handler(request): - return text('FAIL') + return text("FAIL") - request, response = app.test_client.get('/page_not_found') - assert response.text == 'OK' - assert result['status_code'] == 404 + request, response = app.test_client.get("/page_not_found") + assert response.text == "OK" + assert result["status_code"] == 404 def test_middleware_response_raise_cancelled_error(app, caplog): - - @app.middleware('response') + @app.middleware("response") async def process_response(request, response): - raise CancelledError('CancelledError at response middleware') + raise CancelledError("CancelledError at response middleware") - @app.get('/') + @app.get("/") def handler(request): - return text('OK') + return text("OK") with caplog.at_level(logging.ERROR): - reqrequest, response = app.test_client.get('/') + reqrequest, response = app.test_client.get("/") assert response.status == 503 assert caplog.record_tuples[0] == ( - 'sanic.root', + "sanic.root", logging.ERROR, - 'Exception occurred while handling uri: \'http://127.0.0.1:42101/\'' + "Exception occurred while handling uri: 'http://127.0.0.1:42101/'", ) def test_middleware_response_raise_exception(app, caplog): - - @app.middleware('response') + @app.middleware("response") async def process_response(request, response): - raise Exception('Exception at response middleware') + raise Exception("Exception at response middleware") with caplog.at_level(logging.ERROR): - reqrequest, response = app.test_client.get('/') + reqrequest, response = app.test_client.get("/") assert response.status == 404 assert caplog.record_tuples[0] == ( - 'sanic.root', + "sanic.root", logging.ERROR, - 'Exception occurred while handling uri: \'http://127.0.0.1:42101/\'' + "Exception occurred while handling uri: 'http://127.0.0.1:42101/'", ) assert caplog.record_tuples[1] == ( - 'sanic.error', + "sanic.error", logging.ERROR, - 'Exception occurred in one of response middleware handlers' + "Exception occurred in one of response middleware handlers", ) def test_middleware_override_request(app): - @app.middleware async def halt_request(request): - return text('OK') + return text("OK") - @app.route('/') + @app.route("/") async def handler(request): - return text('FAIL') + return text("FAIL") - response = app.test_client.get('/', gather_request=False) + response = app.test_client.get("/", gather_request=False) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_middleware_override_response(app): - - @app.middleware('response') + @app.middleware("response") async def process_response(request, response): - return text('OK') + return text("OK") - @app.route('/') + @app.route("/") async def handler(request): - return text('FAIL') + return text("FAIL") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_middleware_order(app): order = [] - @app.middleware('request') + @app.middleware("request") async def request1(request): order.append(1) - @app.middleware('request') + @app.middleware("request") async def request2(request): order.append(2) - @app.middleware('request') + @app.middleware("request") async def request3(request): order.append(3) - @app.middleware('response') + @app.middleware("response") async def response1(request, response): order.append(6) - @app.middleware('response') + @app.middleware("response") async def response2(request, response): order.append(5) - @app.middleware('response') + @app.middleware("response") async def response3(request, response): order.append(4) - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 200 assert order == [1, 2, 3, 4, 5, 6] diff --git a/tests/test_multiprocessing.py b/tests/test_multiprocessing.py index 45d6aaf2..b4b69caf 100644 --- a/tests/test_multiprocessing.py +++ b/tests/test_multiprocessing.py @@ -9,9 +9,9 @@ from sanic.response import text @pytest.mark.skipif( - not hasattr(signal, 'SIGALRM'), - reason='SIGALRM is not implemented for this platform, we have to come ' - 'up with another timeout strategy to test these' + not hasattr(signal, "SIGALRM"), + reason="SIGALRM is not implemented for this platform, we have to come " + "up with another timeout strategy to test these", ) def test_multiprocessing(app): """Tests that the number of children we produce is correct""" @@ -32,11 +32,12 @@ def test_multiprocessing(app): @pytest.mark.skipif( - not hasattr(signal, 'SIGALRM'), - reason='SIGALRM is not implemented for this platform', + not hasattr(signal, "SIGALRM"), + reason="SIGALRM is not implemented for this platform", ) def test_multiprocessing_with_blueprint(app): from sanic import Blueprint + # Selects a number at random so we can spot check num_workers = random.choice(range(2, multiprocessing.cpu_count() * 2 + 1)) process_list = set() @@ -49,7 +50,7 @@ def test_multiprocessing_with_blueprint(app): signal.signal(signal.SIGALRM, stop_on_alarm) signal.alarm(3) - bp = Blueprint('test_text') + bp = Blueprint("test_text") app.blueprint(bp) app.run(HOST, PORT, workers=num_workers) @@ -59,28 +60,30 @@ def test_multiprocessing_with_blueprint(app): # this function must be outside a test function so that it can be # able to be pickled (local functions cannot be pickled). def handler(request): - return text('Hello') + return text("Hello") + # Muliprocessing on Windows requires app to be able to be pickled -@pytest.mark.parametrize('protocol', [3, 4]) +@pytest.mark.parametrize("protocol", [3, 4]) def test_pickle_app(app, protocol): - app.route('/')(handler) + app.route("/")(handler) p_app = pickle.dumps(app, protocol=protocol) up_p_app = pickle.loads(p_app) assert up_p_app - request, response = app.test_client.get('/') - assert response.text == 'Hello' + request, response = app.test_client.get("/") + assert response.text == "Hello" -@pytest.mark.parametrize('protocol', [3, 4]) +@pytest.mark.parametrize("protocol", [3, 4]) def test_pickle_app_with_bp(app, protocol): from sanic import Blueprint - bp = Blueprint('test_text') - bp.route('/')(handler) + + bp = Blueprint("test_text") + bp.route("/")(handler) app.blueprint(bp) p_app = pickle.dumps(app, protocol=protocol) up_p_app = pickle.loads(p_app) assert up_p_app - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert app.is_request_stream is False - assert response.text == 'Hello' + assert response.text == "Hello" diff --git a/tests/test_named_routes.py b/tests/test_named_routes.py index b63b4c6e..05e3890e 100644 --- a/tests/test_named_routes.py +++ b/tests/test_named_routes.py @@ -14,28 +14,32 @@ from sanic.constants import HTTP_METHODS # UTF-8 # ------------------------------------------------------------ # -@pytest.mark.parametrize('method', HTTP_METHODS) + +@pytest.mark.parametrize("method", HTTP_METHODS) def test_versioned_named_routes_get(app, method): - bp = Blueprint('test_bp', url_prefix='/bp') + bp = Blueprint("test_bp", url_prefix="/bp") method = method.lower() - route_name = 'route_{}'.format(method) - route_name2 = 'route2_{}'.format(method) + route_name = "route_{}".format(method) + route_name2 = "route2_{}".format(method) func = getattr(app, method) if callable(func): - @func('/{}'.format(method), version=1, name=route_name) + + @func("/{}".format(method), version=1, name=route_name) def handler(request): - return text('OK') + return text("OK") + else: print(func) raise func = getattr(bp, method) if callable(func): - @func('/{}'.format(method), version=1, name=route_name2) + + @func("/{}".format(method), version=1, name=route_name2) def handler2(request): - return text('OK') + return text("OK") else: print(func) @@ -43,261 +47,250 @@ def test_versioned_named_routes_get(app, method): app.blueprint(bp) - assert app.router.routes_all['/v1/{}'.format(method)].name == route_name + assert app.router.routes_all["/v1/{}".format(method)].name == route_name - route = app.router.routes_all['/v1/bp/{}'.format(method)] - assert route.name == 'test_bp.{}'.format(route_name2) + route = app.router.routes_all["/v1/bp/{}".format(method)] + assert route.name == "test_bp.{}".format(route_name2) - assert app.url_for(route_name) == '/v1/{}'.format(method) - url = app.url_for('test_bp.{}'.format(route_name2)) - assert url == '/v1/bp/{}'.format(method) + assert app.url_for(route_name) == "/v1/{}".format(method) + url = app.url_for("test_bp.{}".format(route_name2)) + assert url == "/v1/bp/{}".format(method) with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_shorthand_default_routes_get(app): - - @app.get('/get') + @app.get("/get") def handler(request): - return text('OK') + return text("OK") - assert app.router.routes_all['/get'].name == 'handler' - assert app.url_for('handler') == '/get' + assert app.router.routes_all["/get"].name == "handler" + assert app.url_for("handler") == "/get" def test_shorthand_named_routes_get(app): - bp = Blueprint('test_bp', url_prefix='/bp') + bp = Blueprint("test_bp", url_prefix="/bp") - @app.get('/get', name='route_get') + @app.get("/get", name="route_get") def handler(request): - return text('OK') + return text("OK") - @bp.get('/get', name='route_bp') + @bp.get("/get", name="route_bp") def handler2(request): - return text('Blueprint') + return text("Blueprint") app.blueprint(bp) - assert app.router.routes_all['/get'].name == 'route_get' - assert app.url_for('route_get') == '/get' + assert app.router.routes_all["/get"].name == "route_get" + assert app.url_for("route_get") == "/get" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") - assert app.router.routes_all['/bp/get'].name == 'test_bp.route_bp' - assert app.url_for('test_bp.route_bp') == '/bp/get' + assert app.router.routes_all["/bp/get"].name == "test_bp.route_bp" + assert app.url_for("test_bp.route_bp") == "/bp/get" with pytest.raises(URLBuildError): - app.url_for('test_bp.handler2') + app.url_for("test_bp.handler2") def test_shorthand_named_routes_post(app): - - @app.post('/post', name='route_name') + @app.post("/post", name="route_name") def handler(request): - return text('OK') + return text("OK") - assert app.router.routes_all['/post'].name == 'route_name' - assert app.url_for('route_name') == '/post' + assert app.router.routes_all["/post"].name == "route_name" + assert app.url_for("route_name") == "/post" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_shorthand_named_routes_put(app): - - @app.put('/put', name='route_put') + @app.put("/put", name="route_put") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - assert app.router.routes_all['/put'].name == 'route_put' - assert app.url_for('route_put') == '/put' + assert app.router.routes_all["/put"].name == "route_put" + assert app.url_for("route_put") == "/put" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_shorthand_named_routes_delete(app): - - @app.delete('/delete', name='route_delete') + @app.delete("/delete", name="route_delete") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - assert app.router.routes_all['/delete'].name == 'route_delete' - assert app.url_for('route_delete') == '/delete' + assert app.router.routes_all["/delete"].name == "route_delete" + assert app.url_for("route_delete") == "/delete" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_shorthand_named_routes_patch(app): - - @app.patch('/patch', name='route_patch') + @app.patch("/patch", name="route_patch") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - assert app.router.routes_all['/patch'].name == 'route_patch' - assert app.url_for('route_patch') == '/patch' + assert app.router.routes_all["/patch"].name == "route_patch" + assert app.url_for("route_patch") == "/patch" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_shorthand_named_routes_head(app): - - @app.head('/head', name='route_head') + @app.head("/head", name="route_head") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - assert app.router.routes_all['/head'].name == 'route_head' - assert app.url_for('route_head') == '/head' + assert app.router.routes_all["/head"].name == "route_head" + assert app.url_for("route_head") == "/head" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_shorthand_named_routes_options(app): - - @app.options('/options', name='route_options') + @app.options("/options", name="route_options") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - assert app.router.routes_all['/options'].name == 'route_options' - assert app.url_for('route_options') == '/options' + assert app.router.routes_all["/options"].name == "route_options" + assert app.url_for("route_options") == "/options" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_named_static_routes(app): - - @app.route('/test', name='route_test') + @app.route("/test", name="route_test") async def handler1(request): - return text('OK1') + return text("OK1") - @app.route('/pizazz', name='route_pizazz') + @app.route("/pizazz", name="route_pizazz") async def handler2(request): - return text('OK2') + return text("OK2") - assert app.router.routes_all['/test'].name == 'route_test' - assert app.router.routes_static['/test'].name == 'route_test' - assert app.url_for('route_test') == '/test' + assert app.router.routes_all["/test"].name == "route_test" + assert app.router.routes_static["/test"].name == "route_test" + assert app.url_for("route_test") == "/test" with pytest.raises(URLBuildError): - app.url_for('handler1') + app.url_for("handler1") - assert app.router.routes_all['/pizazz'].name == 'route_pizazz' - assert app.router.routes_static['/pizazz'].name == 'route_pizazz' - assert app.url_for('route_pizazz') == '/pizazz' + assert app.router.routes_all["/pizazz"].name == "route_pizazz" + assert app.router.routes_static["/pizazz"].name == "route_pizazz" + assert app.url_for("route_pizazz") == "/pizazz" with pytest.raises(URLBuildError): - app.url_for('handler2') + app.url_for("handler2") def test_named_dynamic_route(app): results = [] - @app.route('/folder/', name='route_dynamic') + @app.route("/folder/", name="route_dynamic") async def handler(request, name): results.append(name) - return text('OK') + return text("OK") - assert app.router.routes_all['/folder/'].name == 'route_dynamic' - assert app.url_for('route_dynamic', name='test') == '/folder/test' + assert app.router.routes_all["/folder/"].name == "route_dynamic" + assert app.url_for("route_dynamic", name="test") == "/folder/test" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_dynamic_named_route_regex(app): - - @app.route('/folder/', name='route_re') + @app.route("/folder/", name="route_re") async def handler(request, folder_id): - return text('OK') + return text("OK") - route = app.router.routes_all['/folder/'] - assert route.name == 'route_re' - assert app.url_for('route_re', folder_id='test') == '/folder/test' + route = app.router.routes_all["/folder/"] + assert route.name == "route_re" + assert app.url_for("route_re", folder_id="test") == "/folder/test" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_dynamic_named_route_path(app): - - @app.route('//info', name='route_dynamic_path') + @app.route("//info", name="route_dynamic_path") async def handler(request, path): - return text('OK') + return text("OK") - route = app.router.routes_all['//info'] - assert route.name == 'route_dynamic_path' - assert app.url_for('route_dynamic_path', path='path/1') == '/path/1/info' + route = app.router.routes_all["//info"] + assert route.name == "route_dynamic_path" + assert app.url_for("route_dynamic_path", path="path/1") == "/path/1/info" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_dynamic_named_route_unhashable(app): - - @app.route('/folder//end/', - name='route_unhashable') + @app.route( + "/folder//end/", name="route_unhashable" + ) async def handler(request, unhashable): - return text('OK') + return text("OK") - route = app.router.routes_all['/folder//end/'] - assert route.name == 'route_unhashable' - url = app.url_for('route_unhashable', unhashable='test/asdf') - assert url == '/folder/test/asdf/end' + route = app.router.routes_all["/folder//end/"] + assert route.name == "route_unhashable" + url = app.url_for("route_unhashable", unhashable="test/asdf") + assert url == "/folder/test/asdf/end" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_websocket_named_route(app): ev = asyncio.Event() - @app.websocket('/ws', name='route_ws') + @app.websocket("/ws", name="route_ws") async def handler(request, ws): assert ws.subprotocol is None ev.set() - assert app.router.routes_all['/ws'].name == 'route_ws' - assert app.url_for('route_ws') == '/ws' + assert app.router.routes_all["/ws"].name == "route_ws" + assert app.url_for("route_ws") == "/ws" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_websocket_named_route_with_subprotocols(app): results = [] - @app.websocket('/ws', subprotocols=['foo', 'bar'], name='route_ws') + @app.websocket("/ws", subprotocols=["foo", "bar"], name="route_ws") async def handler(request, ws): results.append(ws.subprotocol) - assert app.router.routes_all['/ws'].name == 'route_ws' - assert app.url_for('route_ws') == '/ws' + assert app.router.routes_all["/ws"].name == "route_ws" + assert app.url_for("route_ws") == "/ws" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_static_add_named_route(app): - async def handler1(request): - return text('OK1') + return text("OK1") async def handler2(request): - return text('OK2') + return text("OK2") - app.add_route(handler1, '/test', name='route_test') - app.add_route(handler2, '/test2', name='route_test2') + app.add_route(handler1, "/test", name="route_test") + app.add_route(handler2, "/test2", name="route_test2") - assert app.router.routes_all['/test'].name == 'route_test' - assert app.router.routes_static['/test'].name == 'route_test' - assert app.url_for('route_test') == '/test' + assert app.router.routes_all["/test"].name == "route_test" + assert app.router.routes_static["/test"].name == "route_test" + assert app.url_for("route_test") == "/test" with pytest.raises(URLBuildError): - app.url_for('handler1') + app.url_for("handler1") - assert app.router.routes_all['/test2'].name == 'route_test2' - assert app.router.routes_static['/test2'].name == 'route_test2' - assert app.url_for('route_test2') == '/test2' + assert app.router.routes_all["/test2"].name == "route_test2" + assert app.router.routes_static["/test2"].name == "route_test2" + assert app.url_for("route_test2") == "/test2" with pytest.raises(URLBuildError): - app.url_for('handler2') + app.url_for("handler2") def test_dynamic_add_named_route(app): @@ -305,61 +298,62 @@ def test_dynamic_add_named_route(app): async def handler(request, name): results.append(name) - return text('OK') + return text("OK") - app.add_route(handler, '/folder/', name='route_dynamic') - assert app.router.routes_all['/folder/'].name == 'route_dynamic' - assert app.url_for('route_dynamic', name='test') == '/folder/test' + app.add_route(handler, "/folder/", name="route_dynamic") + assert app.router.routes_all["/folder/"].name == "route_dynamic" + assert app.url_for("route_dynamic", name="test") == "/folder/test" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_dynamic_add_named_route_unhashable(app): - async def handler(request, unhashable): - return text('OK') + return text("OK") - app.add_route(handler, '/folder//end/', - name='route_unhashable') - route = app.router.routes_all['/folder//end/'] - assert route.name == 'route_unhashable' - url = app.url_for('route_unhashable', unhashable='folder1') - assert url == '/folder/folder1/end' + app.add_route( + handler, + "/folder//end/", + name="route_unhashable", + ) + route = app.router.routes_all["/folder//end/"] + assert route.name == "route_unhashable" + url = app.url_for("route_unhashable", unhashable="folder1") + assert url == "/folder/folder1/end" with pytest.raises(URLBuildError): - app.url_for('handler') + app.url_for("handler") def test_overload_routes(app): - - @app.route('/overload', methods=['GET'], name='route_first') + @app.route("/overload", methods=["GET"], name="route_first") async def handler1(request): - return text('OK1') + return text("OK1") - @app.route('/overload', methods=['POST', 'PUT'], name='route_second') + @app.route("/overload", methods=["POST", "PUT"], name="route_second") async def handler2(request): - return text('OK2') + return text("OK2") - request, response = app.test_client.get(app.url_for('route_first')) - assert response.text == 'OK1' + request, response = app.test_client.get(app.url_for("route_first")) + assert response.text == "OK1" - request, response = app.test_client.post(app.url_for('route_first')) - assert response.text == 'OK2' + request, response = app.test_client.post(app.url_for("route_first")) + assert response.text == "OK2" - request, response = app.test_client.put(app.url_for('route_first')) - assert response.text == 'OK2' + request, response = app.test_client.put(app.url_for("route_first")) + assert response.text == "OK2" - request, response = app.test_client.get(app.url_for('route_second')) - assert response.text == 'OK1' + request, response = app.test_client.get(app.url_for("route_second")) + assert response.text == "OK1" - request, response = app.test_client.post(app.url_for('route_second')) - assert response.text == 'OK2' + request, response = app.test_client.post(app.url_for("route_second")) + assert response.text == "OK2" - request, response = app.test_client.put(app.url_for('route_second')) - assert response.text == 'OK2' + request, response = app.test_client.put(app.url_for("route_second")) + assert response.text == "OK2" - assert app.router.routes_all['/overload'].name == 'route_first' + assert app.router.routes_all["/overload"].name == "route_first" with pytest.raises(URLBuildError): - app.url_for('handler1') + app.url_for("handler1") - assert app.url_for('route_first') == '/overload' - assert app.url_for('route_second') == app.url_for('route_first') + assert app.url_for("route_first") == "/overload" + assert app.url_for("route_second") == app.url_for("route_first") diff --git a/tests/test_payload_too_large.py b/tests/test_payload_too_large.py index 49ad5ab7..de2edc47 100644 --- a/tests/test_payload_too_large.py +++ b/tests/test_payload_too_large.py @@ -5,41 +5,39 @@ from sanic.response import text def test_payload_too_large_from_error_handler(app): app.config.REQUEST_MAX_SIZE = 1 - @app.route('/1') + @app.route("/1") async def handler1(request): - return text('OK') + return text("OK") @app.exception(PayloadTooLarge) def handler_exception(request, exception): - return text('Payload Too Large from error_handler.', 413) + return text("Payload Too Large from error_handler.", 413) - response = app.test_client.get('/1', gather_request=False) + response = app.test_client.get("/1", gather_request=False) assert response.status == 413 - assert response.text == 'Payload Too Large from error_handler.' + assert response.text == "Payload Too Large from error_handler." def test_payload_too_large_at_data_received_default(app): app.config.REQUEST_MAX_SIZE = 1 - @app.route('/1') + @app.route("/1") async def handler2(request): - return text('OK') + return text("OK") - response = app.test_client.get( - '/1', gather_request=False) + response = app.test_client.get("/1", gather_request=False) assert response.status == 413 - assert response.text == 'Error: Payload Too Large' + assert response.text == "Error: Payload Too Large" def test_payload_too_large_at_on_header_default(app): app.config.REQUEST_MAX_SIZE = 500 - @app.post('/1') + @app.post("/1") async def handler3(request): - return text('OK') + return text("OK") - data = 'a' * 1000 - response = app.test_client.post( - '/1', gather_request=False, data=data) + data = "a" * 1000 + response = app.test_client.post("/1", gather_request=False, data=data) assert response.status == 413 - assert response.text == 'Error: Payload Too Large' + assert response.text == "Error: Payload Too Large" diff --git a/tests/test_redirect.py b/tests/test_redirect.py index 28e7d831..c2c54744 100644 --- a/tests/test_redirect.py +++ b/tests/test_redirect.py @@ -6,32 +6,31 @@ from sanic.response import text, redirect @pytest.fixture def redirect_app(app): - - @app.route('/redirect_init') + @app.route("/redirect_init") async def redirect_init(request): return redirect("/redirect_target") - @app.route('/redirect_init_with_301') + @app.route("/redirect_init_with_301") async def redirect_init_with_301(request): return redirect("/redirect_target", status=301) - @app.route('/redirect_target') + @app.route("/redirect_target") async def redirect_target(request): - return text('OK') + return text("OK") - @app.route('/1') + @app.route("/1") def handler1(request): - return redirect('/2') + return redirect("/2") - @app.route('/2') + @app.route("/2") def handler2(request): - return redirect('/3') + return redirect("/3") - @app.route('/3') + @app.route("/3") def handler3(request): - return text('OK') + return text("OK") - @app.route('/redirect_with_header_injection') + @app.route("/redirect_with_header_injection") async def redirect_with_header_injection(request): return redirect("/unsafe\ntest-header: test-value\n\ntest-body") @@ -43,19 +42,18 @@ def test_redirect_default_302(redirect_app): We expect a 302 default status code and the headers to be set. """ request, response = redirect_app.test_client.get( - '/redirect_init', - allow_redirects=False) + "/redirect_init", allow_redirects=False + ) assert response.status == 302 assert response.headers["Location"] == "/redirect_target" - assert response.headers["Content-Type"] == 'text/html; charset=utf-8' + assert response.headers["Content-Type"] == "text/html; charset=utf-8" def test_redirect_headers_none(redirect_app): request, response = redirect_app.test_client.get( - uri="/redirect_init", - headers=None, - allow_redirects=False) + uri="/redirect_init", headers=None, allow_redirects=False + ) assert response.status == 302 assert response.headers["Location"] == "/redirect_target" @@ -66,8 +64,8 @@ def test_redirect_with_301(redirect_app): Test redirection with a different status code. """ request, response = redirect_app.test_client.get( - "/redirect_init_with_301", - allow_redirects=False) + "/redirect_init_with_301", allow_redirects=False + ) assert response.status == 301 assert response.headers["Location"] == "/redirect_target" @@ -78,23 +76,23 @@ def test_get_then_redirect_follow_redirect(redirect_app): With `allow_redirects` we expect a 200. """ request, response = redirect_app.test_client.get( - "/redirect_init", - allow_redirects=True) + "/redirect_init", allow_redirects=True + ) assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_chained_redirect(redirect_app): """Test test_client is working for redirection""" - request, response = redirect_app.test_client.get('/1') - assert request.url.endswith('/1') + request, response = redirect_app.test_client.get("/1") + assert request.url.endswith("/1") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" try: - assert response.url.endswith('/3') + assert response.url.endswith("/3") except AttributeError: - assert response.url.path.endswith('/3') + assert response.url.path.endswith("/3") def test_redirect_with_header_injection(redirect_app): @@ -102,17 +100,16 @@ def test_redirect_with_header_injection(redirect_app): Test redirection to a URL with header and body injections. """ request, response = redirect_app.test_client.get( - "/redirect_with_header_injection", - allow_redirects=False) + "/redirect_with_header_injection", allow_redirects=False + ) assert response.status == 302 assert "test-header" not in response.headers - assert not response.text.startswith('test-body') + assert not response.text.startswith("test-body") @pytest.mark.parametrize("test_str", ["sanic-test", "sanictest", "sanic test"]) async def test_redirect_with_params(app, test_client, test_str): - @app.route("/api/v1/test//") async def init_handler(request, test): assert test == test_str diff --git a/tests/test_request_cancel.py b/tests/test_request_cancel.py index 4619d655..d6b53079 100644 --- a/tests/test_request_cancel.py +++ b/tests/test_request_cancel.py @@ -7,17 +7,17 @@ from sanic.response import text, stream async def test_request_cancel_when_connection_lost(loop, app, test_client): app.still_serving_cancelled_request = False - @app.get('/') + @app.get("/") async def handler(request): await asyncio.sleep(1.0) # at this point client is already disconnected app.still_serving_cancelled_request = True - return text('OK') + return text("OK") test_cli = await test_client(app) # schedule client call - task = loop.create_task(test_cli.get('/')) + task = loop.create_task(test_cli.get("/")) loop.call_later(0.01, task) await asyncio.sleep(0.5) @@ -36,7 +36,7 @@ async def test_request_cancel_when_connection_lost(loop, app, test_client): async def test_stream_request_cancel_when_conn_lost(loop, app, test_client): app.still_serving_cancelled_request = False - @app.post('/post/', stream=True) + @app.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, asyncio.Queue) @@ -45,7 +45,7 @@ async def test_stream_request_cancel_when_conn_lost(loop, app, test_client): body = await request.stream.get() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) await asyncio.sleep(1.0) # at this point client is already disconnected @@ -56,7 +56,7 @@ async def test_stream_request_cancel_when_conn_lost(loop, app, test_client): test_cli = await test_client(app) # schedule client call - task = loop.create_task(test_cli.post('/post/1')) + task = loop.create_task(test_cli.post("/post/1")) loop.call_later(0.01, task) await asyncio.sleep(0.5) diff --git a/tests/test_request_data.py b/tests/test_request_data.py index 2cd422c3..dad112ad 100644 --- a/tests/test_request_data.py +++ b/tests/test_request_data.py @@ -9,39 +9,37 @@ except ImportError: def test_storage(app): - - @app.middleware('request') + @app.middleware("request") def store(request): - request['user'] = 'sanic' - request['sidekick'] = 'tails' - del request['sidekick'] + request["user"] = "sanic" + request["sidekick"] = "tails" + del request["sidekick"] - @app.route('/') + @app.route("/") def handler(request): - return json({ - 'user': request.get('user'), - 'sidekick': request.get('sidekick') - }) + return json( + {"user": request.get("user"), "sidekick": request.get("sidekick")} + ) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") response_json = loads(response.text) - assert response_json['user'] == 'sanic' - assert response_json.get('sidekick') is None + assert response_json["user"] == "sanic" + assert response_json.get("sidekick") is None def test_app_injection(app): expected = random.choice(range(0, 100)) - @app.listener('after_server_start') + @app.listener("after_server_start") async def inject_data(app, loop): app.injected = expected - @app.get('/') + @app.get("/") async def handler(request): - return json({'injected': request.app.injected}) + return json({"injected": request.app.injected}) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") response_json = loads(response.text) - assert response_json['injected'] == expected + assert response_json["injected"] == expected diff --git a/tests/test_request_stream.py b/tests/test_request_stream.py index ecf201f2..bf8bf7d4 100644 --- a/tests/test_request_stream.py +++ b/tests/test_request_stream.py @@ -11,67 +11,66 @@ data = "abc" * 10000000 def test_request_stream_method_view(app): - '''for self.is_request_stream = True''' + """for self.is_request_stream = True""" class SimpleView(HTTPMethodView): - def get(self, request): assert request.stream is None - return text('OK') + return text("OK") @stream_decorator async def post(self, request): assert isinstance(request.stream, StreamBuffer) - result = '' + result = "" while True: body = await request.stream.read() if body is None: break - result += body.decode('utf-8') + result += body.decode("utf-8") return text(result) - app.add_route(SimpleView.as_view(), '/method_view') + app.add_route(SimpleView.as_view(), "/method_view") assert app.is_request_stream is True - request, response = app.test_client.get('/method_view') + request, response = app.test_client.get("/method_view") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.post('/method_view', data=data) + request, response = app.test_client.post("/method_view", data=data) assert response.status == 200 assert response.text == data def test_request_stream_app(app): - '''for self.is_request_stream = True and decorators''' + """for self.is_request_stream = True and decorators""" - @app.get('/get') + @app.get("/get") async def get(request): assert request.stream is None - return text('GET') + return text("GET") - @app.head('/head') + @app.head("/head") async def head(request): assert request.stream is None - return text('HEAD') + return text("HEAD") - @app.delete('/delete') + @app.delete("/delete") async def delete(request): assert request.stream is None - return text('DELETE') + return text("DELETE") - @app.options('/options') + @app.options("/options") async def options(request): assert request.stream is None - return text('OPTIONS') + return text("OPTIONS") - @app.post('/_post/') + @app.post("/_post/") async def _post(request, id): assert request.stream is None - return text('_POST') + return text("_POST") - @app.post('/post/', stream=True) + @app.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, StreamBuffer) @@ -80,15 +79,16 @@ def test_request_stream_app(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) - @app.put('/_put') + @app.put("/_put") async def _put(request): assert request.stream is None - return text('_PUT') + return text("_PUT") - @app.put('/put', stream=True) + @app.put("/put", stream=True) async def put(request): assert isinstance(request.stream, StreamBuffer) @@ -97,15 +97,16 @@ def test_request_stream_app(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) - @app.patch('/_patch') + @app.patch("/_patch") async def _patch(request): assert request.stream is None - return text('_PATCH') + return text("_PATCH") - @app.patch('/patch', stream=True) + @app.patch("/patch", stream=True) async def patch(request): assert isinstance(request.stream, StreamBuffer) @@ -114,56 +115,57 @@ def test_request_stream_app(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) assert app.is_request_stream is True - request, response = app.test_client.get('/get') + request, response = app.test_client.get("/get") assert response.status == 200 - assert response.text == 'GET' + assert response.text == "GET" - request, response = app.test_client.head('/head') + request, response = app.test_client.head("/head") assert response.status == 200 - assert response.text == '' + assert response.text == "" - request, response = app.test_client.delete('/delete') + request, response = app.test_client.delete("/delete") assert response.status == 200 - assert response.text == 'DELETE' + assert response.text == "DELETE" - request, response = app.test_client.options('/options') + request, response = app.test_client.options("/options") assert response.status == 200 - assert response.text == 'OPTIONS' + assert response.text == "OPTIONS" - request, response = app.test_client.post('/_post/1', data=data) + request, response = app.test_client.post("/_post/1", data=data) assert response.status == 200 - assert response.text == '_POST' + assert response.text == "_POST" - request, response = app.test_client.post('/post/1', data=data) + request, response = app.test_client.post("/post/1", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.put('/_put', data=data) + request, response = app.test_client.put("/_put", data=data) assert response.status == 200 - assert response.text == '_PUT' + assert response.text == "_PUT" - request, response = app.test_client.put('/put', data=data) + request, response = app.test_client.put("/put", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.patch('/_patch', data=data) + request, response = app.test_client.patch("/_patch", data=data) assert response.status == 200 - assert response.text == '_PATCH' + assert response.text == "_PATCH" - request, response = app.test_client.patch('/patch', data=data) + request, response = app.test_client.patch("/patch", data=data) assert response.status == 200 assert response.text == data def test_request_stream_handle_exception(app): - '''for handling exceptions properly''' + """for handling exceptions properly""" - @app.post('/post/', stream=True) + @app.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, StreamBuffer) @@ -172,51 +174,54 @@ def test_request_stream_handle_exception(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) # 404 - request, response = app.test_client.post('/in_valid_post', data=data) + request, response = app.test_client.post("/in_valid_post", data=data) assert response.status == 404 - assert response.text == 'Error: Requested URL /in_valid_post not found' + assert response.text == "Error: Requested URL /in_valid_post not found" # 405 - request, response = app.test_client.get('/post/random_id', data=data) + request, response = app.test_client.get("/post/random_id", data=data) assert response.status == 405 - assert response.text == 'Error: Method GET not allowed for URL' \ - ' /post/random_id' + assert ( + response.text == "Error: Method GET not allowed for URL" + " /post/random_id" + ) def test_request_stream_blueprint(app): - '''for self.is_request_stream = True''' - bp = Blueprint('test_blueprint_request_stream_blueprint') + """for self.is_request_stream = True""" + bp = Blueprint("test_blueprint_request_stream_blueprint") - @app.get('/get') + @app.get("/get") async def get(request): assert request.stream is None - return text('GET') + return text("GET") - @bp.head('/head') + @bp.head("/head") async def head(request): assert request.stream is None - return text('HEAD') + return text("HEAD") - @bp.delete('/delete') + @bp.delete("/delete") async def delete(request): assert request.stream is None - return text('DELETE') + return text("DELETE") - @bp.options('/options') + @bp.options("/options") async def options(request): assert request.stream is None - return text('OPTIONS') + return text("OPTIONS") - @bp.post('/_post/') + @bp.post("/_post/") async def _post(request, id): assert request.stream is None - return text('_POST') + return text("_POST") - @bp.post('/post/', stream=True) + @bp.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, StreamBuffer) @@ -225,15 +230,16 @@ def test_request_stream_blueprint(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) - @bp.put('/_put') + @bp.put("/_put") async def _put(request): assert request.stream is None - return text('_PUT') + return text("_PUT") - @bp.put('/put', stream=True) + @bp.put("/put", stream=True) async def put(request): assert isinstance(request.stream, StreamBuffer) @@ -242,15 +248,16 @@ def test_request_stream_blueprint(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) - @bp.patch('/_patch') + @bp.patch("/_patch") async def _patch(request): assert request.stream is None - return text('_PATCH') + return text("_PATCH") - @bp.patch('/patch', stream=True) + @bp.patch("/patch", stream=True) async def patch(request): assert isinstance(request.stream, StreamBuffer) @@ -259,109 +266,109 @@ def test_request_stream_blueprint(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) app.blueprint(bp) assert app.is_request_stream is True - request, response = app.test_client.get('/get') + request, response = app.test_client.get("/get") assert response.status == 200 - assert response.text == 'GET' + assert response.text == "GET" - request, response = app.test_client.head('/head') + request, response = app.test_client.head("/head") assert response.status == 200 - assert response.text == '' + assert response.text == "" - request, response = app.test_client.delete('/delete') + request, response = app.test_client.delete("/delete") assert response.status == 200 - assert response.text == 'DELETE' + assert response.text == "DELETE" - request, response = app.test_client.options('/options') + request, response = app.test_client.options("/options") assert response.status == 200 - assert response.text == 'OPTIONS' + assert response.text == "OPTIONS" - request, response = app.test_client.post('/_post/1', data=data) + request, response = app.test_client.post("/_post/1", data=data) assert response.status == 200 - assert response.text == '_POST' + assert response.text == "_POST" - request, response = app.test_client.post('/post/1', data=data) + request, response = app.test_client.post("/post/1", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.put('/_put', data=data) + request, response = app.test_client.put("/_put", data=data) assert response.status == 200 - assert response.text == '_PUT' + assert response.text == "_PUT" - request, response = app.test_client.put('/put', data=data) + request, response = app.test_client.put("/put", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.patch('/_patch', data=data) + request, response = app.test_client.patch("/_patch", data=data) assert response.status == 200 - assert response.text == '_PATCH' + assert response.text == "_PATCH" - request, response = app.test_client.patch('/patch', data=data) + request, response = app.test_client.patch("/patch", data=data) assert response.status == 200 assert response.text == data def test_request_stream_composition_view(app): - '''for self.is_request_stream = True''' + """for self.is_request_stream = True""" def get_handler(request): assert request.stream is None - return text('OK') + return text("OK") async def post_handler(request): assert isinstance(request.stream, StreamBuffer) - result = '' + result = "" while True: body = await request.stream.read() if body is None: break - result += body.decode('utf-8') + result += body.decode("utf-8") return text(result) view = CompositionView() - view.add(['GET'], get_handler) - view.add(['POST'], post_handler, stream=True) - app.add_route(view, '/composition_view') + view.add(["GET"], get_handler) + view.add(["POST"], post_handler, stream=True) + app.add_route(view, "/composition_view") assert app.is_request_stream is True - request, response = app.test_client.get('/composition_view') + request, response = app.test_client.get("/composition_view") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.post('/composition_view', data=data) + request, response = app.test_client.post("/composition_view", data=data) assert response.status == 200 assert response.text == data def test_request_stream(app): - '''test for complex application''' - bp = Blueprint('test_blueprint_request_stream') + """test for complex application""" + bp = Blueprint("test_blueprint_request_stream") class SimpleView(HTTPMethodView): - def get(self, request): assert request.stream is None - return text('OK') + return text("OK") @stream_decorator async def post(self, request): assert isinstance(request.stream, StreamBuffer) - result = '' + result = "" while True: body = await request.stream.read() if body is None: break - result += body.decode('utf-8') + result += body.decode("utf-8") return text(result) - @app.post('/stream', stream=True) + @app.post("/stream", stream=True) async def handler(request): assert isinstance(request.stream, StreamBuffer) @@ -370,84 +377,85 @@ def test_request_stream(app): body = await request.stream.read() if body is None: break - await response.write(body.decode('utf-8')) + await response.write(body.decode("utf-8")) + return stream(streaming) - @app.get('/get') + @app.get("/get") async def get(request): assert request.stream is None - return text('OK') + return text("OK") - @bp.post('/bp_stream', stream=True) + @bp.post("/bp_stream", stream=True) async def bp_stream(request): assert isinstance(request.stream, StreamBuffer) - result = '' + result = "" while True: body = await request.stream.read() if body is None: break - result += body.decode('utf-8') + result += body.decode("utf-8") return text(result) - @bp.get('/bp_get') + @bp.get("/bp_get") async def bp_get(request): assert request.stream is None - return text('OK') + return text("OK") def get_handler(request): assert request.stream is None - return text('OK') + return text("OK") async def post_handler(request): assert isinstance(request.stream, StreamBuffer) - result = '' + result = "" while True: body = await request.stream.read() if body is None: break - result += body.decode('utf-8') + result += body.decode("utf-8") return text(result) - app.add_route(SimpleView.as_view(), '/method_view') + app.add_route(SimpleView.as_view(), "/method_view") view = CompositionView() - view.add(['GET'], get_handler) - view.add(['POST'], post_handler, stream=True) + view.add(["GET"], get_handler) + view.add(["POST"], post_handler, stream=True) app.blueprint(bp) - app.add_route(view, '/composition_view') + app.add_route(view, "/composition_view") assert app.is_request_stream is True - request, response = app.test_client.get('/method_view') + request, response = app.test_client.get("/method_view") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.post('/method_view', data=data) + request, response = app.test_client.post("/method_view", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.get('/composition_view') + request, response = app.test_client.get("/composition_view") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.post('/composition_view', data=data) + request, response = app.test_client.post("/composition_view", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.get('/get') + request, response = app.test_client.get("/get") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.post('/stream', data=data) + request, response = app.test_client.post("/stream", data=data) assert response.status == 200 assert response.text == data - request, response = app.test_client.get('/bp_get') + request, response = app.test_client.get("/bp_get") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.post('/bp_stream', data=data) + request, response = app.test_client.post("/bp_stream", data=data) assert response.status == 200 assert response.text == data diff --git a/tests/test_request_timeout.py b/tests/test_request_timeout.py index 5d115722..8cb9bd61 100644 --- a/tests/test_request_timeout.py +++ b/tests/test_request_timeout.py @@ -12,6 +12,7 @@ try: try: # direct use import packaging + version = packaging.version except (ImportError, AttributeError): # setuptools v39.0 and above. @@ -29,15 +30,15 @@ aiohttp_version = version.parse(aiohttp.__version__) class DelayableTCPConnector(TCPConnector): - class RequestContextManager(object): def __new__(cls, req, delay): - cls = super(DelayableTCPConnector.RequestContextManager, cls).\ - __new__(cls) + cls = super( + DelayableTCPConnector.RequestContextManager, cls + ).__new__(cls) cls.req = req cls.send_task = None cls.resp = None - cls.orig_send = getattr(req, 'send') + cls.orig_send = getattr(req, "send") cls.orig_start = None cls.delay = delay cls._acting_as = req @@ -54,7 +55,7 @@ class DelayableTCPConnector(TCPConnector): self.send_task = None self.resp = resp self._acting_as = self.resp - self.orig_start = getattr(resp, 'start') + self.orig_start = getattr(resp, "start") try: if aiohttp_version >= version.parse("3.3.0"): @@ -92,10 +93,10 @@ class DelayableTCPConnector(TCPConnector): request_info=None, traces=[], loop=req.loop, - session=None + session=None, ) if aiohttp_version < version.parse("3.3.0"): - kw['auto_decompress'] = None + kw["auto_decompress"] = None return aiohttp.ClientResponse(req.method, req.url, **kw) def _send(self, *args, **kwargs): @@ -109,24 +110,26 @@ class DelayableTCPConnector(TCPConnector): # aiohttp changed the request.send method to async async def send(self, *args, **kwargs): return self._send(*args, **kwargs) + else: send = _send def __init__(self, *args, **kwargs): - _post_connect_delay = kwargs.pop('post_connect_delay', 0) - _pre_request_delay = kwargs.pop('pre_request_delay', 0) + _post_connect_delay = kwargs.pop("post_connect_delay", 0) + _pre_request_delay = kwargs.pop("pre_request_delay", 0) super(DelayableTCPConnector, self).__init__(*args, **kwargs) self._post_connect_delay = _post_connect_delay self._pre_request_delay = _pre_request_delay async def connect(self, req, *args, **kwargs): - d_req = DelayableTCPConnector.\ - RequestContextManager(req, self._pre_request_delay) - conn = await super(DelayableTCPConnector, self).\ - connect(req, *args, **kwargs) + d_req = DelayableTCPConnector.RequestContextManager( + req, self._pre_request_delay + ) + conn = await super(DelayableTCPConnector, self).connect( + req, *args, **kwargs + ) if self._post_connect_delay and self._post_connect_delay > 0: - await asyncio.sleep(self._post_connect_delay, - loop=self._loop) + await asyncio.sleep(self._post_connect_delay, loop=self._loop) req.send = d_req.send t = req.loop.time() print("Connected at {}".format(t), flush=True) @@ -139,24 +142,29 @@ class DelayableSanicTestClient(SanicTestClient): self._request_delay = request_delay self._loop = None - async def _local_request(self, method, uri, cookies=None, *args, - **kwargs): + async def _local_request(self, method, uri, cookies=None, *args, **kwargs): if self._loop is None: self._loop = asyncio.get_event_loop() - if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://' '//')): + if uri.startswith(("http:", "https:", "ftp:", "ftps://" "//")): url = uri else: - url = 'http://{host}:{port}{uri}'.format( - host=HOST, port=self.port, uri=uri) - conn = DelayableTCPConnector(pre_request_delay=self._request_delay, - verify_ssl=False, loop=self._loop) - async with aiohttp.ClientSession(cookies=cookies, connector=conn, - loop=self._loop) as session: + url = "http://{host}:{port}{uri}".format( + host=HOST, port=self.port, uri=uri + ) + conn = DelayableTCPConnector( + pre_request_delay=self._request_delay, + verify_ssl=False, + loop=self._loop, + ) + async with aiohttp.ClientSession( + cookies=cookies, connector=conn, loop=self._loop + ) as session: # Insert a delay after creating the connection # But before sending the request. async with getattr(session, method.lower())( - url, *args, **kwargs) as response: + url, *args, **kwargs + ) as response: try: response.text = await response.text() except UnicodeDecodeError: @@ -164,9 +172,11 @@ class DelayableSanicTestClient(SanicTestClient): try: response.json = await response.json() - except (JSONDecodeError, - UnicodeDecodeError, - aiohttp.ClientResponseError): + except ( + JSONDecodeError, + UnicodeDecodeError, + aiohttp.ClientResponseError, + ): response.json = None response.body = await response.read() @@ -174,50 +184,50 @@ class DelayableSanicTestClient(SanicTestClient): Config.REQUEST_TIMEOUT = 0.6 -request_timeout_default_app = Sanic('test_request_timeout_default') -request_no_timeout_app = Sanic('test_request_no_timeout') +request_timeout_default_app = Sanic("test_request_timeout_default") +request_no_timeout_app = Sanic("test_request_no_timeout") -@request_timeout_default_app.route('/1') +@request_timeout_default_app.route("/1") async def handler1(request): - return text('OK') + return text("OK") -@request_no_timeout_app.route('/1') +@request_no_timeout_app.route("/1") async def handler2(request): - return text('OK') + return text("OK") -@request_timeout_default_app.websocket('/ws1') +@request_timeout_default_app.websocket("/ws1") async def ws_handler1(request, ws): - await ws.send('OK') + await ws.send("OK") def test_default_server_error_request_timeout(): client = DelayableSanicTestClient(request_timeout_default_app, None, 2) - request, response = client.get('/1') + request, response = client.get("/1") assert response.status == 408 - assert response.text == 'Error: Request Timeout' + assert response.text == "Error: Request Timeout" def test_default_server_error_request_dont_timeout(): client = DelayableSanicTestClient(request_no_timeout_app, None, 0.2) - request, response = client.get('/1') + request, response = client.get("/1") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" def test_default_server_error_websocket_request_timeout(): - headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13' + headers = { + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", } client = DelayableSanicTestClient(request_timeout_default_app, None, 2) - request, response = client.get('/ws1', headers=headers) + request, response = client.get("/ws1", headers=headers) assert response.status == 408 - assert response.text == 'Error: Request Timeout' + assert response.text == "Error: Request Timeout" diff --git a/tests/test_requests.py b/tests/test_requests.py index 52a074f8..09b82685 100644 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -16,235 +16,214 @@ from sanic.testing import HOST, PORT # GET # ------------------------------------------------------------ # + def test_sync(app): - - @app.route('/') + @app.route("/") def handler(request): - return text('Hello') + return text("Hello") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == 'Hello' + assert response.text == "Hello" def test_remote_address(app): - - @app.route('/') + @app.route("/") def handler(request): return text("{}".format(request.ip)) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == '127.0.0.1' + assert response.text == "127.0.0.1" def test_text(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('Hello') + return text("Hello") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == 'Hello' + assert response.text == "Hello" def test_headers(app): - - @app.route('/') + @app.route("/") async def handler(request): headers = {"spam": "great"} - return text('Hello', headers=headers) + return text("Hello", headers=headers) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.headers.get('spam') == 'great' + assert response.headers.get("spam") == "great" def test_non_str_headers(app): - - @app.route('/') + @app.route("/") async def handler(request): headers = {"answer": 42} - return text('Hello', headers=headers) + return text("Hello", headers=headers) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.headers.get('answer') == '42' + assert response.headers.get("answer") == "42" def test_invalid_response(app): - @app.exception(ServerError) def handler_exception(request, exception): - return text('Internal Server Error.', 500) + return text("Internal Server Error.", 500) - @app.route('/') + @app.route("/") async def handler(request): - return 'This should fail' + return "This should fail" - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 500 assert response.text == "Internal Server Error." def test_json(app): - - @app.route('/') + @app.route("/") async def handler(request): return json({"test": True}) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") results = json_loads(response.text) - assert results.get('test') is True + assert results.get("test") is True def test_empty_json(app): - - @app.route('/') + @app.route("/") async def handler(request): assert request.json is None return json(request.json) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.status == 200 - assert response.text == 'null' + assert response.text == "null" def test_invalid_json(app): - - @app.route('/') + @app.route("/") async def handler(request): return json(request.json) data = "I am not json" - request, response = app.test_client.get('/', data=data) + request, response = app.test_client.get("/", data=data) assert response.status == 400 def test_query_string(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") request, response = app.test_client.get( - '/', params=[("test1", "1"), ("test2", "false"), ("test2", "true")]) + "/", params=[("test1", "1"), ("test2", "false"), ("test2", "true")] + ) - assert request.args.get('test1') == '1' - assert request.args.get('test2') == 'false' + assert request.args.get("test1") == "1" + assert request.args.get("test2") == "false" def test_uri_template(app): - - @app.route('/foo//bar/') + @app.route("/foo//bar/") async def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/foo/123/bar/baz') - assert request.uri_template == '/foo//bar/' + request, response = app.test_client.get("/foo/123/bar/baz") + assert request.uri_template == "/foo//bar/" def test_token(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") # uuid4 generated token. - token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' + token = "a1d895e0-553a-421a-8e22-5ff8ecb48cbf" headers = { - 'content-type': 'application/json', - 'Authorization': '{}'.format(token) + "content-type": "application/json", + "Authorization": "{}".format(token), } - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert request.token == token - token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' + token = "a1d895e0-553a-421a-8e22-5ff8ecb48cbf" headers = { - 'content-type': 'application/json', - 'Authorization': 'Token {}'.format(token) + "content-type": "application/json", + "Authorization": "Token {}".format(token), } - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert request.token == token - token = 'a1d895e0-553a-421a-8e22-5ff8ecb48cbf' + token = "a1d895e0-553a-421a-8e22-5ff8ecb48cbf" headers = { - 'content-type': 'application/json', - 'Authorization': 'Bearer {}'.format(token) + "content-type": "application/json", + "Authorization": "Bearer {}".format(token), } - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert request.token == token # no Authorization headers - headers = { - 'content-type': 'application/json' - } + headers = {"content-type": "application/json"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert request.token is None def test_content_type(app): - - @app.route('/') + @app.route("/") async def handler(request): return text(request.content_type) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert request.content_type == DEFAULT_HTTP_CONTENT_TYPE assert response.text == DEFAULT_HTTP_CONTENT_TYPE - headers = { - 'content-type': 'application/json', - } - request, response = app.test_client.get('/', headers=headers) - assert request.content_type == 'application/json' - assert response.text == 'application/json' + headers = {"content-type": "application/json"} + request, response = app.test_client.get("/", headers=headers) + assert request.content_type == "application/json" + assert response.text == "application/json" def test_remote_addr(app): - - @app.route('/') + @app.route("/") async def handler(request): return text(request.remote_addr) - headers = { - 'X-Forwarded-For': '127.0.0.1, 127.0.1.2' - } - request, response = app.test_client.get('/', headers=headers) - assert request.remote_addr == '127.0.0.1' - assert response.text == '127.0.0.1' + headers = {"X-Forwarded-For": "127.0.0.1, 127.0.1.2"} + request, response = app.test_client.get("/", headers=headers) + assert request.remote_addr == "127.0.0.1" + assert response.text == "127.0.0.1" - request, response = app.test_client.get('/') - assert request.remote_addr == '' - assert response.text == '' + request, response = app.test_client.get("/") + assert request.remote_addr == "" + assert response.text == "" - headers = { - 'X-Forwarded-For': '127.0.0.1, , ,,127.0.1.2' - } - request, response = app.test_client.get('/', headers=headers) - assert request.remote_addr == '127.0.0.1' - assert response.text == '127.0.0.1' + headers = {"X-Forwarded-For": "127.0.0.1, , ,,127.0.1.2"} + request, response = app.test_client.get("/", headers=headers) + assert request.remote_addr == "127.0.0.1" + assert response.text == "127.0.0.1" def test_match_info(app): - - @app.route('/api/v1/user//') + @app.route("/api/v1/user//") async def handler(request, user_id): return json(request.match_info) - request, response = app.test_client.get('/api/v1/user/sanic_user/') + request, response = app.test_client.get("/api/v1/user/sanic_user/") assert request.match_info == {"user_id": "sanic_user"} assert json_loads(response.text) == {"user_id": "sanic_user"} @@ -254,79 +233,82 @@ def test_match_info(app): # POST # ------------------------------------------------------------ # + def test_post_json(app): - - @app.route('/', methods=['POST']) + @app.route("/", methods=["POST"]) async def handler(request): - return text('OK') + return text("OK") - payload = {'test': 'OK'} - headers = {'content-type': 'application/json'} + payload = {"test": "OK"} + headers = {"content-type": "application/json"} request, response = app.test_client.post( - '/', data=json_dumps(payload), headers=headers) + "/", data=json_dumps(payload), headers=headers + ) - assert request.json.get('test') == 'OK' - assert request.json.get('test') == 'OK' # for request.parsed_json - assert response.text == 'OK' + assert request.json.get("test") == "OK" + assert request.json.get("test") == "OK" # for request.parsed_json + assert response.text == "OK" def test_post_form_urlencoded(app): - - @app.route('/', methods=['POST']) + @app.route("/", methods=["POST"]) async def handler(request): - return text('OK') + return text("OK") - payload = 'test=OK' - headers = {'content-type': 'application/x-www-form-urlencoded'} + payload = "test=OK" + headers = {"content-type": "application/x-www-form-urlencoded"} - request, response = app.test_client.post('/', data=payload, - headers=headers) + request, response = app.test_client.post( + "/", data=payload, headers=headers + ) - assert request.form.get('test') == 'OK' - assert request.form.get('test') == 'OK' # For request.parsed_form + assert request.form.get("test") == "OK" + assert request.form.get("test") == "OK" # For request.parsed_form @pytest.mark.parametrize( - 'payload', [ - '------sanic\r\n' + "payload", + [ + "------sanic\r\n" 'Content-Disposition: form-data; name="test"\r\n' - '\r\n' - 'OK\r\n' - '------sanic--\r\n', - '------sanic\r\n' + "\r\n" + "OK\r\n" + "------sanic--\r\n", + "------sanic\r\n" 'content-disposition: form-data; name="test"\r\n' - '\r\n' - 'OK\r\n' - '------sanic--\r\n', - ]) + "\r\n" + "OK\r\n" + "------sanic--\r\n", + ], +) def test_post_form_multipart_form_data(app, payload): - - @app.route('/', methods=['POST']) + @app.route("/", methods=["POST"]) async def handler(request): - return text('OK') + return text("OK") - headers = {'content-type': 'multipart/form-data; boundary=----sanic'} + headers = {"content-type": "multipart/form-data; boundary=----sanic"} request, response = app.test_client.post(data=payload, headers=headers) - assert request.form.get('test') == 'OK' + assert request.form.get("test") == "OK" @pytest.mark.parametrize( - 'path,query,expected_url', [ - ('/foo', '', 'http://{}:{}/foo'), - ('/bar/baz', '', 'http://{}:{}/bar/baz'), - ('/moo/boo', 'arg1=val1', 'http://{}:{}/moo/boo?arg1=val1') - ]) + "path,query,expected_url", + [ + ("/foo", "", "http://{}:{}/foo"), + ("/bar/baz", "", "http://{}:{}/bar/baz"), + ("/moo/boo", "arg1=val1", "http://{}:{}/moo/boo?arg1=val1"), + ], +) def test_url_attributes_no_ssl(app, path, query, expected_url): - async def handler(request): - return text('OK') + return text("OK") app.add_route(handler, path) - request, response = app.test_client.get(path + '?{}'.format(query)) + request, response = app.test_client.get(path + "?{}".format(query)) assert request.url == expected_url.format(HOST, PORT) parsed = urlparse(request.url) @@ -338,26 +320,30 @@ def test_url_attributes_no_ssl(app, path, query, expected_url): @pytest.mark.parametrize( - 'path,query,expected_url', [ - ('/foo', '', 'https://{}:{}/foo'), - ('/bar/baz', '', 'https://{}:{}/bar/baz'), - ('/moo/boo', 'arg1=val1', 'https://{}:{}/moo/boo?arg1=val1') - ]) + "path,query,expected_url", + [ + ("/foo", "", "https://{}:{}/foo"), + ("/bar/baz", "", "https://{}:{}/bar/baz"), + ("/moo/boo", "arg1=val1", "https://{}:{}/moo/boo?arg1=val1"), + ], +) def test_url_attributes_with_ssl_context(app, path, query, expected_url): current_dir = os.path.dirname(os.path.realpath(__file__)) context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH) context.load_cert_chain( - os.path.join(current_dir, 'certs/selfsigned.cert'), - keyfile=os.path.join(current_dir, 'certs/selfsigned.key')) + os.path.join(current_dir, "certs/selfsigned.cert"), + keyfile=os.path.join(current_dir, "certs/selfsigned.key"), + ) async def handler(request): - return text('OK') + return text("OK") app.add_route(handler, path) request, response = app.test_client.get( - 'https://{}:{}'.format(HOST, PORT) + path + '?{}'.format(query), - server_kwargs={'ssl': context}) + "https://{}:{}".format(HOST, PORT) + path + "?{}".format(query), + server_kwargs={"ssl": context}, + ) assert request.url == expected_url.format(HOST, PORT) parsed = urlparse(request.url) @@ -369,30 +355,30 @@ def test_url_attributes_with_ssl_context(app, path, query, expected_url): @pytest.mark.parametrize( - 'path,query,expected_url', [ - ('/foo', '', 'https://{}:{}/foo'), - ('/bar/baz', '', 'https://{}:{}/bar/baz'), - ('/moo/boo', 'arg1=val1', 'https://{}:{}/moo/boo?arg1=val1') - ]) + "path,query,expected_url", + [ + ("/foo", "", "https://{}:{}/foo"), + ("/bar/baz", "", "https://{}:{}/bar/baz"), + ("/moo/boo", "arg1=val1", "https://{}:{}/moo/boo?arg1=val1"), + ], +) def test_url_attributes_with_ssl_dict(app, path, query, expected_url): current_dir = os.path.dirname(os.path.realpath(__file__)) - ssl_cert = os.path.join(current_dir, 'certs/selfsigned.cert') - ssl_key = os.path.join(current_dir, 'certs/selfsigned.key') + ssl_cert = os.path.join(current_dir, "certs/selfsigned.cert") + ssl_key = os.path.join(current_dir, "certs/selfsigned.key") - ssl_dict = { - 'cert': ssl_cert, - 'key': ssl_key - } + ssl_dict = {"cert": ssl_cert, "key": ssl_key} async def handler(request): - return text('OK') + return text("OK") app.add_route(handler, path) request, response = app.test_client.get( - 'https://{}:{}'.format(HOST, PORT) + path + '?{}'.format(query), - server_kwargs={'ssl': ssl_dict}) + "https://{}:{}".format(HOST, PORT) + path + "?{}".format(query), + server_kwargs={"ssl": ssl_dict}, + ) assert request.url == expected_url.format(HOST, PORT) parsed = urlparse(request.url) @@ -404,69 +390,69 @@ def test_url_attributes_with_ssl_dict(app, path, query, expected_url): def test_invalid_ssl_dict(app): - - @app.get('/test') + @app.get("/test") async def handler(request): - return text('ssl test') + return text("ssl test") - ssl_dict = { - 'cert': None, - 'key': None - } + ssl_dict = {"cert": None, "key": None} with pytest.raises(ValueError) as excinfo: - request, response = app.test_client.get('/test', server_kwargs={'ssl': ssl_dict}) + request, response = app.test_client.get( + "/test", server_kwargs={"ssl": ssl_dict} + ) - assert str(excinfo.value) == 'SSLContext or certificate and key required.' + assert str(excinfo.value) == "SSLContext or certificate and key required." def test_form_with_multiple_values(app): - - @app.route('/', methods=['POST']) + @app.route("/", methods=["POST"]) async def handler(request): return text("OK") - payload="selectedItems=v1&selectedItems=v2&selectedItems=v3" + payload = "selectedItems=v1&selectedItems=v2&selectedItems=v3" - headers = {'content-type': 'application/x-www-form-urlencoded'} + headers = {"content-type": "application/x-www-form-urlencoded"} - request, response = app.test_client.post('/', data=payload, - headers=headers) + request, response = app.test_client.post( + "/", data=payload, headers=headers + ) assert request.form.getlist("selectedItems") == ["v1", "v2", "v3"] def test_request_string_representation(app): - @app.route('/', methods=["GET"]) + @app.route("/", methods=["GET"]) async def get(request): return text("OK") request, _ = app.test_client.get("/") - assert repr(request) == '' + assert repr(request) == "" @pytest.mark.parametrize( - 'payload', [ - '------sanic\r\n' + "payload", + [ + "------sanic\r\n" 'Content-Disposition: form-data; filename="filename"; name="test"\r\n' - '\r\n' - 'OK\r\n' - '------sanic--\r\n', - '------sanic\r\n' + "\r\n" + "OK\r\n" + "------sanic--\r\n", + "------sanic\r\n" 'content-disposition: form-data; filename="filename"; name="test"\r\n' - '\r\n' + "\r\n" 'content-type: application/json; {"field": "value"}\r\n' - '------sanic--\r\n', - ]) + "------sanic--\r\n", + ], +) def test_request_multipart_files(app, payload): @app.route("/", methods=["POST"]) async def post(request): return text("OK") - headers = {'content-type': 'multipart/form-data; boundary=----sanic'} + headers = {"content-type": "multipart/form-data; boundary=----sanic"} request, _ = app.test_client.post(data=payload, headers=headers) - assert request.files.get('test').name == "filename" + assert request.files.get("test").name == "filename" def test_request_multipart_file_with_json_content_type(app): @@ -475,72 +461,79 @@ def test_request_multipart_file_with_json_content_type(app): return text("OK") payload = ( - '------sanic\r\n' + "------sanic\r\n" 'Content-Disposition: form-data; name="file"; filename="test.json"\r\n' - 'Content-Type: application/json\r\n' - 'Content-Length: 0' - '\r\n' - '\r\n' - '------sanic--' + "Content-Type: application/json\r\n" + "Content-Length: 0" + "\r\n" + "\r\n" + "------sanic--" ) - headers = {'content-type': 'multipart/form-data; boundary=------sanic'} + headers = {"content-type": "multipart/form-data; boundary=------sanic"} request, _ = app.test_client.post(data=payload, headers=headers) - assert request.files.get('file').type == 'application/json' + assert request.files.get("file").type == "application/json" def test_request_multipart_file_without_field_name(app, caplog): - @app.route("/", methods=["POST"]) async def post(request): return text("OK") payload = ( '------sanic\r\nContent-Disposition: form-data; filename="test.json"' - '\r\nContent-Type: application/json\r\n\r\n\r\n------sanic--' + "\r\nContent-Type: application/json\r\n\r\n\r\n------sanic--" ) - headers = {'content-type': 'multipart/form-data; boundary=------sanic'} + headers = {"content-type": "multipart/form-data; boundary=------sanic"} - request, _ = app.test_client.post(data=payload, headers=headers, debug=True) + request, _ = app.test_client.post( + data=payload, headers=headers, debug=True + ) with caplog.at_level(logging.DEBUG): request.form - assert caplog.record_tuples[-1] == ('sanic.root', logging.DEBUG, + assert caplog.record_tuples[-1] == ( + "sanic.root", + logging.DEBUG, "Form-data field does not have a 'name' parameter " - "in the Content-Disposition header" + "in the Content-Disposition header", ) def test_request_multipart_file_duplicate_filed_name(app): - @app.route("/", methods=["POST"]) async def post(request): return text("OK") payload = ( - '--e73ffaa8b1b2472b8ec848de833cb05b\r\n' + "--e73ffaa8b1b2472b8ec848de833cb05b\r\n" 'Content-Disposition: form-data; name="file"\r\n' - 'Content-Type: application/octet-stream\r\n' - 'Content-Length: 15\r\n' - '\r\n' + "Content-Type: application/octet-stream\r\n" + "Content-Length: 15\r\n" + "\r\n" '{"test":"json"}\r\n' - '--e73ffaa8b1b2472b8ec848de833cb05b\r\n' + "--e73ffaa8b1b2472b8ec848de833cb05b\r\n" 'Content-Disposition: form-data; name="file"\r\n' - 'Content-Type: application/octet-stream\r\n' - 'Content-Length: 15\r\n' - '\r\n' + "Content-Type: application/octet-stream\r\n" + "Content-Length: 15\r\n" + "\r\n" '{"test":"json2"}\r\n' - '--e73ffaa8b1b2472b8ec848de833cb05b--\r\n' + "--e73ffaa8b1b2472b8ec848de833cb05b--\r\n" ) headers = { - 'Content-Type': 'multipart/form-data; boundary=e73ffaa8b1b2472b8ec848de833cb05b' + "Content-Type": "multipart/form-data; boundary=e73ffaa8b1b2472b8ec848de833cb05b" } - request, _ = app.test_client.post(data=payload, headers=headers, debug=True) - assert request.form.getlist('file') == ['{"test":"json"}', '{"test":"json2"}'] + request, _ = app.test_client.post( + data=payload, headers=headers, debug=True + ) + assert request.form.getlist("file") == [ + '{"test":"json"}', + '{"test":"json2"}', + ] def test_request_multipart_with_multiple_files_and_type(app): @@ -548,38 +541,38 @@ def test_request_multipart_with_multiple_files_and_type(app): async def post(request): return text("OK") - payload = '------sanic\r\nContent-Disposition: form-data; name="file"; filename="test.json"' \ - '\r\nContent-Type: application/json\r\n\r\n\r\n' \ - '------sanic\r\nContent-Disposition: form-data; name="file"; filename="some_file.pdf"\r\n' \ - 'Content-Type: application/pdf\r\n\r\n\r\n------sanic--' - headers = {'content-type': 'multipart/form-data; boundary=------sanic'} + payload = ( + '------sanic\r\nContent-Disposition: form-data; name="file"; filename="test.json"' + "\r\nContent-Type: application/json\r\n\r\n\r\n" + '------sanic\r\nContent-Disposition: form-data; name="file"; filename="some_file.pdf"\r\n' + "Content-Type: application/pdf\r\n\r\n\r\n------sanic--" + ) + headers = {"content-type": "multipart/form-data; boundary=------sanic"} request, _ = app.test_client.post(data=payload, headers=headers) - assert len(request.files.getlist('file')) == 2 - assert request.files.getlist('file')[0].type == 'application/json' - assert request.files.getlist('file')[1].type == 'application/pdf' + assert len(request.files.getlist("file")) == 2 + assert request.files.getlist("file")[0].type == "application/json" + assert request.files.getlist("file")[1].type == "application/pdf" def test_request_repr(app): - - @app.get('/') + @app.get("/") def handler(request): - return text('pass') + return text("pass") - request, response = app.test_client.get('/') - assert repr(request) == '' + request, response = app.test_client.get("/") + assert repr(request) == "" request.method = None - assert repr(request) == '' + assert repr(request) == "" def test_request_bool(app): - - @app.get('/') + @app.get("/") def handler(request): - return text('pass') + return text("pass") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert bool(request) request.transport = False @@ -587,98 +580,99 @@ def test_request_bool(app): def test_request_parsing_form_failed(app, caplog): - - @app.route('/', methods=['POST']) + @app.route("/", methods=["POST"]) async def handler(request): - return text('OK') + return text("OK") - payload = 'test=OK' - headers = {'content-type': 'multipart/form-data'} + payload = "test=OK" + headers = {"content-type": "multipart/form-data"} - request, response = app.test_client.post('/', data=payload, headers=headers) + request, response = app.test_client.post( + "/", data=payload, headers=headers + ) with caplog.at_level(logging.ERROR): request.form - assert caplog.record_tuples[-1] == ('sanic.error', logging.ERROR, 'Failed when parsing form') + assert caplog.record_tuples[-1] == ( + "sanic.error", + logging.ERROR, + "Failed when parsing form", + ) def test_request_args_no_query_string(app): - - @app.get('/') + @app.get("/") def handler(request): - return text('pass') + return text("pass") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert request.args == {} def test_request_raw_args(app): - params = {'test': 'OK'} + params = {"test": "OK"} - @app.get('/') + @app.get("/") def handler(request): - return text('pass') + return text("pass") - request, response = app.test_client.get('/', params=params) + request, response = app.test_client.get("/", params=params) assert request.raw_args == params def test_request_cookies(app): - cookies = {'test': 'OK'} + cookies = {"test": "OK"} - @app.get('/') + @app.get("/") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/', cookies=cookies) + request, response = app.test_client.get("/", cookies=cookies) assert request.cookies == cookies - assert request.cookies == cookies # For request._cookies + assert request.cookies == cookies # For request._cookies def test_request_cookies_without_cookies(app): - - @app.get('/') + @app.get("/") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert request.cookies == {} def test_request_port(app): - - @app.get('/') + @app.get("/") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") port = request.port assert isinstance(port, int) - delattr(request, '_socket') - delattr(request, '_port') + delattr(request, "_socket") + delattr(request, "_port") port = request.port assert isinstance(port, int) - assert hasattr(request, '_socket') - assert hasattr(request, '_port') + assert hasattr(request, "_socket") + assert hasattr(request, "_port") def test_request_socket(app): - - @app.get('/') + @app.get("/") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") socket = request.socket assert isinstance(socket, tuple) @@ -689,19 +683,18 @@ def test_request_socket(app): assert ip == request.ip assert port == request.port - delattr(request, '_socket') + delattr(request, "_socket") socket = request.socket assert isinstance(socket, tuple) - assert hasattr(request, '_socket') + assert hasattr(request, "_socket") def test_request_form_invalid_content_type(app): - @app.route("/", methods=["POST"]) async def post(request): return text("OK") - request, response = app.test_client.post('/', json={'test': 'OK'}) + request, response = app.test_client.post("/", json={"test": "OK"}) assert request.form == {} diff --git a/tests/test_response.py b/tests/test_response.py index d4a181c1..256a37c6 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -10,127 +10,128 @@ from urllib.parse import unquote import pytest from aiofiles import os as async_os -from sanic.response import (HTTPResponse, StreamingHTTPResponse, file, - file_stream, json, raw, stream, text) +from sanic.response import ( + HTTPResponse, + StreamingHTTPResponse, + file, + file_stream, + json, + raw, + stream, + text, +) from sanic.server import HttpProtocol from sanic.testing import HOST, PORT -JSON_DATA = {'ok': True} +JSON_DATA = {"ok": True} def test_response_body_not_a_string(app): """Test when a response body sent from the application is not a string""" random_num = choice(range(1000)) - @app.route('/hello') + @app.route("/hello") async def hello_route(request): return HTTPResponse(body=random_num) - request, response = app.test_client.get('/hello') + request, response = app.test_client.get("/hello") assert response.text == str(random_num) async def sample_streaming_fn(response): - await response.write('foo,') - await asyncio.sleep(.001) - await response.write('bar') + await response.write("foo,") + await asyncio.sleep(0.001) + await response.write("bar") def test_method_not_allowed(app): - @app.get('/') + @app.get("/") async def test_get(request): - return response.json({'hello': 'world'}) + return response.json({"hello": "world"}) - request, response = app.test_client.head('/') - assert response.headers['Allow'] == 'GET' + request, response = app.test_client.head("/") + assert response.headers["Allow"] == "GET" - request, response = app.test_client.post('/') - assert response.headers['Allow'] == 'GET' + request, response = app.test_client.post("/") + assert response.headers["Allow"] == "GET" - @app.post('/') + @app.post("/") async def test_post(request): - return response.json({'hello': 'world'}) + return response.json({"hello": "world"}) - request, response = app.test_client.head('/') + request, response = app.test_client.head("/") assert response.status == 405 - assert set(response.headers['Allow'].split(', ')) == {'GET', 'POST'} - assert response.headers['Content-Length'] == '0' + assert set(response.headers["Allow"].split(", ")) == {"GET", "POST"} + assert response.headers["Content-Length"] == "0" - request, response = app.test_client.patch('/') + request, response = app.test_client.patch("/") assert response.status == 405 - assert set(response.headers['Allow'].split(', ')) == {'GET', 'POST'} - assert response.headers['Content-Length'] == '0' + assert set(response.headers["Allow"].split(", ")) == {"GET", "POST"} + assert response.headers["Content-Length"] == "0" def test_response_header(app): - - @app.get('/') + @app.get("/") async def test(request): - return json({ - "ok": True - }, headers={ - 'CONTENT-TYPE': 'application/json' - }) + return json({"ok": True}, headers={"CONTENT-TYPE": "application/json"}) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert dict(response.headers) == { - 'Connection': 'keep-alive', - 'Keep-Alive': str(app.config.KEEP_ALIVE_TIMEOUT), - 'Content-Length': '11', - 'Content-Type': 'application/json', + "Connection": "keep-alive", + "Keep-Alive": str(app.config.KEEP_ALIVE_TIMEOUT), + "Content-Length": "11", + "Content-Type": "application/json", } def test_response_content_length(app): @app.get("/response_with_space") async def response_with_space(request): - return json({ - "message": "Data", - "details": "Some Details" - }, headers={ - 'CONTENT-TYPE': 'application/json' - }) + return json( + {"message": "Data", "details": "Some Details"}, + headers={"CONTENT-TYPE": "application/json"}, + ) @app.get("/response_without_space") async def response_without_space(request): - return json({ - "message":"Data", - "details":"Some Details" - }, headers={ - 'CONTENT-TYPE': 'application/json' - }) + return json( + {"message": "Data", "details": "Some Details"}, + headers={"CONTENT-TYPE": "application/json"}, + ) _, response = app.test_client.get("/response_with_space") - content_length_for_response_with_space = response.headers.get("Content-Length") + content_length_for_response_with_space = response.headers.get( + "Content-Length" + ) _, response = app.test_client.get("/response_without_space") - content_length_for_response_without_space = response.headers.get("Content-Length") + content_length_for_response_without_space = response.headers.get( + "Content-Length" + ) - assert content_length_for_response_with_space == content_length_for_response_without_space + assert ( + content_length_for_response_with_space + == content_length_for_response_without_space + ) - assert content_length_for_response_with_space == '43' + assert content_length_for_response_with_space == "43" def test_response_content_length_with_different_data_types(app): @app.get("/") async def get_data_with_different_types(request): # Indentation issues in the Response is intentional. Please do not fix - return json({ - 'bool': True, - 'none': None, - 'string':'string', - 'number': -1}, - headers={ - 'CONTENT-TYPE': 'application/json' - }) + return json( + {"bool": True, "none": None, "string": "string", "number": -1}, + headers={"CONTENT-TYPE": "application/json"}, + ) _, response = app.test_client.get("/") - assert response.headers.get("Content-Length") == '55' + assert response.headers.get("Content-Length") == "55" @pytest.fixture def json_app(app): - @app.route("/") async def test(request): return json(JSON_DATA) @@ -156,70 +157,72 @@ def json_app(app): def test_json_response(json_app): from sanic.response import json_dumps - request, response = json_app.test_client.get('/') + + request, response = json_app.test_client.get("/") assert response.status == 200 assert response.text == json_dumps(JSON_DATA) assert response.json == JSON_DATA def test_no_content(json_app): - request, response = json_app.test_client.get('/no-content') + request, response = json_app.test_client.get("/no-content") assert response.status == 204 - assert response.text == '' - assert 'Content-Length' not in response.headers + assert response.text == "" + assert "Content-Length" not in response.headers - request, response = json_app.test_client.get('/no-content/unmodified') + request, response = json_app.test_client.get("/no-content/unmodified") assert response.status == 304 - assert response.text == '' - assert 'Content-Length' not in response.headers - assert 'Content-Type' not in response.headers + assert response.text == "" + assert "Content-Length" not in response.headers + assert "Content-Type" not in response.headers - request, response = json_app.test_client.get('/unmodified') + request, response = json_app.test_client.get("/unmodified") assert response.status == 304 - assert response.text == '' - assert 'Content-Length' not in response.headers - assert 'Content-Type' not in response.headers + assert response.text == "" + assert "Content-Length" not in response.headers + assert "Content-Type" not in response.headers - request, response = json_app.test_client.delete('/') + request, response = json_app.test_client.delete("/") assert response.status == 204 - assert response.text == '' - assert 'Content-Length' not in response.headers + assert response.text == "" + assert "Content-Length" not in response.headers @pytest.fixture def streaming_app(app): - @app.route("/") async def test(request): - return stream(sample_streaming_fn, content_type='text/csv') + return stream(sample_streaming_fn, content_type="text/csv") return app def test_streaming_adds_correct_headers(streaming_app): - request, response = streaming_app.test_client.get('/') - assert response.headers['Transfer-Encoding'] == 'chunked' - assert response.headers['Content-Type'] == 'text/csv' + request, response = streaming_app.test_client.get("/") + assert response.headers["Transfer-Encoding"] == "chunked" + assert response.headers["Content-Type"] == "text/csv" def test_streaming_returns_correct_content(streaming_app): - request, response = streaming_app.test_client.get('/') - assert response.text == 'foo,bar' + request, response = streaming_app.test_client.get("/") + assert response.text == "foo,bar" -@pytest.mark.parametrize('status', [200, 201, 400, 401]) +@pytest.mark.parametrize("status", [200, 201, 400, 401]) def test_stream_response_status_returns_correct_headers(status): response = StreamingHTTPResponse(sample_streaming_fn, status=status) headers = response.get_headers() assert b"HTTP/1.1 %s" % str(status).encode() in headers -@pytest.mark.parametrize('keep_alive_timeout', [10, 20, 30]) +@pytest.mark.parametrize("keep_alive_timeout", [10, 20, 30]) def test_stream_response_keep_alive_returns_correct_headers( - keep_alive_timeout): + keep_alive_timeout +): response = StreamingHTTPResponse(sample_streaming_fn) headers = response.get_headers( - keep_alive=True, keep_alive_timeout=keep_alive_timeout) + keep_alive=True, keep_alive_timeout=keep_alive_timeout + ) assert b"Keep-Alive: %s\r\n" % str(keep_alive_timeout).encode() in headers @@ -244,19 +247,19 @@ def test_stream_response_writes_correct_content_to_transport(streaming_app): response.protocol.push_data = mock_push_data response.protocol.drain = mock_drain - @streaming_app.listener('after_server_start') + @streaming_app.listener("after_server_start") async def run_stream(app, loop): await response.stream() assert response.protocol.transport.write.call_args_list[1][0][0] == ( - b'4\r\nfoo,\r\n' + b"4\r\nfoo,\r\n" ) assert response.protocol.transport.write.call_args_list[2][0][0] == ( - b'3\r\nbar\r\n' + b"3\r\nbar\r\n" ) assert response.protocol.transport.write.call_args_list[3][0][0] == ( - b'0\r\n\r\n' + b"0\r\n\r\n" ) app.stop() @@ -265,25 +268,23 @@ def test_stream_response_writes_correct_content_to_transport(streaming_app): def test_stream_response_with_cookies(app): - @app.route("/") async def test(request): - response = stream(sample_streaming_fn, content_type='text/csv') - response.cookies['test'] = 'modified' - response.cookies['test'] = 'pass' + response = stream(sample_streaming_fn, content_type="text/csv") + response.cookies["test"] = "modified" + response.cookies["test"] = "pass" return response - request, response = app.test_client.get('/') - assert response.cookies['test'].value == 'pass' + request, response = app.test_client.get("/") + assert response.cookies["test"].value == "pass" def test_stream_response_without_cookies(app): - @app.route("/") async def test(request): - return stream(sample_streaming_fn, content_type='text/csv') + return stream(sample_streaming_fn, content_type="text/csv") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.cookies == {} @@ -292,195 +293,214 @@ def static_file_directory(): """The static directory to serve""" current_file = inspect.getfile(inspect.currentframe()) current_directory = os.path.dirname(os.path.abspath(current_file)) - static_directory = os.path.join(current_directory, 'static') + static_directory = os.path.join(current_directory, "static") return static_directory def get_file_content(static_file_directory, file_name): """The content of the static file to check""" - with open(os.path.join(static_file_directory, file_name), 'rb') as file: + with open(os.path.join(static_file_directory, file_name), "rb") as file: return file.read() -@pytest.mark.parametrize('file_name', - ['test.file', 'decode me.txt', 'python.png']) -@pytest.mark.parametrize('status', [200, 401]) +@pytest.mark.parametrize( + "file_name", ["test.file", "decode me.txt", "python.png"] +) +@pytest.mark.parametrize("status", [200, 401]) def test_file_response(app, file_name, static_file_directory, status): - - @app.route('/files/', methods=['GET']) + @app.route("/files/", methods=["GET"]) def file_route(request, filename): file_path = os.path.join(static_file_directory, filename) file_path = os.path.abspath(unquote(file_path)) - return file(file_path, status=status, - mime_type=guess_type(file_path)[0] or 'text/plain') + return file( + file_path, + status=status, + mime_type=guess_type(file_path)[0] or "text/plain", + ) - request, response = app.test_client.get('/files/{}'.format(file_name)) + request, response = app.test_client.get("/files/{}".format(file_name)) assert response.status == status assert response.body == get_file_content(static_file_directory, file_name) - assert 'Content-Disposition' not in response.headers + assert "Content-Disposition" not in response.headers @pytest.mark.parametrize( - 'source,dest', + "source,dest", [ - ('test.file', 'my_file.txt'), ('decode me.txt', 'readme.md'), - ('python.png', 'logo.png') - ] + ("test.file", "my_file.txt"), + ("decode me.txt", "readme.md"), + ("python.png", "logo.png"), + ], ) -def test_file_response_custom_filename(app, source, dest, - static_file_directory): - - @app.route('/files/', methods=['GET']) +def test_file_response_custom_filename( + app, source, dest, static_file_directory +): + @app.route("/files/", methods=["GET"]) def file_route(request, filename): file_path = os.path.join(static_file_directory, filename) file_path = os.path.abspath(unquote(file_path)) return file(file_path, filename=dest) - request, response = app.test_client.get('/files/{}'.format(source)) + request, response = app.test_client.get("/files/{}".format(source)) assert response.status == 200 assert response.body == get_file_content(static_file_directory, source) - assert response.headers['Content-Disposition'] == \ - 'attachment; filename="{}"'.format(dest) + assert response.headers[ + "Content-Disposition" + ] == 'attachment; filename="{}"'.format(dest) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_file_head_response(app, file_name, static_file_directory): - - @app.route('/files/', methods=['GET', 'HEAD']) + @app.route("/files/", methods=["GET", "HEAD"]) async def file_route(request, filename): file_path = os.path.join(static_file_directory, filename) file_path = os.path.abspath(unquote(file_path)) stats = await async_os.stat(file_path) headers = dict() - headers['Accept-Ranges'] = 'bytes' - headers['Content-Length'] = str(stats.st_size) + headers["Accept-Ranges"] = "bytes" + headers["Content-Length"] = str(stats.st_size) if request.method == "HEAD": return HTTPResponse( headers=headers, - content_type=guess_type(file_path)[0] or 'text/plain') + content_type=guess_type(file_path)[0] or "text/plain", + ) else: - return file(file_path, headers=headers, - mime_type=guess_type(file_path)[0] or 'text/plain') + return file( + file_path, + headers=headers, + mime_type=guess_type(file_path)[0] or "text/plain", + ) - request, response = app.test_client.head('/files/{}'.format(file_name)) + request, response = app.test_client.head("/files/{}".format(file_name)) assert response.status == 200 - assert 'Accept-Ranges' in response.headers - assert 'Content-Length' in response.headers - assert int(response.headers[ - 'Content-Length']) == len( - get_file_content(static_file_directory, file_name)) - - -@pytest.mark.parametrize('file_name', - ['test.file', 'decode me.txt', 'python.png']) -def test_file_stream_response(app, file_name, static_file_directory): - - @app.route('/files/', methods=['GET']) - def file_route(request, filename): - file_path = os.path.join(static_file_directory, filename) - file_path = os.path.abspath(unquote(file_path)) - return file_stream(file_path, chunk_size=32, - mime_type=guess_type(file_path)[0] or 'text/plain') - - request, response = app.test_client.get('/files/{}'.format(file_name)) - assert response.status == 200 - assert response.body == get_file_content(static_file_directory, file_name) - assert 'Content-Disposition' not in response.headers + assert "Accept-Ranges" in response.headers + assert "Content-Length" in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) @pytest.mark.parametrize( - 'source,dest', - [ - ('test.file', 'my_file.txt'), ('decode me.txt', 'readme.md'), - ('python.png', 'logo.png') - ] + "file_name", ["test.file", "decode me.txt", "python.png"] ) -def test_file_stream_response_custom_filename(app, source, dest, - static_file_directory): - - @app.route('/files/', methods=['GET']) - def file_route(request, filename): - file_path = os.path.join(static_file_directory, filename) - file_path = os.path.abspath(unquote(file_path)) - return file_stream(file_path, chunk_size=32, filename=dest) - - request, response = app.test_client.get('/files/{}'.format(source)) - assert response.status == 200 - assert response.body == get_file_content(static_file_directory, source) - assert response.headers['Content-Disposition'] == \ - 'attachment; filename="{}"'.format(dest) - - -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_file_stream_head_response(app, file_name, static_file_directory): - - @app.route('/files/', methods=['GET', 'HEAD']) - async def file_route(request, filename): - file_path = os.path.join(static_file_directory, filename) - file_path = os.path.abspath(unquote(file_path)) - headers = dict() - headers['Accept-Ranges'] = 'bytes' - if request.method == "HEAD": - # Return a normal HTTPResponse, not a - # StreamingHTTPResponse for a HEAD request - stats = await async_os.stat(file_path) - headers['Content-Length'] = str(stats.st_size) - return HTTPResponse( - headers=headers, - content_type=guess_type(file_path)[0] or 'text/plain') - else: - return file_stream( - file_path, chunk_size=32, headers=headers, - mime_type=guess_type(file_path)[0] or 'text/plain' - ) - - request, response = app.test_client.head('/files/{}'.format(file_name)) - assert response.status == 200 - # A HEAD request should never be streamed/chunked. - if 'Transfer-Encoding' in response.headers: - assert response.headers['Transfer-Encoding'] != "chunked" - assert 'Accept-Ranges' in response.headers - # A HEAD request should get the Content-Length too - assert 'Content-Length' in response.headers - assert int(response.headers[ - 'Content-Length']) == len( - get_file_content(static_file_directory, file_name)) - - -@pytest.mark.parametrize('file_name', - ['test.file', 'decode me.txt', 'python.png']) -@pytest.mark.parametrize('size,start,end', [ - (1024, 0, 1024), - (4096, 1024, 8192), - ]) -def test_file_stream_response_range(app, file_name, static_file_directory, size, start, end): - - Range = namedtuple('Range', ['size', 'start', 'end', 'total']) - total = len(get_file_content(static_file_directory, file_name)) - range = Range(size=size, start=start, end=end, total=total) - - @app.route('/files/', methods=['GET']) +def test_file_stream_response(app, file_name, static_file_directory): + @app.route("/files/", methods=["GET"]) def file_route(request, filename): file_path = os.path.join(static_file_directory, filename) file_path = os.path.abspath(unquote(file_path)) return file_stream( file_path, chunk_size=32, - mime_type=guess_type(file_path)[0] or 'text/plain', - _range=range) + mime_type=guess_type(file_path)[0] or "text/plain", + ) - request, response = app.test_client.get('/files/{}'.format(file_name)) + request, response = app.test_client.get("/files/{}".format(file_name)) + assert response.status == 200 + assert response.body == get_file_content(static_file_directory, file_name) + assert "Content-Disposition" not in response.headers + + +@pytest.mark.parametrize( + "source,dest", + [ + ("test.file", "my_file.txt"), + ("decode me.txt", "readme.md"), + ("python.png", "logo.png"), + ], +) +def test_file_stream_response_custom_filename( + app, source, dest, static_file_directory +): + @app.route("/files/", methods=["GET"]) + def file_route(request, filename): + file_path = os.path.join(static_file_directory, filename) + file_path = os.path.abspath(unquote(file_path)) + return file_stream(file_path, chunk_size=32, filename=dest) + + request, response = app.test_client.get("/files/{}".format(source)) + assert response.status == 200 + assert response.body == get_file_content(static_file_directory, source) + assert response.headers[ + "Content-Disposition" + ] == 'attachment; filename="{}"'.format(dest) + + +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_file_stream_head_response(app, file_name, static_file_directory): + @app.route("/files/", methods=["GET", "HEAD"]) + async def file_route(request, filename): + file_path = os.path.join(static_file_directory, filename) + file_path = os.path.abspath(unquote(file_path)) + headers = dict() + headers["Accept-Ranges"] = "bytes" + if request.method == "HEAD": + # Return a normal HTTPResponse, not a + # StreamingHTTPResponse for a HEAD request + stats = await async_os.stat(file_path) + headers["Content-Length"] = str(stats.st_size) + return HTTPResponse( + headers=headers, + content_type=guess_type(file_path)[0] or "text/plain", + ) + else: + return file_stream( + file_path, + chunk_size=32, + headers=headers, + mime_type=guess_type(file_path)[0] or "text/plain", + ) + + request, response = app.test_client.head("/files/{}".format(file_name)) + assert response.status == 200 + # A HEAD request should never be streamed/chunked. + if "Transfer-Encoding" in response.headers: + assert response.headers["Transfer-Encoding"] != "chunked" + assert "Accept-Ranges" in response.headers + # A HEAD request should get the Content-Length too + assert "Content-Length" in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) + + +@pytest.mark.parametrize( + "file_name", ["test.file", "decode me.txt", "python.png"] +) +@pytest.mark.parametrize( + "size,start,end", [(1024, 0, 1024), (4096, 1024, 8192)] +) +def test_file_stream_response_range( + app, file_name, static_file_directory, size, start, end +): + + Range = namedtuple("Range", ["size", "start", "end", "total"]) + total = len(get_file_content(static_file_directory, file_name)) + range = Range(size=size, start=start, end=end, total=total) + + @app.route("/files/", methods=["GET"]) + def file_route(request, filename): + file_path = os.path.join(static_file_directory, filename) + file_path = os.path.abspath(unquote(file_path)) + return file_stream( + file_path, + chunk_size=32, + mime_type=guess_type(file_path)[0] or "text/plain", + _range=range, + ) + + request, response = app.test_client.get("/files/{}".format(file_name)) assert response.status == 206 - assert 'Content-Range' in response.headers - assert response.headers['Content-Range'] == 'bytes {}-{}/{}'.format(range.start, range.end, range.total) + assert "Content-Range" in response.headers + assert response.headers["Content-Range"] == "bytes {}-{}/{}".format( + range.start, range.end, range.total + ) def test_raw_response(app): - - @app.get('/test') + @app.get("/test") def handler(request): - return raw(b'raw_response') + return raw(b"raw_response") - request, response = app.test_client.get('/test') - assert response.content_type == 'application/octet-stream' - assert response.body == b'raw_response' + request, response = app.test_client.get("/test") + assert response.content_type == "application/octet-stream" + assert response.body == b"raw_response" diff --git a/tests/test_response_timeout.py b/tests/test_response_timeout.py index 44204b5e..f0406724 100644 --- a/tests/test_response_timeout.py +++ b/tests/test_response_timeout.py @@ -5,38 +5,38 @@ from sanic.exceptions import ServiceUnavailable from sanic.config import Config Config.RESPONSE_TIMEOUT = 1 -response_timeout_app = Sanic('test_response_timeout') -response_timeout_default_app = Sanic('test_response_timeout_default') -response_handler_cancelled_app = Sanic('test_response_handler_cancelled') +response_timeout_app = Sanic("test_response_timeout") +response_timeout_default_app = Sanic("test_response_timeout_default") +response_handler_cancelled_app = Sanic("test_response_handler_cancelled") -@response_timeout_app.route('/1') +@response_timeout_app.route("/1") async def handler_1(request): await asyncio.sleep(2) - return text('OK') + return text("OK") @response_timeout_app.exception(ServiceUnavailable) def handler_exception(request, exception): - return text('Response Timeout from error_handler.', 503) + return text("Response Timeout from error_handler.", 503) def test_server_error_response_timeout(): - request, response = response_timeout_app.test_client.get('/1') + request, response = response_timeout_app.test_client.get("/1") assert response.status == 503 - assert response.text == 'Response Timeout from error_handler.' + assert response.text == "Response Timeout from error_handler." -@response_timeout_default_app.route('/1') +@response_timeout_default_app.route("/1") async def handler_2(request): await asyncio.sleep(2) - return text('OK') + return text("OK") def test_default_server_error_response_timeout(): - request, response = response_timeout_default_app.test_client.get('/1') + request, response = response_timeout_default_app.test_client.get("/1") assert response.status == 503 - assert response.text == 'Error: Response Timeout' + assert response.text == "Error: Response Timeout" response_handler_cancelled_app.flag = False @@ -52,14 +52,14 @@ def handler_cancelled(request, exception): # is already closed when we get a CancelledError. -@response_handler_cancelled_app.route('/1') +@response_handler_cancelled_app.route("/1") async def handler_3(request): await asyncio.sleep(2) - return text('OK') + return text("OK") def test_response_handler_cancelled(): - request, response = response_handler_cancelled_app.test_client.get('/1') + request, response = response_handler_cancelled_app.test_client.get("/1") assert response.status == 503 - assert response.text == 'Error: Response Timeout' + assert response.text == "Error: Response Timeout" assert response_handler_cancelled_app.flag is False diff --git a/tests/test_routes.py b/tests/test_routes.py index 525dacad..f3152935 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -11,390 +11,379 @@ from sanic.router import ParameterNameConflicts, RouteDoesNotExist, RouteExists # UTF-8 # ------------------------------------------------------------ # -@pytest.mark.parametrize('method', HTTP_METHODS) + +@pytest.mark.parametrize("method", HTTP_METHODS) def test_versioned_routes_get(app, method): method = method.lower() func = getattr(app, method) if callable(func): - @func('/{}'.format(method), version=1) + + @func("/{}".format(method), version=1) def handler(request): - return text('OK') + return text("OK") + else: print(func) raise Exception("Method: {} is not callable".format(method)) client_method = getattr(app.test_client, method) - request, response = client_method('/v1/{}'.format(method)) + request, response = client_method("/v1/{}".format(method)) assert response.status == 200 def test_shorthand_routes_get(app): - - @app.get('/get') + @app.get("/get") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/get') - assert response.text == 'OK' + request, response = app.test_client.get("/get") + assert response.text == "OK" - request, response = app.test_client.post('/get') + request, response = app.test_client.post("/get") assert response.status == 405 def test_shorthand_routes_multiple(app): - - @app.get('/get') + @app.get("/get") def get_handler(request): - return text('OK') + return text("OK") - @app.options('/get') + @app.options("/get") def options_handler(request): - return text('') + return text("") - request, response = app.test_client.get('/get/') + request, response = app.test_client.get("/get/") assert response.status == 200 - assert response.text == 'OK' + assert response.text == "OK" - request, response = app.test_client.options('/get/') + request, response = app.test_client.options("/get/") assert response.status == 200 def test_route_strict_slash(app): - - @app.get('/get', strict_slashes=True) + @app.get("/get", strict_slashes=True) def handler1(request): assert request.stream is None - return text('OK') + return text("OK") - @app.post('/post/', strict_slashes=True) + @app.post("/post/", strict_slashes=True) def handler2(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - request, response = app.test_client.get('/get') - assert response.text == 'OK' + request, response = app.test_client.get("/get") + assert response.text == "OK" - request, response = app.test_client.get('/get/') + request, response = app.test_client.get("/get/") assert response.status == 404 - request, response = app.test_client.post('/post/') - assert response.text == 'OK' + request, response = app.test_client.post("/post/") + assert response.text == "OK" - request, response = app.test_client.post('/post') + request, response = app.test_client.post("/post") assert response.status == 404 def test_route_invalid_parameter_syntax(app): with pytest.raises(ValueError): - @app.get('/get/<:string>', strict_slashes=True) + @app.get("/get/<:string>", strict_slashes=True) def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/get') + request, response = app.test_client.get("/get") def test_route_strict_slash_default_value(): - app = Sanic('test_route_strict_slash', strict_slashes=True) + app = Sanic("test_route_strict_slash", strict_slashes=True) - @app.get('/get') + @app.get("/get") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/get/') + request, response = app.test_client.get("/get/") assert response.status == 404 def test_route_strict_slash_without_passing_default_value(app): - - @app.get('/get') + @app.get("/get") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/get/') - assert response.text == 'OK' + request, response = app.test_client.get("/get/") + assert response.text == "OK" def test_route_strict_slash_default_value_can_be_overwritten(): - app = Sanic('test_route_strict_slash', strict_slashes=True) + app = Sanic("test_route_strict_slash", strict_slashes=True) - @app.get('/get', strict_slashes=False) + @app.get("/get", strict_slashes=False) def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/get/') - assert response.text == 'OK' + request, response = app.test_client.get("/get/") + assert response.text == "OK" def test_route_slashes_overload(app): - - @app.get('/hello/') + @app.get("/hello/") def handler_get(request): - return text('OK') + return text("OK") - @app.post('/hello/') + @app.post("/hello/") def handler_post(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/hello') - assert response.text == 'OK' + request, response = app.test_client.get("/hello") + assert response.text == "OK" - request, response = app.test_client.get('/hello/') - assert response.text == 'OK' + request, response = app.test_client.get("/hello/") + assert response.text == "OK" - request, response = app.test_client.post('/hello') - assert response.text == 'OK' + request, response = app.test_client.post("/hello") + assert response.text == "OK" - request, response = app.test_client.post('/hello/') - assert response.text == 'OK' + request, response = app.test_client.post("/hello/") + assert response.text == "OK" def test_route_optional_slash(app): - - @app.get('/get') + @app.get("/get") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/get') - assert response.text == 'OK' + request, response = app.test_client.get("/get") + assert response.text == "OK" - request, response = app.test_client.get('/get/') - assert response.text == 'OK' + request, response = app.test_client.get("/get/") + assert response.text == "OK" def test_route_strict_slashes_set_to_false_and_host_is_a_list(app): # Part of regression test for issue #1120 - site1 = '127.0.0.1:{}'.format(app.test_client.port) + site1 = "127.0.0.1:{}".format(app.test_client.port) # before fix, this raises a RouteExists error - @app.get('/get', host=[site1, 'site2.com'], strict_slashes=False) + @app.get("/get", host=[site1, "site2.com"], strict_slashes=False) def get_handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('http://' + site1 + '/get') - assert response.text == 'OK' + request, response = app.test_client.get("http://" + site1 + "/get") + assert response.text == "OK" - @app.post('/post', host=[site1, 'site2.com'], strict_slashes=False) + @app.post("/post", host=[site1, "site2.com"], strict_slashes=False) def post_handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.post('http://' + site1 + '/post') - assert response.text == 'OK' + request, response = app.test_client.post("http://" + site1 + "/post") + assert response.text == "OK" - @app.put('/put', host=[site1, 'site2.com'], strict_slashes=False) + @app.put("/put", host=[site1, "site2.com"], strict_slashes=False) def put_handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.put('http://' + site1 + '/put') - assert response.text == 'OK' + request, response = app.test_client.put("http://" + site1 + "/put") + assert response.text == "OK" - @app.delete('/delete', host=[site1, 'site2.com'], strict_slashes=False) + @app.delete("/delete", host=[site1, "site2.com"], strict_slashes=False) def delete_handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.delete('http://' + site1 + '/delete') - assert response.text == 'OK' + request, response = app.test_client.delete("http://" + site1 + "/delete") + assert response.text == "OK" def test_shorthand_routes_post(app): - - @app.post('/post') + @app.post("/post") def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.post('/post') - assert response.text == 'OK' + request, response = app.test_client.post("/post") + assert response.text == "OK" - request, response = app.test_client.get('/post') + request, response = app.test_client.get("/post") assert response.status == 405 def test_shorthand_routes_put(app): - - @app.put('/put') + @app.put("/put") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - request, response = app.test_client.put('/put') - assert response.text == 'OK' + request, response = app.test_client.put("/put") + assert response.text == "OK" - request, response = app.test_client.get('/put') + request, response = app.test_client.get("/put") assert response.status == 405 def test_shorthand_routes_delete(app): - - @app.delete('/delete') + @app.delete("/delete") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - request, response = app.test_client.delete('/delete') - assert response.text == 'OK' + request, response = app.test_client.delete("/delete") + assert response.text == "OK" - request, response = app.test_client.get('/delete') + request, response = app.test_client.get("/delete") assert response.status == 405 def test_shorthand_routes_patch(app): - - @app.patch('/patch') + @app.patch("/patch") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - request, response = app.test_client.patch('/patch') - assert response.text == 'OK' + request, response = app.test_client.patch("/patch") + assert response.text == "OK" - request, response = app.test_client.get('/patch') + request, response = app.test_client.get("/patch") assert response.status == 405 def test_shorthand_routes_head(app): - - @app.head('/head') + @app.head("/head") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - request, response = app.test_client.head('/head') + request, response = app.test_client.head("/head") assert response.status == 200 - request, response = app.test_client.get('/head') + request, response = app.test_client.get("/head") assert response.status == 405 def test_shorthand_routes_options(app): - - @app.options('/options') + @app.options("/options") def handler(request): assert request.stream is None - return text('OK') + return text("OK") assert app.is_request_stream is False - request, response = app.test_client.options('/options') + request, response = app.test_client.options("/options") assert response.status == 200 - request, response = app.test_client.get('/options') + request, response = app.test_client.get("/options") assert response.status == 405 def test_static_routes(app): - - @app.route('/test') + @app.route("/test") async def handler1(request): - return text('OK1') + return text("OK1") - @app.route('/pizazz') + @app.route("/pizazz") async def handler2(request): - return text('OK2') + return text("OK2") - request, response = app.test_client.get('/test') - assert response.text == 'OK1' + request, response = app.test_client.get("/test") + assert response.text == "OK1" - request, response = app.test_client.get('/pizazz') - assert response.text == 'OK2' + request, response = app.test_client.get("/pizazz") + assert response.text == "OK2" def test_dynamic_route(app): results = [] - @app.route('/folder/') + @app.route("/folder/") async def handler(request, name): results.append(name) - return text('OK') + return text("OK") - request, response = app.test_client.get('/folder/test123') + request, response = app.test_client.get("/folder/test123") - assert response.text == 'OK' - assert results[0] == 'test123' + assert response.text == "OK" + assert results[0] == "test123" def test_dynamic_route_string(app): results = [] - @app.route('/folder/') + @app.route("/folder/") async def handler(request, name): results.append(name) - return text('OK') + return text("OK") - request, response = app.test_client.get('/folder/test123') + request, response = app.test_client.get("/folder/test123") - assert response.text == 'OK' - assert results[0] == 'test123' + assert response.text == "OK" + assert results[0] == "test123" - request, response = app.test_client.get('/folder/favicon.ico') + request, response = app.test_client.get("/folder/favicon.ico") - assert response.text == 'OK' - assert results[1] == 'favicon.ico' + assert response.text == "OK" + assert results[1] == "favicon.ico" def test_dynamic_route_int(app): results = [] - @app.route('/folder/') + @app.route("/folder/") async def handler(request, folder_id): results.append(folder_id) - return text('OK') + return text("OK") - request, response = app.test_client.get('/folder/12345') - assert response.text == 'OK' + request, response = app.test_client.get("/folder/12345") + assert response.text == "OK" assert type(results[0]) is int - request, response = app.test_client.get('/folder/asdf') + request, response = app.test_client.get("/folder/asdf") assert response.status == 404 def test_dynamic_route_number(app): results = [] - @app.route('/weight/') + @app.route("/weight/") async def handler(request, weight): results.append(weight) - return text('OK') + return text("OK") - request, response = app.test_client.get('/weight/12345') - assert response.text == 'OK' + request, response = app.test_client.get("/weight/12345") + assert response.text == "OK" assert type(results[0]) is float - request, response = app.test_client.get('/weight/1234.56') + request, response = app.test_client.get("/weight/1234.56") assert response.status == 200 - request, response = app.test_client.get('/weight/1234-56') + request, response = app.test_client.get("/weight/1234-56") assert response.status == 404 def test_dynamic_route_regex(app): - - @app.route('/folder/') + @app.route("/folder/") async def handler(request, folder_id): - return text('OK') + return text("OK") - request, response = app.test_client.get('/folder/test') + request, response = app.test_client.get("/folder/test") assert response.status == 200 - request, response = app.test_client.get('/folder/test1') + request, response = app.test_client.get("/folder/test1") assert response.status == 404 - request, response = app.test_client.get('/folder/test-123') + request, response = app.test_client.get("/folder/test-123") assert response.status == 404 - request, response = app.test_client.get('/folder/') + request, response = app.test_client.get("/folder/") assert response.status == 200 @@ -403,80 +392,82 @@ def test_dynamic_route_uuid(app): results = [] - @app.route('/quirky/') + @app.route("/quirky/") async def handler(request, unique_id): results.append(unique_id) - return text('OK') + return text("OK") - url = '/quirky/123e4567-e89b-12d3-a456-426655440000' + url = "/quirky/123e4567-e89b-12d3-a456-426655440000" request, response = app.test_client.get(url) - assert response.text == 'OK' + assert response.text == "OK" assert type(results[0]) is uuid.UUID - request, response = app.test_client.get('/quirky/{}'.format(uuid.uuid4())) + request, response = app.test_client.get("/quirky/{}".format(uuid.uuid4())) assert response.status == 200 - request, response = app.test_client.get('/quirky/non-existing') + request, response = app.test_client.get("/quirky/non-existing") assert response.status == 404 def test_dynamic_route_path(app): - - @app.route('//info') + @app.route("//info") async def handler(request, path): - return text('OK') + return text("OK") - request, response = app.test_client.get('/path/1/info') + request, response = app.test_client.get("/path/1/info") assert response.status == 200 - request, response = app.test_client.get('/info') + request, response = app.test_client.get("/info") assert response.status == 404 - @app.route('/') + @app.route("/") async def handler1(request, path): - return text('OK') + return text("OK") - request, response = app.test_client.get('/info') + request, response = app.test_client.get("/info") assert response.status == 200 - request, response = app.test_client.get('/whatever/you/set') + request, response = app.test_client.get("/whatever/you/set") assert response.status == 200 def test_dynamic_route_unhashable(app): - - @app.route('/folder//end/') + @app.route("/folder//end/") async def handler(request, unhashable): - return text('OK') + return text("OK") - request, response = app.test_client.get('/folder/test/asdf/end/') + request, response = app.test_client.get("/folder/test/asdf/end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test///////end/') + request, response = app.test_client.get("/folder/test///////end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test/end/') + request, response = app.test_client.get("/folder/test/end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test/nope/') + request, response = app.test_client.get("/folder/test/nope/") assert response.status == 404 -@pytest.mark.parametrize('url', ['/ws', 'ws']) +@pytest.mark.parametrize("url", ["/ws", "ws"]) def test_websocket_route(app, url): ev = asyncio.Event() @app.websocket(url) async def handler(request, ws): - assert request.scheme == 'ws' + assert request.scheme == "ws" assert ws.subprotocol is None ev.set() - request, response = app.test_client.get('/ws', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13'}) + request, response = app.test_client.get( + "/ws", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + }, + ) assert response.status == 101 assert ev.is_set() @@ -484,45 +475,61 @@ def test_websocket_route(app, url): def test_websocket_route_with_subprotocols(app): results = [] - @app.websocket('/ws', subprotocols=['foo', 'bar']) + @app.websocket("/ws", subprotocols=["foo", "bar"]) async def handler(request, ws): results.append(ws.subprotocol) - request, response = app.test_client.get('/ws', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13', - 'Sec-WebSocket-Protocol': 'bar'}) + request, response = app.test_client.get( + "/ws", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + "Sec-WebSocket-Protocol": "bar", + }, + ) assert response.status == 101 - request, response = app.test_client.get('/ws', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13', - 'Sec-WebSocket-Protocol': 'bar, foo'}) + request, response = app.test_client.get( + "/ws", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + "Sec-WebSocket-Protocol": "bar, foo", + }, + ) assert response.status == 101 - request, response = app.test_client.get('/ws', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13', - 'Sec-WebSocket-Protocol': 'baz'}) + request, response = app.test_client.get( + "/ws", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + "Sec-WebSocket-Protocol": "baz", + }, + ) assert response.status == 101 - request, response = app.test_client.get('/ws', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13'}) + request, response = app.test_client.get( + "/ws", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + }, + ) assert response.status == 101 - assert results == ['bar', 'bar', None, None] + assert results == ["bar", "bar", None, None] -@pytest.mark.parametrize('strict_slashes', [True, False, None]) +@pytest.mark.parametrize("strict_slashes", [True, False, None]) def test_add_webscoket_route(app, strict_slashes): ev = asyncio.Event() @@ -530,12 +537,16 @@ def test_add_webscoket_route(app, strict_slashes): assert ws.subprotocol is None ev.set() - app.add_websocket_route(handler, '/ws', strict_slashes=strict_slashes) - request, response = app.test_client.get('/ws', headers={ - 'Upgrade': 'websocket', - 'Connection': 'upgrade', - 'Sec-WebSocket-Key': 'dGhlIHNhbXBsZSBub25jZQ==', - 'Sec-WebSocket-Version': '13'}) + app.add_websocket_route(handler, "/ws", strict_slashes=strict_slashes) + request, response = app.test_client.get( + "/ws", + headers={ + "Upgrade": "websocket", + "Connection": "upgrade", + "Sec-WebSocket-Key": "dGhlIHNhbXBsZSBub25jZQ==", + "Sec-WebSocket-Version": "13", + }, + ) assert response.status == 101 assert ev.is_set() @@ -543,54 +554,54 @@ def test_add_webscoket_route(app, strict_slashes): def test_route_duplicate(app): with pytest.raises(RouteExists): - @app.route('/test') + + @app.route("/test") async def handler1(request): pass - @app.route('/test') + @app.route("/test") async def handler2(request): pass with pytest.raises(RouteExists): - @app.route('/test//') + + @app.route("/test//") async def handler3(request, dynamic): pass - @app.route('/test//') + @app.route("/test//") async def handler4(request, dynamic): pass def test_method_not_allowed(app): - - @app.route('/test', methods=['GET']) + @app.route("/test", methods=["GET"]) async def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 200 - request, response = app.test_client.post('/test') + request, response = app.test_client.post("/test") assert response.status == 405 -@pytest.mark.parametrize('strict_slashes', [True, False, None]) +@pytest.mark.parametrize("strict_slashes", [True, False, None]) def test_static_add_route(app, strict_slashes): - async def handler1(request): - return text('OK1') + return text("OK1") async def handler2(request): - return text('OK2') + return text("OK2") - app.add_route(handler1, '/test', strict_slashes=strict_slashes) - app.add_route(handler2, '/test2', strict_slashes=strict_slashes) + app.add_route(handler1, "/test", strict_slashes=strict_slashes) + app.add_route(handler2, "/test2", strict_slashes=strict_slashes) - request, response = app.test_client.get('/test') - assert response.text == 'OK1' + request, response = app.test_client.get("/test") + assert response.text == "OK1" - request, response = app.test_client.get('/test2') - assert response.text == 'OK2' + request, response = app.test_client.get("/test2") + assert response.text == "OK2" def test_dynamic_add_route(app): @@ -599,13 +610,13 @@ def test_dynamic_add_route(app): async def handler(request, name): results.append(name) - return text('OK') + return text("OK") - app.add_route(handler, '/folder/') - request, response = app.test_client.get('/folder/test123') + app.add_route(handler, "/folder/") + request, response = app.test_client.get("/folder/test123") - assert response.text == 'OK' - assert results[0] == 'test123' + assert response.text == "OK" + assert results[0] == "test123" def test_dynamic_add_route_string(app): @@ -614,18 +625,18 @@ def test_dynamic_add_route_string(app): async def handler(request, name): results.append(name) - return text('OK') + return text("OK") - app.add_route(handler, '/folder/') - request, response = app.test_client.get('/folder/test123') + app.add_route(handler, "/folder/") + request, response = app.test_client.get("/folder/test123") - assert response.text == 'OK' - assert results[0] == 'test123' + assert response.text == "OK" + assert results[0] == "test123" - request, response = app.test_client.get('/folder/favicon.ico') + request, response = app.test_client.get("/folder/favicon.ico") - assert response.text == 'OK' - assert results[1] == 'favicon.ico' + assert response.text == "OK" + assert results[1] == "favicon.ico" def test_dynamic_add_route_int(app): @@ -633,15 +644,15 @@ def test_dynamic_add_route_int(app): async def handler(request, folder_id): results.append(folder_id) - return text('OK') + return text("OK") - app.add_route(handler, '/folder/') + app.add_route(handler, "/folder/") - request, response = app.test_client.get('/folder/12345') - assert response.text == 'OK' + request, response = app.test_client.get("/folder/12345") + assert response.text == "OK" assert type(results[0]) is int - request, response = app.test_client.get('/folder/asdf') + request, response = app.test_client.get("/folder/asdf") assert response.status == 404 @@ -650,156 +661,152 @@ def test_dynamic_add_route_number(app): async def handler(request, weight): results.append(weight) - return text('OK') + return text("OK") - app.add_route(handler, '/weight/') + app.add_route(handler, "/weight/") - request, response = app.test_client.get('/weight/12345') - assert response.text == 'OK' + request, response = app.test_client.get("/weight/12345") + assert response.text == "OK" assert type(results[0]) is float - request, response = app.test_client.get('/weight/1234.56') + request, response = app.test_client.get("/weight/1234.56") assert response.status == 200 - request, response = app.test_client.get('/weight/1234-56') + request, response = app.test_client.get("/weight/1234-56") assert response.status == 404 def test_dynamic_add_route_regex(app): - async def handler(request, folder_id): - return text('OK') + return text("OK") - app.add_route(handler, '/folder/') + app.add_route(handler, "/folder/") - request, response = app.test_client.get('/folder/test') + request, response = app.test_client.get("/folder/test") assert response.status == 200 - request, response = app.test_client.get('/folder/test1') + request, response = app.test_client.get("/folder/test1") assert response.status == 404 - request, response = app.test_client.get('/folder/test-123') + request, response = app.test_client.get("/folder/test-123") assert response.status == 404 - request, response = app.test_client.get('/folder/') + request, response = app.test_client.get("/folder/") assert response.status == 200 def test_dynamic_add_route_unhashable(app): - async def handler(request, unhashable): - return text('OK') + return text("OK") - app.add_route(handler, '/folder//end/') + app.add_route(handler, "/folder//end/") - request, response = app.test_client.get('/folder/test/asdf/end/') + request, response = app.test_client.get("/folder/test/asdf/end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test///////end/') + request, response = app.test_client.get("/folder/test///////end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test/end/') + request, response = app.test_client.get("/folder/test/end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test/nope/') + request, response = app.test_client.get("/folder/test/nope/") assert response.status == 404 def test_add_route_duplicate(app): with pytest.raises(RouteExists): + async def handler1(request): pass async def handler2(request): pass - app.add_route(handler1, '/test') - app.add_route(handler2, '/test') + app.add_route(handler1, "/test") + app.add_route(handler2, "/test") with pytest.raises(RouteExists): + async def handler1(request, dynamic): pass async def handler2(request, dynamic): pass - app.add_route(handler1, '/test//') - app.add_route(handler2, '/test//') + app.add_route(handler1, "/test//") + app.add_route(handler2, "/test//") def test_add_route_method_not_allowed(app): - async def handler(request): - return text('OK') + return text("OK") - app.add_route(handler, '/test', methods=['GET']) + app.add_route(handler, "/test", methods=["GET"]) - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 200 - request, response = app.test_client.post('/test') + request, response = app.test_client.post("/test") assert response.status == 405 def test_remove_static_route(app): - async def handler1(request): - return text('OK1') + return text("OK1") async def handler2(request): - return text('OK2') + return text("OK2") - app.add_route(handler1, '/test') - app.add_route(handler2, '/test2') + app.add_route(handler1, "/test") + app.add_route(handler2, "/test2") - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 200 - request, response = app.test_client.get('/test2') + request, response = app.test_client.get("/test2") assert response.status == 200 - app.remove_route('/test') - app.remove_route('/test2') + app.remove_route("/test") + app.remove_route("/test2") - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 404 - request, response = app.test_client.get('/test2') + request, response = app.test_client.get("/test2") assert response.status == 404 def test_remove_dynamic_route(app): - async def handler(request, name): - return text('OK') + return text("OK") - app.add_route(handler, '/folder/') + app.add_route(handler, "/folder/") - request, response = app.test_client.get('/folder/test123') + request, response = app.test_client.get("/folder/test123") assert response.status == 200 - app.remove_route('/folder/') - request, response = app.test_client.get('/folder/test123') + app.remove_route("/folder/") + request, response = app.test_client.get("/folder/test123") assert response.status == 404 def test_remove_inexistent_route(app): - uri = '/test' + uri = "/test" with pytest.raises(RouteDoesNotExist) as excinfo: app.remove_route(uri) - assert str(excinfo.value) == 'Route was not registered: {}'.format(uri) + assert str(excinfo.value) == "Route was not registered: {}".format(uri) def test_removing_slash(app): - - @app.get('/rest/') + @app.get("/rest/") def get(_): pass - @app.post('/rest/') + @app.post("/rest/") def post(_): pass @@ -807,177 +814,171 @@ def test_removing_slash(app): def test_remove_unhashable_route(app): - async def handler(request, unhashable): - return text('OK') + return text("OK") - app.add_route(handler, '/folder//end/') + app.add_route(handler, "/folder//end/") - request, response = app.test_client.get('/folder/test/asdf/end/') + request, response = app.test_client.get("/folder/test/asdf/end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test///////end/') + request, response = app.test_client.get("/folder/test///////end/") assert response.status == 200 - request, response = app.test_client.get('/folder/test/end/') + request, response = app.test_client.get("/folder/test/end/") assert response.status == 200 - app.remove_route('/folder//end/') + app.remove_route("/folder//end/") - request, response = app.test_client.get('/folder/test/asdf/end/') + request, response = app.test_client.get("/folder/test/asdf/end/") assert response.status == 404 - request, response = app.test_client.get('/folder/test///////end/') + request, response = app.test_client.get("/folder/test///////end/") assert response.status == 404 - request, response = app.test_client.get('/folder/test/end/') + request, response = app.test_client.get("/folder/test/end/") assert response.status == 404 def test_remove_route_without_clean_cache(app): - async def handler(request): - return text('OK') + return text("OK") - app.add_route(handler, '/test') + app.add_route(handler, "/test") - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 200 - app.remove_route('/test', clean_cache=True) - app.remove_route('/test/', clean_cache=True) + app.remove_route("/test", clean_cache=True) + app.remove_route("/test/", clean_cache=True) - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 404 - app.add_route(handler, '/test') + app.add_route(handler, "/test") - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 200 - app.remove_route('/test', clean_cache=False) + app.remove_route("/test", clean_cache=False) - request, response = app.test_client.get('/test') + request, response = app.test_client.get("/test") assert response.status == 200 def test_overload_routes(app): - - @app.route('/overload', methods=['GET']) + @app.route("/overload", methods=["GET"]) async def handler1(request): - return text('OK1') + return text("OK1") - @app.route('/overload', methods=['POST', 'PUT']) + @app.route("/overload", methods=["POST", "PUT"]) async def handler2(request): - return text('OK2') + return text("OK2") - request, response = app.test_client.get('/overload') - assert response.text == 'OK1' + request, response = app.test_client.get("/overload") + assert response.text == "OK1" - request, response = app.test_client.post('/overload') - assert response.text == 'OK2' + request, response = app.test_client.post("/overload") + assert response.text == "OK2" - request, response = app.test_client.put('/overload') - assert response.text == 'OK2' + request, response = app.test_client.put("/overload") + assert response.text == "OK2" - request, response = app.test_client.delete('/overload') + request, response = app.test_client.delete("/overload") assert response.status == 405 with pytest.raises(RouteExists): - @app.route('/overload', methods=['PUT', 'DELETE']) + + @app.route("/overload", methods=["PUT", "DELETE"]) async def handler3(request): - return text('Duplicated') + return text("Duplicated") def test_unmergeable_overload_routes(app): - - @app.route('/overload_whole', methods=None) + @app.route("/overload_whole", methods=None) async def handler1(request): - return text('OK1') + return text("OK1") with pytest.raises(RouteExists): - @app.route('/overload_whole', methods=['POST', 'PUT']) + + @app.route("/overload_whole", methods=["POST", "PUT"]) async def handler2(request): - return text('Duplicated') + return text("Duplicated") - request, response = app.test_client.get('/overload_whole') - assert response.text == 'OK1' + request, response = app.test_client.get("/overload_whole") + assert response.text == "OK1" - request, response = app.test_client.post('/overload_whole') - assert response.text == 'OK1' + request, response = app.test_client.post("/overload_whole") + assert response.text == "OK1" - @app.route('/overload_part', methods=['GET']) + @app.route("/overload_part", methods=["GET"]) async def handler3(request): - return text('OK1') + return text("OK1") with pytest.raises(RouteExists): - @app.route('/overload_part') + + @app.route("/overload_part") async def handler4(request): - return text('Duplicated') + return text("Duplicated") - request, response = app.test_client.get('/overload_part') - assert response.text == 'OK1' + request, response = app.test_client.get("/overload_part") + assert response.text == "OK1" - request, response = app.test_client.post('/overload_part') + request, response = app.test_client.post("/overload_part") assert response.status == 405 def test_unicode_routes(app): - - @app.get('/你好') + @app.get("/你好") def handler1(request): - return text('OK1') + return text("OK1") - request, response = app.test_client.get('/你好') - assert response.text == 'OK1' + request, response = app.test_client.get("/你好") + assert response.text == "OK1" - @app.route('/overload/', methods=['GET']) + @app.route("/overload/", methods=["GET"]) async def handler2(request, param): - return text('OK2 ' + param) + return text("OK2 " + param) - request, response = app.test_client.get('/overload/你好') - assert response.text == 'OK2 你好' + request, response = app.test_client.get("/overload/你好") + assert response.text == "OK2 你好" def test_uri_with_different_method_and_different_params(app): - - @app.route('/ads/', methods=['GET']) + @app.route("/ads/", methods=["GET"]) async def ad_get(request, ad_id): - return json({'ad_id': ad_id}) + return json({"ad_id": ad_id}) - @app.route('/ads/', methods=['POST']) + @app.route("/ads/", methods=["POST"]) async def ad_post(request, action): - return json({'action': action}) + return json({"action": action}) - request, response = app.test_client.get('/ads/1234') + request, response = app.test_client.get("/ads/1234") assert response.status == 200 - assert response.json == { - 'ad_id': '1234' - } + assert response.json == {"ad_id": "1234"} - request, response = app.test_client.post('/ads/post') + request, response = app.test_client.post("/ads/post") assert response.status == 200 - assert response.json == { - 'action': 'post' - } + assert response.json == {"action": "post"} def test_route_raise_ParameterNameConflicts(app): with pytest.raises(ParameterNameConflicts): - @app.get('/api/v1///') + + @app.get("/api/v1///") def handler(request, user): - return text('OK') + return text("OK") def test_route_invalid_host(app): host = 321 with pytest.raises(ValueError) as excinfo: - @app.get('/test', host=host) + + @app.get("/test", host=host) def handler(request): - return text('pass') + return text("pass") assert str(excinfo.value) == ( - "Expected either string or Iterable of " - "host strings, not {!r}" + "Expected either string or Iterable of " "host strings, not {!r}" ).format(host) diff --git a/tests/test_server_events.py b/tests/test_server_events.py index 64972271..0dc344df 100644 --- a/tests/test_server_events.py +++ b/tests/test_server_events.py @@ -5,30 +5,30 @@ import pytest from sanic.testing import HOST, PORT AVAILABLE_LISTENERS = [ - 'before_server_start', - 'after_server_start', - 'before_server_stop', - 'after_server_stop' + "before_server_start", + "after_server_start", + "before_server_stop", + "after_server_stop", ] skipif_no_alarm = pytest.mark.skipif( - not hasattr(signal, 'SIGALRM'), - reason='SIGALRM is not implemented for this platform, we have to come ' - 'up with another timeout strategy to test these' + not hasattr(signal, "SIGALRM"), + reason="SIGALRM is not implemented for this platform, we have to come " + "up with another timeout strategy to test these", ) def create_listener(listener_name, in_list): async def _listener(app, loop): - print('DEBUG MESSAGE FOR PYTEST for {}'.format(listener_name)) + print("DEBUG MESSAGE FOR PYTEST for {}".format(listener_name)) in_list.insert(0, app.name + listener_name) + return _listener def start_stop_app(random_name_app, **run_kwargs): - def stop_on_alarm(signum, frame): - raise KeyboardInterrupt('SIGINT for sanic to stop gracefully') + raise KeyboardInterrupt("SIGINT for sanic to stop gracefully") signal.signal(signal.SIGALRM, stop_on_alarm) signal.alarm(1) @@ -39,19 +39,18 @@ def start_stop_app(random_name_app, **run_kwargs): @skipif_no_alarm -@pytest.mark.parametrize('listener_name', AVAILABLE_LISTENERS) +@pytest.mark.parametrize("listener_name", AVAILABLE_LISTENERS) def test_single_listener(app, listener_name): """Test that listeners on their own work""" output = [] # Register listener - app.listener(listener_name)( - create_listener(listener_name, output)) + app.listener(listener_name)(create_listener(listener_name, output)) start_stop_app(app) assert app.name + listener_name == output.pop() @skipif_no_alarm -@pytest.mark.parametrize('listener_name', AVAILABLE_LISTENERS) +@pytest.mark.parametrize("listener_name", AVAILABLE_LISTENERS) def test_register_listener(app, listener_name): """ Test that listeners on their own work with @@ -77,11 +76,10 @@ def test_all_listeners(app): async def test_trigger_before_events_create_server(app): - class MySanicDb: pass - @app.listener('before_server_start') + @app.listener("before_server_start") async def init_db(app, loop): app.db = MySanicDb() diff --git a/tests/test_signal_handlers.py b/tests/test_signal_handlers.py index af8b0bb5..7a49a348 100644 --- a/tests/test_signal_handlers.py +++ b/tests/test_signal_handlers.py @@ -9,6 +9,7 @@ async def stop(app, loop): await asyncio.sleep(0.1) app.stop() + calledq = Queue() @@ -23,13 +24,13 @@ def after(app, loop): def test_register_system_signals(app): """Test if sanic register system signals""" - @app.route('/hello') + @app.route("/hello") async def hello_route(request): return HTTPResponse() - app.listener('after_server_start')(stop) - app.listener('before_server_start')(set_loop) - app.listener('after_server_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() is True @@ -38,13 +39,13 @@ def test_register_system_signals(app): def test_dont_register_system_signals(app): """Test if sanic don't register system signals""" - @app.route('/hello') + @app.route("/hello") async def hello_route(request): return HTTPResponse() - app.listener('after_server_start')(stop) - app.listener('before_server_start')(set_loop) - app.listener('after_server_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, register_sys_signals=False) assert calledq.get() is False diff --git a/tests/test_static.py b/tests/test_static.py index c1ee899c..43078a9d 100644 --- a/tests/test_static.py +++ b/tests/test_static.py @@ -5,12 +5,12 @@ from time import gmtime, strftime import pytest -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def static_file_directory(): """The static directory to serve""" current_file = inspect.getfile(inspect.currentframe()) current_directory = os.path.dirname(os.path.abspath(current_file)) - static_directory = os.path.join(current_directory, 'static') + static_directory = os.path.join(current_directory, "static") return static_directory @@ -20,336 +20,376 @@ def get_file_path(static_file_directory, file_name): def get_file_content(static_file_directory, file_name): """The content of the static file to check""" - with open(get_file_path(static_file_directory, file_name), 'rb') as file: + with open(get_file_path(static_file_directory, file_name), "rb") as file: return file.read() -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def large_file(static_file_directory): - large_file_path = os.path.join(static_file_directory, 'large.file') + large_file_path = os.path.join(static_file_directory, "large.file") size = 2 * 1024 * 1024 - with open(large_file_path, 'w') as f: - f.write('a' * size) + with open(large_file_path, "w") as f: + f.write("a" * size) yield large_file_path os.remove(large_file_path) -@pytest.fixture(autouse=True, scope='module') +@pytest.fixture(autouse=True, scope="module") def symlink(static_file_directory): - src = os.path.abspath(os.path.join(os.path.dirname(static_file_directory), 'conftest.py')) - symlink = 'symlink' + src = os.path.abspath( + os.path.join(os.path.dirname(static_file_directory), "conftest.py") + ) + symlink = "symlink" dist = os.path.join(static_file_directory, symlink) os.symlink(src, dist) yield symlink os.remove(dist) -@pytest.fixture(autouse=True, scope='module') +@pytest.fixture(autouse=True, scope="module") def hard_link(static_file_directory): - src = os.path.abspath(os.path.join(os.path.dirname(static_file_directory), 'conftest.py')) - hard_link = 'hard_link' + src = os.path.abspath( + os.path.join(os.path.dirname(static_file_directory), "conftest.py") + ) + hard_link = "hard_link" dist = os.path.join(static_file_directory, hard_link) os.link(src, dist) yield hard_link os.remove(dist) -@pytest.mark.parametrize('file_name', - ['test.file', 'decode me.txt', 'python.png', 'symlink', 'hard_link']) +@pytest.mark.parametrize( + "file_name", + ["test.file", "decode me.txt", "python.png", "symlink", "hard_link"], +) def test_static_file(app, static_file_directory, file_name): app.static( - '/testing.file', get_file_path(static_file_directory, file_name)) - - request, response = app.test_client.get('/testing.file') - assert response.status == 200 - assert response.body == get_file_content(static_file_directory, file_name) - - -@pytest.mark.parametrize('file_name', ['test.html']) -def test_static_file_content_type(app, static_file_directory, file_name): - app.static( - '/testing.file', - get_file_path(static_file_directory, file_name), - content_type='text/html; charset=utf-8' + "/testing.file", get_file_path(static_file_directory, file_name) ) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.get("/testing.file") assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) - assert response.headers['Content-Type'] == 'text/html; charset=utf-8' -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt', 'symlink', 'hard_link']) -@pytest.mark.parametrize('base_uri', ['/static', '', '/dir']) +@pytest.mark.parametrize("file_name", ["test.html"]) +def test_static_file_content_type(app, static_file_directory, file_name): + app.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + content_type="text/html; charset=utf-8", + ) + + request, response = app.test_client.get("/testing.file") + assert response.status == 200 + assert response.body == get_file_content(static_file_directory, file_name) + assert response.headers["Content-Type"] == "text/html; charset=utf-8" + + +@pytest.mark.parametrize( + "file_name", ["test.file", "decode me.txt", "symlink", "hard_link"] +) +@pytest.mark.parametrize("base_uri", ["/static", "", "/dir"]) def test_static_directory(app, file_name, base_uri, static_file_directory): app.static(base_uri, static_file_directory) request, response = app.test_client.get( - uri='{}/{}'.format(base_uri, file_name)) + uri="{}/{}".format(base_uri, file_name) + ) assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_head_request(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) - - request, response = app.test_client.head('/testing.file') - assert response.status == 200 - assert 'Accept-Ranges' in response.headers - assert 'Content-Length' in response.headers - assert int(response.headers[ - 'Content-Length']) == len( - get_file_content(static_file_directory, file_name)) - - -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_correct(app, file_name, static_file_directory): - app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) - - headers = { - 'Range': 'bytes=12-19' - } - request, response = app.test_client.get('/testing.file', headers=headers) - assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[12:20] - assert int(response.headers[ - 'Content-Length']) == len(static_content) - assert response.body == static_content - - -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_front(app, file_name, static_file_directory): - app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) - - headers = { - 'Range': 'bytes=12-' - } - request, response = app.test_client.get('/testing.file', headers=headers) - assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[12:] - assert int(response.headers[ - 'Content-Length']) == len(static_content) - assert response.body == static_content - - -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_back(app, file_name, static_file_directory): - app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) - - headers = { - 'Range': 'bytes=-12' - } - request, response = app.test_client.get('/testing.file', headers=headers) - assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[-12:] - assert int(response.headers[ - 'Content-Length']) == len(static_content) - assert response.body == static_content - - -@pytest.mark.parametrize('use_modified_since', [True, False]) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_empty(app, file_name, static_file_directory, use_modified_since): - app.static( - '/testing.file', + "/testing.file", get_file_path(static_file_directory, file_name), use_content_range=True, - use_modified_since=use_modified_since ) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.head("/testing.file") assert response.status == 200 - assert 'Content-Length' in response.headers - assert 'Content-Range' not in response.headers - assert int(response.headers['Content-Length']) == \ - len(get_file_content(static_file_directory, file_name)) + assert "Accept-Ranges" in response.headers + assert "Content-Length" in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) + + +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_correct(app, file_name, static_file_directory): + app.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) + + headers = {"Range": "bytes=12-19"} + request, response = app.test_client.get("/testing.file", headers=headers) + assert response.status == 206 + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + 12:20 + ] + assert int(response.headers["Content-Length"]) == len(static_content) + assert response.body == static_content + + +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_front(app, file_name, static_file_directory): + app.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) + + headers = {"Range": "bytes=12-"} + request, response = app.test_client.get("/testing.file", headers=headers) + assert response.status == 206 + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + 12: + ] + assert int(response.headers["Content-Length"]) == len(static_content) + assert response.body == static_content + + +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_back(app, file_name, static_file_directory): + app.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) + + headers = {"Range": "bytes=-12"} + request, response = app.test_client.get("/testing.file", headers=headers) + assert response.status == 206 + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + -12: + ] + assert int(response.headers["Content-Length"]) == len(static_content) + assert response.body == static_content + + +@pytest.mark.parametrize("use_modified_since", [True, False]) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_empty( + app, file_name, static_file_directory, use_modified_since +): + app.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + use_modified_since=use_modified_since, + ) + + request, response = app.test_client.get("/testing.file") + assert response.status == 200 + assert "Content-Length" in response.headers + assert "Content-Range" not in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) assert response.body == bytes( - get_file_content(static_file_directory, file_name)) + get_file_content(static_file_directory, file_name) + ) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_error(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - headers = { - 'Range': 'bytes=1-0' - } - request, response = app.test_client.get('/testing.file', headers=headers) + headers = {"Range": "bytes=1-0"} + request, response = app.test_client.get("/testing.file", headers=headers) assert response.status == 416 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - assert response.headers['Content-Range'] == "bytes */%s" % ( - len(get_file_content(static_file_directory, file_name)),) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + assert response.headers["Content-Range"] == "bytes */%s" % ( + len(get_file_content(static_file_directory, file_name)), + ) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_invalid_unit(app, file_name, static_file_directory): +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_invalid_unit( + app, file_name, static_file_directory +): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - unit = 'bit' - headers = { - 'Range': '{}=1-0'.format(unit) - } - request, response = app.test_client.get('/testing.file', headers=headers) + unit = "bit" + headers = {"Range": "{}=1-0".format(unit)} + request, response = app.test_client.get("/testing.file", headers=headers) assert response.status == 416 assert response.text == "Error: {} is not a valid Range Type".format(unit) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_invalid_start(app, file_name, static_file_directory): +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_invalid_start( + app, file_name, static_file_directory +): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - start = 'start' - headers = { - 'Range': 'bytes={}-0'.format(start) - } - request, response = app.test_client.get('/testing.file', headers=headers) + start = "start" + headers = {"Range": "bytes={}-0".format(start)} + request, response = app.test_client.get("/testing.file", headers=headers) assert response.status == 416 - assert response.text == "Error: '{}' is invalid for Content Range".format(start) + assert response.text == "Error: '{}' is invalid for Content Range".format( + start + ) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_invalid_end(app, file_name, static_file_directory): +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_invalid_end( + app, file_name, static_file_directory +): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - end = 'end' - headers = { - 'Range': 'bytes=1-{}'.format(end) - } - request, response = app.test_client.get('/testing.file', headers=headers) + end = "end" + headers = {"Range": "bytes=1-{}".format(end)} + request, response = app.test_client.get("/testing.file", headers=headers) assert response.status == 416 - assert response.text == "Error: '{}' is invalid for Content Range".format(end) + assert response.text == "Error: '{}' is invalid for Content Range".format( + end + ) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -def test_static_content_range_invalid_parameters(app, file_name, static_file_directory): +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +def test_static_content_range_invalid_parameters( + app, file_name, static_file_directory +): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - headers = { - 'Range': 'bytes=-' - } - request, response = app.test_client.get('/testing.file', headers=headers) + headers = {"Range": "bytes=-"} + request, response = app.test_client.get("/testing.file", headers=headers) assert response.status == 416 assert response.text == "Error: Invalid for Content Range parameters" -@pytest.mark.parametrize('file_name', - ['test.file', 'decode me.txt', 'python.png']) +@pytest.mark.parametrize( + "file_name", ["test.file", "decode me.txt", "python.png"] +) def test_static_file_specified_host(app, static_file_directory, file_name): app.static( - '/testing.file', + "/testing.file", get_file_path(static_file_directory, file_name), - host="www.example.com" + host="www.example.com", ) headers = {"Host": "www.example.com"} - request, response = app.test_client.get('/testing.file', headers=headers) + request, response = app.test_client.get("/testing.file", headers=headers) assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.get("/testing.file") assert response.status == 404 -@pytest.mark.parametrize('use_modified_since', [True, False]) -@pytest.mark.parametrize('stream_large_files', [True, 1024]) -@pytest.mark.parametrize('file_name', ['test.file', 'large.file']) -def test_static_stream_large_file(app, static_file_directory, file_name, use_modified_since, stream_large_files, large_file): +@pytest.mark.parametrize("use_modified_since", [True, False]) +@pytest.mark.parametrize("stream_large_files", [True, 1024]) +@pytest.mark.parametrize("file_name", ["test.file", "large.file"]) +def test_static_stream_large_file( + app, + static_file_directory, + file_name, + use_modified_since, + stream_large_files, + large_file, +): app.static( - '/testing.file', + "/testing.file", get_file_path(static_file_directory, file_name), use_modified_since=use_modified_since, - stream_large_files=stream_large_files + stream_large_files=stream_large_files, ) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.get("/testing.file") assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt', 'python.png']) +@pytest.mark.parametrize( + "file_name", ["test.file", "decode me.txt", "python.png"] +) def test_use_modified_since(app, static_file_directory, file_name): file_stat = os.stat(get_file_path(static_file_directory, file_name)) - modified_since = strftime("%a, %d %b %Y %H:%M:%S GMT", gmtime(file_stat.st_mtime)) + modified_since = strftime( + "%a, %d %b %Y %H:%M:%S GMT", gmtime(file_stat.st_mtime) + ) app.static( - '/testing.file', + "/testing.file", get_file_path(static_file_directory, file_name), - use_modified_since=True + use_modified_since=True, ) request, response = app.test_client.get( - '/testing.file', headers={'If-Modified-Since': modified_since}) + "/testing.file", headers={"If-Modified-Since": modified_since} + ) assert response.status == 304 def test_file_not_found(app, static_file_directory): - app.static('/static', static_file_directory) + app.static("/static", static_file_directory) - request, response = app.test_client.get('/static/not_found') + request, response = app.test_client.get("/static/not_found") assert response.status == 404 - assert response.text == 'Error: File not found' + assert response.text == "Error: File not found" -@pytest.mark.parametrize('static_name', ['_static_name', 'static']) -@pytest.mark.parametrize('file_name', ['test.html']) +@pytest.mark.parametrize("static_name", ["_static_name", "static"]) +@pytest.mark.parametrize("file_name", ["test.html"]) def test_static_name(app, static_file_directory, static_name, file_name): - app.static('/static', static_file_directory, name=static_name) + app.static("/static", static_file_directory, name=static_name) - request, response = app.test_client.get('/static/{}'.format(file_name)) + request, response = app.test_client.get("/static/{}".format(file_name)) assert response.status == 200 -@pytest.mark.parametrize('file_name', - ['test.file']) +@pytest.mark.parametrize("file_name", ["test.file"]) def test_static_remove_route(app, static_file_directory, file_name): app.static( - '/testing.file', - get_file_path(static_file_directory, file_name) + "/testing.file", get_file_path(static_file_directory, file_name) ) - request, response = app.test_client.get('/testing.file') + request, response = app.test_client.get("/testing.file") assert response.status == 200 - app.remove_route('/testing.file') - request, response = app.test_client.get('/testing.file') + app.remove_route("/testing.file") + request, response = app.test_client.get("/testing.file") assert response.status == 404 diff --git a/tests/test_url_building.py b/tests/test_url_building.py index 1b3ce1b9..6145b064 100644 --- a/tests/test_url_building.py +++ b/tests/test_url_building.py @@ -9,27 +9,39 @@ from sanic.exceptions import URLBuildError import string -URL_FOR_ARGS1 = dict(arg1=['v1', 'v2']) -URL_FOR_VALUE1 = '/myurl?arg1=v1&arg1=v2' -URL_FOR_ARGS2 = dict(arg1=['v1', 'v2'], _anchor='anchor') -URL_FOR_VALUE2 = '/myurl?arg1=v1&arg1=v2#anchor' +URL_FOR_ARGS1 = dict(arg1=["v1", "v2"]) +URL_FOR_VALUE1 = "/myurl?arg1=v1&arg1=v2" +URL_FOR_ARGS2 = dict(arg1=["v1", "v2"], _anchor="anchor") +URL_FOR_VALUE2 = "/myurl?arg1=v1&arg1=v2#anchor" URL_FOR_ARGS3 = dict( - arg1='v1', _anchor='anchor', _scheme='http', - _server='{}:{}'.format(test_host, test_port), _external=True + arg1="v1", + _anchor="anchor", + _scheme="http", + _server="{}:{}".format(test_host, test_port), + _external=True, +) +URL_FOR_VALUE3 = "http://{}:{}/myurl?arg1=v1#anchor".format( + test_host, test_port +) +URL_FOR_ARGS4 = dict( + arg1="v1", + _anchor="anchor", + _external=True, + _server="http://{}:{}".format(test_host, test_port), +) +URL_FOR_VALUE4 = "http://{}:{}/myurl?arg1=v1#anchor".format( + test_host, test_port ) -URL_FOR_VALUE3 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host, - test_port) -URL_FOR_ARGS4 = dict(arg1='v1', _anchor='anchor', _external=True, - _server='http://{}:{}'.format(test_host, test_port)) -URL_FOR_VALUE4 = 'http://{}:{}/myurl?arg1=v1#anchor'.format(test_host, - test_port) def _generate_handlers_from_names(app, l): for name in l: # this is the easiest way to generate functions with dynamic names - exec('@app.route(name)\ndef {}(request):\n\treturn text("{}")'.format( - name, name)) + exec( + '@app.route(name)\ndef {}(request):\n\treturn text("{}")'.format( + name, name + ) + ) @pytest.fixture @@ -45,69 +57,69 @@ def test_simple_url_for_getting(simple_app): for letter in string.ascii_letters: url = simple_app.url_for(letter) - assert url == '/{}'.format(letter) + assert url == "/{}".format(letter) request, response = simple_app.test_client.get(url) assert response.status == 200 assert response.text == letter -@pytest.mark.parametrize('args,url', - [(URL_FOR_ARGS1, URL_FOR_VALUE1), - (URL_FOR_ARGS2, URL_FOR_VALUE2), - (URL_FOR_ARGS3, URL_FOR_VALUE3), - (URL_FOR_ARGS4, URL_FOR_VALUE4)]) +@pytest.mark.parametrize( + "args,url", + [ + (URL_FOR_ARGS1, URL_FOR_VALUE1), + (URL_FOR_ARGS2, URL_FOR_VALUE2), + (URL_FOR_ARGS3, URL_FOR_VALUE3), + (URL_FOR_ARGS4, URL_FOR_VALUE4), + ], +) def test_simple_url_for_getting_with_more_params(app, args, url): - - @app.route('/myurl') + @app.route("/myurl") def passes(request): - return text('this should pass') + return text("this should pass") - assert url == app.url_for('passes', **args) + assert url == app.url_for("passes", **args) request, response = app.test_client.get(url) assert response.status == 200 - assert response.text == 'this should pass' + assert response.text == "this should pass" def test_url_for_with_server_name(app): - server_name = '{}:{}'.format(test_host, test_port) - app.config.update({ - 'SERVER_NAME': server_name - }) - path = '/myurl' + server_name = "{}:{}".format(test_host, test_port) + app.config.update({"SERVER_NAME": server_name}) + path = "/myurl" @app.route(path) def passes(request): - return text('this should pass') + return text("this should pass") - url = 'http://{}{}'.format(server_name, path) - assert url == app.url_for('passes', _server=None, _external=True) + url = "http://{}{}".format(server_name, path) + assert url == app.url_for("passes", _server=None, _external=True) request, response = app.test_client.get(url) assert response.status == 200 - assert response.text == 'this should pass' + assert response.text == "this should pass" def test_fails_if_endpoint_not_found(app): - - @app.route('/fail') + @app.route("/fail") def fail(request): - return text('this should fail') + return text("this should fail") with pytest.raises(URLBuildError) as e: - app.url_for('passes') + app.url_for("passes") - assert str(e.value) == 'Endpoint with name `passes` was not found' + assert str(e.value) == "Endpoint with name `passes` was not found" def test_fails_url_build_if_param_not_passed(app): - url = '/' + url = "/" for letter in string.ascii_letters: - url += '<{}>/'.format(letter) + url += "<{}>/".format(letter) @app.route(url) def fail(request): - return text('this should fail') + return text("this should fail") fail_args = list(string.ascii_letters) fail_args.pop() @@ -115,130 +127,130 @@ def test_fails_url_build_if_param_not_passed(app): fail_kwargs = {l: l for l in fail_args} with pytest.raises(URLBuildError) as e: - app.url_for('fail', **fail_kwargs) + app.url_for("fail", **fail_kwargs) - assert 'Required parameter `Z` was not passed to url_for' in str(e.value) + assert "Required parameter `Z` was not passed to url_for" in str(e.value) def test_fails_url_build_if_params_not_passed(app): - - @app.route('/fail') + @app.route("/fail") def fail(request): - return text('this should fail') + return text("this should fail") with pytest.raises(ValueError) as e: - app.url_for('fail', _scheme='http') + app.url_for("fail", _scheme="http") - assert str(e.value) == 'When specifying _scheme, _external must be True' + assert str(e.value) == "When specifying _scheme, _external must be True" COMPLEX_PARAM_URL = ( - '///' - '//') + "///" + "//" +) PASSING_KWARGS = { - 'foo': 4, 'four_letter_string': 'woof', - 'two_letter_string': 'ba', 'normal_string': 'normal', - 'some_number': '1.001'} -EXPECTED_BUILT_URL = '/4/woof/ba/normal/1.001' + "foo": 4, + "four_letter_string": "woof", + "two_letter_string": "ba", + "normal_string": "normal", + "some_number": "1.001", +} +EXPECTED_BUILT_URL = "/4/woof/ba/normal/1.001" def test_fails_with_int_message(app): - @app.route(COMPLEX_PARAM_URL) def fail(request): - return text('this should fail') + return text("this should fail") failing_kwargs = dict(PASSING_KWARGS) - failing_kwargs['foo'] = 'not_int' + failing_kwargs["foo"] = "not_int" with pytest.raises(URLBuildError) as e: - app.url_for('fail', **failing_kwargs) + app.url_for("fail", **failing_kwargs) expected_error = ( 'Value "not_int" for parameter `foo` ' - 'does not match pattern for type `int`: \d+') + "does not match pattern for type `int`: \d+" + ) assert str(e.value) == expected_error def test_fails_with_two_letter_string_message(app): - @app.route(COMPLEX_PARAM_URL) def fail(request): - return text('this should fail') + return text("this should fail") failing_kwargs = dict(PASSING_KWARGS) - failing_kwargs['two_letter_string'] = 'foobar' + failing_kwargs["two_letter_string"] = "foobar" with pytest.raises(URLBuildError) as e: - app.url_for('fail', **failing_kwargs) + app.url_for("fail", **failing_kwargs) expected_error = ( 'Value "foobar" for parameter `two_letter_string` ' - 'does not satisfy pattern [A-z]{2}') + "does not satisfy pattern [A-z]{2}" + ) assert str(e.value) == expected_error def test_fails_with_number_message(app): - @app.route(COMPLEX_PARAM_URL) def fail(request): - return text('this should fail') + return text("this should fail") failing_kwargs = dict(PASSING_KWARGS) - failing_kwargs['some_number'] = 'foo' + failing_kwargs["some_number"] = "foo" with pytest.raises(URLBuildError) as e: - app.url_for('fail', **failing_kwargs) + app.url_for("fail", **failing_kwargs) expected_error = ( 'Value "foo" for parameter `some_number` ' - 'does not match pattern for type `float`: [0-9\\\\.]+') + "does not match pattern for type `float`: [0-9\\\\.]+" + ) assert str(e.value) == expected_error def test_adds_other_supplied_values_as_query_string(app): - @app.route(COMPLEX_PARAM_URL) def passes(request): - return text('this should pass') + return text("this should pass") new_kwargs = dict(PASSING_KWARGS) - new_kwargs['added_value_one'] = 'one' - new_kwargs['added_value_two'] = 'two' + new_kwargs["added_value_one"] = "one" + new_kwargs["added_value_two"] = "two" - url = app.url_for('passes', **new_kwargs) + url = app.url_for("passes", **new_kwargs) query = dict(parse_qsl(urlsplit(url).query)) - assert query['added_value_one'] == 'one' - assert query['added_value_two'] == 'two' + assert query["added_value_one"] == "one" + assert query["added_value_two"] == "two" @pytest.fixture def blueprint_app(app): - first_print = Blueprint('first', url_prefix='/first') - second_print = Blueprint('second', url_prefix='/second') + first_print = Blueprint("first", url_prefix="/first") + second_print = Blueprint("second", url_prefix="/second") - @first_print.route('/foo') + @first_print.route("/foo") def foo(request): - return text('foo from first') + return text("foo from first") - @first_print.route('/foo/') + @first_print.route("/foo/") def foo_with_param(request, param): - return text( - 'foo from first : {}'.format(param)) + return text("foo from first : {}".format(param)) - @second_print.route('/foo') # noqa + @second_print.route("/foo") # noqa def foo(request): - return text('foo from second') + return text("foo from second") - @second_print.route('/foo/') # noqa + @second_print.route("/foo/") # noqa def foo_with_param(request, param): - return text( - 'foo from second : {}'.format(param)) + return text("foo from second : {}".format(param)) app.blueprint(first_print) app.blueprint(second_print) @@ -247,66 +259,65 @@ def blueprint_app(app): def test_blueprints_are_named_correctly(blueprint_app): - first_url = blueprint_app.url_for('first.foo') - assert first_url == '/first/foo' + first_url = blueprint_app.url_for("first.foo") + assert first_url == "/first/foo" - second_url = blueprint_app.url_for('second.foo') - assert second_url == '/second/foo' + second_url = blueprint_app.url_for("second.foo") + assert second_url == "/second/foo" def test_blueprints_work_with_params(blueprint_app): - first_url = blueprint_app.url_for('first.foo_with_param', param='bar') - assert first_url == '/first/foo/bar' + first_url = blueprint_app.url_for("first.foo_with_param", param="bar") + assert first_url == "/first/foo/bar" - second_url = blueprint_app.url_for('second.foo_with_param', param='bar') - assert second_url == '/second/foo/bar' + second_url = blueprint_app.url_for("second.foo_with_param", param="bar") + assert second_url == "/second/foo/bar" @pytest.fixture def methodview_app(app): - class ViewOne(HTTPMethodView): def get(self, request): - return text('I am get method') + return text("I am get method") def post(self, request): - return text('I am post method') + return text("I am post method") def put(self, request): - return text('I am put method') + return text("I am put method") def patch(self, request): - return text('I am patch method') + return text("I am patch method") def delete(self, request): - return text('I am delete method') + return text("I am delete method") - app.add_route(ViewOne.as_view('view_one'), '/view_one') + app.add_route(ViewOne.as_view("view_one"), "/view_one") class ViewTwo(HTTPMethodView): def get(self, request): - return text('I am get method') + return text("I am get method") def post(self, request): - return text('I am post method') + return text("I am post method") def put(self, request): - return text('I am put method') + return text("I am put method") def patch(self, request): - return text('I am patch method') + return text("I am patch method") def delete(self, request): - return text('I am delete method') + return text("I am delete method") - app.add_route(ViewTwo.as_view(), '/view_two') + app.add_route(ViewTwo.as_view(), "/view_two") return app def test_methodview_naming(methodview_app): - viewone_url = methodview_app.url_for('ViewOne') - viewtwo_url = methodview_app.url_for('ViewTwo') + viewone_url = methodview_app.url_for("ViewOne") + viewtwo_url = methodview_app.url_for("ViewTwo") - assert viewone_url == '/view_one' - assert viewtwo_url == '/view_two' + assert viewone_url == "/view_one" + assert viewtwo_url == "/view_two" diff --git a/tests/test_url_for_static.py b/tests/test_url_for_static.py index 7b316aef..f5a426a3 100644 --- a/tests/test_url_for_static.py +++ b/tests/test_url_for_static.py @@ -6,12 +6,12 @@ import pytest from sanic.blueprints import Blueprint -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def static_file_directory(): """The static directory to serve""" current_file = inspect.getfile(inspect.currentframe()) current_directory = os.path.dirname(os.path.abspath(current_file)) - static_directory = os.path.join(current_directory, 'static') + static_directory = os.path.join(current_directory, "static") return static_directory @@ -21,24 +21,28 @@ def get_file_path(static_file_directory, file_name): def get_file_content(static_file_directory, file_name): """The content of the static file to check""" - with open(get_file_path(static_file_directory, file_name), 'rb') as file: + with open(get_file_path(static_file_directory, file_name), "rb") as file: return file.read() -@pytest.mark.parametrize('file_name', - ['test.file', 'decode me.txt', 'python.png']) +@pytest.mark.parametrize( + "file_name", ["test.file", "decode me.txt", "python.png"] +) def test_static_file(app, static_file_directory, file_name): app.static( - '/testing.file', get_file_path(static_file_directory, file_name)) + "/testing.file", get_file_path(static_file_directory, file_name) + ) app.static( - '/testing2.file', get_file_path(static_file_directory, file_name), - name='testing_file') + "/testing2.file", + get_file_path(static_file_directory, file_name), + name="testing_file", + ) - uri = app.url_for('static') - uri2 = app.url_for('static', filename='any') - uri3 = app.url_for('static', name='static', filename='any') + uri = app.url_for("static") + uri2 = app.url_for("static", filename="any") + uri3 = app.url_for("static", name="static", filename="any") - assert uri == '/testing.file' + assert uri == "/testing.file" assert uri == uri2 assert uri2 == uri3 @@ -46,23 +50,25 @@ def test_static_file(app, static_file_directory, file_name): assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) - bp = Blueprint('test_bp_static', url_prefix='/bp') + bp = Blueprint("test_bp_static", url_prefix="/bp") - bp.static('/testing.file', get_file_path(static_file_directory, file_name)) - bp.static('/testing2.file', - get_file_path(static_file_directory, file_name), - name='testing_file') + bp.static("/testing.file", get_file_path(static_file_directory, file_name)) + bp.static( + "/testing2.file", + get_file_path(static_file_directory, file_name), + name="testing_file", + ) app.blueprint(bp) - uri = app.url_for('static', name='test_bp_static.static') - uri2 = app.url_for('static', name='test_bp_static.static', filename='any') - uri3 = app.url_for('test_bp_static.static') - uri4 = app.url_for('test_bp_static.static', name='any') - uri5 = app.url_for('test_bp_static.static', filename='any') - uri6 = app.url_for('test_bp_static.static', name='any', filename='any') + uri = app.url_for("static", name="test_bp_static.static") + uri2 = app.url_for("static", name="test_bp_static.static", filename="any") + uri3 = app.url_for("test_bp_static.static") + uri4 = app.url_for("test_bp_static.static", name="any") + uri5 = app.url_for("test_bp_static.static", filename="any") + uri6 = app.url_for("test_bp_static.static", name="any", filename="any") - assert uri == '/bp/testing.file' + assert uri == "/bp/testing.file" assert uri == uri2 assert uri2 == uri3 assert uri3 == uri4 @@ -74,78 +80,87 @@ def test_static_file(app, static_file_directory, file_name): assert response.body == get_file_content(static_file_directory, file_name) # test for other parameters - uri = app.url_for('static', _external=True, _server='http://localhost') - assert uri == 'http://localhost/testing.file' + uri = app.url_for("static", _external=True, _server="http://localhost") + assert uri == "http://localhost/testing.file" - uri = app.url_for('static', name='test_bp_static.static', - _external=True, _server='http://localhost') - assert uri == 'http://localhost/bp/testing.file' + uri = app.url_for( + "static", + name="test_bp_static.static", + _external=True, + _server="http://localhost", + ) + assert uri == "http://localhost/bp/testing.file" # test for defined name - uri = app.url_for('static', name='testing_file') - assert uri == '/testing2.file' + uri = app.url_for("static", name="testing_file") + assert uri == "/testing2.file" request, response = app.test_client.get(uri) assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) - uri = app.url_for('static', name='test_bp_static.testing_file') - assert uri == '/bp/testing2.file' - assert uri == app.url_for('static', name='test_bp_static.testing_file', - filename='any') + uri = app.url_for("static", name="test_bp_static.testing_file") + assert uri == "/bp/testing2.file" + assert uri == app.url_for( + "static", name="test_bp_static.testing_file", filename="any" + ) request, response = app.test_client.get(uri) assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) -@pytest.mark.parametrize('base_uri', ['/static', '', '/dir']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) +@pytest.mark.parametrize("base_uri", ["/static", "", "/dir"]) def test_static_directory(app, file_name, base_uri, static_file_directory): app.static(base_uri, static_file_directory) - base_uri2 = base_uri + '/2' - app.static(base_uri2, static_file_directory, name='uploads') + base_uri2 = base_uri + "/2" + app.static(base_uri2, static_file_directory, name="uploads") - uri = app.url_for('static', name='static', filename=file_name) - assert uri == '{}/{}'.format(base_uri, file_name) + uri = app.url_for("static", name="static", filename=file_name) + assert uri == "{}/{}".format(base_uri, file_name) request, response = app.test_client.get(uri) assert response.status == 200 assert response.body == get_file_content(static_file_directory, file_name) - uri2 = app.url_for('static', name='static', filename='/' + file_name) - uri3 = app.url_for('static', filename=file_name) - uri4 = app.url_for('static', filename='/' + file_name) - uri5 = app.url_for('static', name='uploads', filename=file_name) - uri6 = app.url_for('static', name='uploads', filename='/' + file_name) + uri2 = app.url_for("static", name="static", filename="/" + file_name) + uri3 = app.url_for("static", filename=file_name) + uri4 = app.url_for("static", filename="/" + file_name) + uri5 = app.url_for("static", name="uploads", filename=file_name) + uri6 = app.url_for("static", name="uploads", filename="/" + file_name) assert uri == uri2 assert uri2 == uri3 assert uri3 == uri4 - assert uri5 == '{}/{}'.format(base_uri2, file_name) + assert uri5 == "{}/{}".format(base_uri2, file_name) assert uri5 == uri6 - bp = Blueprint('test_bp_static', url_prefix='/bp') + bp = Blueprint("test_bp_static", url_prefix="/bp") bp.static(base_uri, static_file_directory) - bp.static(base_uri2, static_file_directory, name='uploads') + bp.static(base_uri2, static_file_directory, name="uploads") app.blueprint(bp) - uri = app.url_for('static', name='test_bp_static.static', - filename=file_name) - uri2 = app.url_for('static', name='test_bp_static.static', - filename='/' + file_name) + uri = app.url_for( + "static", name="test_bp_static.static", filename=file_name + ) + uri2 = app.url_for( + "static", name="test_bp_static.static", filename="/" + file_name + ) - uri4 = app.url_for('static', name='test_bp_static.uploads', - filename=file_name) - uri5 = app.url_for('static', name='test_bp_static.uploads', - filename='/' + file_name) + uri4 = app.url_for( + "static", name="test_bp_static.uploads", filename=file_name + ) + uri5 = app.url_for( + "static", name="test_bp_static.uploads", filename="/" + file_name + ) - assert uri == '/bp{}/{}'.format(base_uri, file_name) + assert uri == "/bp{}/{}".format(base_uri, file_name) assert uri == uri2 - assert uri4 == '/bp{}/{}'.format(base_uri2, file_name) + assert uri4 == "/bp{}/{}".format(base_uri2, file_name) assert uri4 == uri5 request, response = app.test_client.get(uri) @@ -153,284 +168,323 @@ def test_static_directory(app, file_name, base_uri, static_file_directory): assert response.body == get_file_content(static_file_directory, file_name) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_head_request(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - bp = Blueprint('test_bp_static', url_prefix='/bp') - bp.static('/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + bp = Blueprint("test_bp_static", url_prefix="/bp") + bp.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) app.blueprint(bp) - uri = app.url_for('static') - assert uri == '/testing.file' - assert uri == app.url_for('static', name='static') - assert uri == app.url_for('static', name='static', filename='any') + uri = app.url_for("static") + assert uri == "/testing.file" + assert uri == app.url_for("static", name="static") + assert uri == app.url_for("static", name="static", filename="any") request, response = app.test_client.head(uri) assert response.status == 200 - assert 'Accept-Ranges' in response.headers - assert 'Content-Length' in response.headers - assert int(response.headers[ - 'Content-Length']) == len( - get_file_content(static_file_directory, file_name)) + assert "Accept-Ranges" in response.headers + assert "Content-Length" in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) # blueprint - uri = app.url_for('static', name='test_bp_static.static') - assert uri == '/bp/testing.file' - assert uri == app.url_for('static', name='test_bp_static.static', - filename='any') + uri = app.url_for("static", name="test_bp_static.static") + assert uri == "/bp/testing.file" + assert uri == app.url_for( + "static", name="test_bp_static.static", filename="any" + ) request, response = app.test_client.head(uri) assert response.status == 200 - assert 'Accept-Ranges' in response.headers - assert 'Content-Length' in response.headers - assert int(response.headers[ - 'Content-Length']) == len( - get_file_content(static_file_directory, file_name)) + assert "Accept-Ranges" in response.headers + assert "Content-Length" in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_correct(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - bp = Blueprint('test_bp_static', url_prefix='/bp') - bp.static('/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + bp = Blueprint("test_bp_static", url_prefix="/bp") + bp.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) app.blueprint(bp) - headers = { - 'Range': 'bytes=12-19' - } - uri = app.url_for('static') - assert uri == '/testing.file' - assert uri == app.url_for('static', name='static') - assert uri == app.url_for('static', name='static', filename='any') + headers = {"Range": "bytes=12-19"} + uri = app.url_for("static") + assert uri == "/testing.file" + assert uri == app.url_for("static", name="static") + assert uri == app.url_for("static", name="static", filename="any") request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[12:20] - assert int(response.headers[ - 'Content-Length']) == len(static_content) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + 12:20 + ] + assert int(response.headers["Content-Length"]) == len(static_content) assert response.body == static_content # blueprint - uri = app.url_for('static', name='test_bp_static.static') - assert uri == '/bp/testing.file' - assert uri == app.url_for('static', name='test_bp_static.static', - filename='any') - assert uri == app.url_for('test_bp_static.static') - assert uri == app.url_for('test_bp_static.static', name='any') - assert uri == app.url_for('test_bp_static.static', filename='any') - assert uri == app.url_for('test_bp_static.static', name='any', - filename='any') + uri = app.url_for("static", name="test_bp_static.static") + assert uri == "/bp/testing.file" + assert uri == app.url_for( + "static", name="test_bp_static.static", filename="any" + ) + assert uri == app.url_for("test_bp_static.static") + assert uri == app.url_for("test_bp_static.static", name="any") + assert uri == app.url_for("test_bp_static.static", filename="any") + assert uri == app.url_for( + "test_bp_static.static", name="any", filename="any" + ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[12:20] - assert int(response.headers[ - 'Content-Length']) == len(static_content) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + 12:20 + ] + assert int(response.headers["Content-Length"]) == len(static_content) assert response.body == static_content -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_front(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - bp = Blueprint('test_bp_static', url_prefix='/bp') - bp.static('/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + bp = Blueprint("test_bp_static", url_prefix="/bp") + bp.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) app.blueprint(bp) - headers = { - 'Range': 'bytes=12-' - } - uri = app.url_for('static') - assert uri == '/testing.file' - assert uri == app.url_for('static', name='static') - assert uri == app.url_for('static', name='static', filename='any') + headers = {"Range": "bytes=12-"} + uri = app.url_for("static") + assert uri == "/testing.file" + assert uri == app.url_for("static", name="static") + assert uri == app.url_for("static", name="static", filename="any") request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[12:] - assert int(response.headers[ - 'Content-Length']) == len(static_content) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + 12: + ] + assert int(response.headers["Content-Length"]) == len(static_content) assert response.body == static_content # blueprint - uri = app.url_for('static', name='test_bp_static.static') - assert uri == '/bp/testing.file' - assert uri == app.url_for('static', name='test_bp_static.static', - filename='any') - assert uri == app.url_for('test_bp_static.static') - assert uri == app.url_for('test_bp_static.static', name='any') - assert uri == app.url_for('test_bp_static.static', filename='any') - assert uri == app.url_for('test_bp_static.static', name='any', - filename='any') + uri = app.url_for("static", name="test_bp_static.static") + assert uri == "/bp/testing.file" + assert uri == app.url_for( + "static", name="test_bp_static.static", filename="any" + ) + assert uri == app.url_for("test_bp_static.static") + assert uri == app.url_for("test_bp_static.static", name="any") + assert uri == app.url_for("test_bp_static.static", filename="any") + assert uri == app.url_for( + "test_bp_static.static", name="any", filename="any" + ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[12:] - assert int(response.headers[ - 'Content-Length']) == len(static_content) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + 12: + ] + assert int(response.headers["Content-Length"]) == len(static_content) assert response.body == static_content -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_back(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - bp = Blueprint('test_bp_static', url_prefix='/bp') - bp.static('/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + bp = Blueprint("test_bp_static", url_prefix="/bp") + bp.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) app.blueprint(bp) - headers = { - 'Range': 'bytes=-12' - } - uri = app.url_for('static') - assert uri == '/testing.file' - assert uri == app.url_for('static', name='static') - assert uri == app.url_for('static', name='static', filename='any') + headers = {"Range": "bytes=-12"} + uri = app.url_for("static") + assert uri == "/testing.file" + assert uri == app.url_for("static", name="static") + assert uri == app.url_for("static", name="static", filename="any") request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[-12:] - assert int(response.headers[ - 'Content-Length']) == len(static_content) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + -12: + ] + assert int(response.headers["Content-Length"]) == len(static_content) assert response.body == static_content # blueprint - uri = app.url_for('static', name='test_bp_static.static') - assert uri == '/bp/testing.file' - assert uri == app.url_for('static', name='test_bp_static.static', - filename='any') - assert uri == app.url_for('test_bp_static.static') - assert uri == app.url_for('test_bp_static.static', name='any') - assert uri == app.url_for('test_bp_static.static', filename='any') - assert uri == app.url_for('test_bp_static.static', name='any', - filename='any') + uri = app.url_for("static", name="test_bp_static.static") + assert uri == "/bp/testing.file" + assert uri == app.url_for( + "static", name="test_bp_static.static", filename="any" + ) + assert uri == app.url_for("test_bp_static.static") + assert uri == app.url_for("test_bp_static.static", name="any") + assert uri == app.url_for("test_bp_static.static", filename="any") + assert uri == app.url_for( + "test_bp_static.static", name="any", filename="any" + ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 206 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - static_content = bytes(get_file_content( - static_file_directory, file_name))[-12:] - assert int(response.headers[ - 'Content-Length']) == len(static_content) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + static_content = bytes(get_file_content(static_file_directory, file_name))[ + -12: + ] + assert int(response.headers["Content-Length"]) == len(static_content) assert response.body == static_content -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_empty(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - bp = Blueprint('test_bp_static', url_prefix='/bp') - bp.static('/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + bp = Blueprint("test_bp_static", url_prefix="/bp") + bp.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) app.blueprint(bp) - uri = app.url_for('static') - assert uri == '/testing.file' - assert uri == app.url_for('static', name='static') - assert uri == app.url_for('static', name='static', filename='any') + uri = app.url_for("static") + assert uri == "/testing.file" + assert uri == app.url_for("static", name="static") + assert uri == app.url_for("static", name="static", filename="any") request, response = app.test_client.get(uri) assert response.status == 200 - assert 'Content-Length' in response.headers - assert 'Content-Range' not in response.headers - assert int(response.headers['Content-Length']) == \ - len(get_file_content(static_file_directory, file_name)) + assert "Content-Length" in response.headers + assert "Content-Range" not in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) assert response.body == bytes( - get_file_content(static_file_directory, file_name)) + get_file_content(static_file_directory, file_name) + ) # blueprint - uri = app.url_for('static', name='test_bp_static.static') - assert uri == '/bp/testing.file' - assert uri == app.url_for('static', name='test_bp_static.static', - filename='any') - assert uri == app.url_for('test_bp_static.static') - assert uri == app.url_for('test_bp_static.static', name='any') - assert uri == app.url_for('test_bp_static.static', filename='any') - assert uri == app.url_for('test_bp_static.static', name='any', - filename='any') + uri = app.url_for("static", name="test_bp_static.static") + assert uri == "/bp/testing.file" + assert uri == app.url_for( + "static", name="test_bp_static.static", filename="any" + ) + assert uri == app.url_for("test_bp_static.static") + assert uri == app.url_for("test_bp_static.static", name="any") + assert uri == app.url_for("test_bp_static.static", filename="any") + assert uri == app.url_for( + "test_bp_static.static", name="any", filename="any" + ) request, response = app.test_client.get(uri) assert response.status == 200 - assert 'Content-Length' in response.headers - assert 'Content-Range' not in response.headers - assert int(response.headers['Content-Length']) == \ - len(get_file_content(static_file_directory, file_name)) + assert "Content-Length" in response.headers + assert "Content-Range" not in response.headers + assert int(response.headers["Content-Length"]) == len( + get_file_content(static_file_directory, file_name) + ) assert response.body == bytes( - get_file_content(static_file_directory, file_name)) + get_file_content(static_file_directory, file_name) + ) -@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) +@pytest.mark.parametrize("file_name", ["test.file", "decode me.txt"]) def test_static_content_range_error(app, file_name, static_file_directory): app.static( - '/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) - bp = Blueprint('test_bp_static', url_prefix='/bp') - bp.static('/testing.file', get_file_path(static_file_directory, file_name), - use_content_range=True) + bp = Blueprint("test_bp_static", url_prefix="/bp") + bp.static( + "/testing.file", + get_file_path(static_file_directory, file_name), + use_content_range=True, + ) app.blueprint(bp) - headers = { - 'Range': 'bytes=1-0' - } - uri = app.url_for('static') - assert uri == '/testing.file' - assert uri == app.url_for('static', name='static') - assert uri == app.url_for('static', name='static', filename='any') + headers = {"Range": "bytes=1-0"} + uri = app.url_for("static") + assert uri == "/testing.file" + assert uri == app.url_for("static", name="static") + assert uri == app.url_for("static", name="static", filename="any") request, response = app.test_client.get(uri, headers=headers) assert response.status == 416 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - assert response.headers['Content-Range'] == "bytes */%s" % ( - len(get_file_content(static_file_directory, file_name)),) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + assert response.headers["Content-Range"] == "bytes */%s" % ( + len(get_file_content(static_file_directory, file_name)), + ) # blueprint - uri = app.url_for('static', name='test_bp_static.static') - assert uri == '/bp/testing.file' - assert uri == app.url_for('static', name='test_bp_static.static', - filename='any') - assert uri == app.url_for('test_bp_static.static') - assert uri == app.url_for('test_bp_static.static', name='any') - assert uri == app.url_for('test_bp_static.static', filename='any') - assert uri == app.url_for('test_bp_static.static', name='any', - filename='any') + uri = app.url_for("static", name="test_bp_static.static") + assert uri == "/bp/testing.file" + assert uri == app.url_for( + "static", name="test_bp_static.static", filename="any" + ) + assert uri == app.url_for("test_bp_static.static") + assert uri == app.url_for("test_bp_static.static", name="any") + assert uri == app.url_for("test_bp_static.static", filename="any") + assert uri == app.url_for( + "test_bp_static.static", name="any", filename="any" + ) request, response = app.test_client.get(uri, headers=headers) assert response.status == 416 - assert 'Content-Length' in response.headers - assert 'Content-Range' in response.headers - assert response.headers['Content-Range'] == "bytes */%s" % ( - len(get_file_content(static_file_directory, file_name)),) + assert "Content-Length" in response.headers + assert "Content-Range" in response.headers + assert response.headers["Content-Range"] == "bytes */%s" % ( + len(get_file_content(static_file_directory, file_name)), + ) diff --git a/tests/test_utf8.py b/tests/test_utf8.py index 4a8b9e73..d6bcdd3e 100644 --- a/tests/test_utf8.py +++ b/tests/test_utf8.py @@ -6,49 +6,46 @@ from sanic.response import text # UTF-8 # ------------------------------------------------------------ # + def test_utf8_query_string(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") - request, response = app.test_client.get('/', params=[("utf8", '✓')]) - assert request.args.get('utf8') == '✓' + request, response = app.test_client.get("/", params=[("utf8", "✓")]) + assert request.args.get("utf8") == "✓" def test_utf8_response(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('✓') + return text("✓") - request, response = app.test_client.get('/') - assert response.text == '✓' + request, response = app.test_client.get("/") + assert response.text == "✓" def skip_test_utf8_route(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") # UTF-8 Paths are not supported - request, response = app.test_client.get('/✓') - assert response.text == 'OK' + request, response = app.test_client.get("/✓") + assert response.text == "OK" def test_utf8_post_json(app): - - @app.route('/') + @app.route("/") async def handler(request): - return text('OK') + return text("OK") - payload = {'test': '✓'} - headers = {'content-type': 'application/json'} + payload = {"test": "✓"} + headers = {"content-type": "application/json"} request, response = app.test_client.get( - '/', - data=json_dumps(payload), headers=headers) + "/", data=json_dumps(payload), headers=headers + ) - assert request.json.get('test') == '✓' - assert response.text == 'OK' + assert request.json.get("test") == "✓" + assert response.text == "OK" diff --git a/tests/test_vhosts.py b/tests/test_vhosts.py index 4a0b2e90..b360b1dc 100644 --- a/tests/test_vhosts.py +++ b/tests/test_vhosts.py @@ -2,67 +2,63 @@ from sanic.response import text def test_vhosts(app): - - @app.route('/', host="example.com") + @app.route("/", host="example.com") async def handler1(request): return text("You're at example.com!") - @app.route('/', host="subdomain.example.com") + @app.route("/", host="subdomain.example.com") async def handler2(request): return text("You're at subdomain.example.com!") headers = {"Host": "example.com"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert response.text == "You're at example.com!" headers = {"Host": "subdomain.example.com"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert response.text == "You're at subdomain.example.com!" def test_vhosts_with_list(app): - - @app.route('/', host=["hello.com", "world.com"]) + @app.route("/", host=["hello.com", "world.com"]) async def handler(request): return text("Hello, world!") headers = {"Host": "hello.com"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert response.text == "Hello, world!" headers = {"Host": "world.com"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert response.text == "Hello, world!" def test_vhosts_with_defaults(app): - - @app.route('/', host="hello.com") + @app.route("/", host="hello.com") async def handler1(request): return text("Hello, world!") - @app.route('/') + @app.route("/") async def handler2(request): return text("default") headers = {"Host": "hello.com"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert response.text == "Hello, world!" - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert response.text == "default" def test_remove_vhost_route(app): - - @app.route('/', host="example.com") + @app.route("/", host="example.com") async def handler1(request): return text("You're at example.com!") headers = {"Host": "example.com"} - request, response = app.test_client.get('/', headers=headers) + request, response = app.test_client.get("/", headers=headers) assert response.status == 200 - app.remove_route('/', host="example.com") - request, response = app.test_client.get('/', headers=headers) + app.remove_route("/", host="example.com") + request, response = app.test_client.get("/", headers=headers) assert response.status == 404 diff --git a/tests/test_views.py b/tests/test_views.py index 5555d13d..d0f35d3a 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -8,110 +8,100 @@ from sanic.request import Request from sanic.constants import HTTP_METHODS -@pytest.mark.parametrize('method', HTTP_METHODS) +@pytest.mark.parametrize("method", HTTP_METHODS) def test_methods(app, method): - class DummyView(HTTPMethodView): - async def get(self, request): assert request.stream is None - return text('', headers={'method': 'GET'}) + return text("", headers={"method": "GET"}) def post(self, request): - return text('', headers={'method': 'POST'}) + return text("", headers={"method": "POST"}) async def put(self, request): - return text('', headers={'method': 'PUT'}) + return text("", headers={"method": "PUT"}) def head(self, request): - return text('', headers={'method': 'HEAD'}) + return text("", headers={"method": "HEAD"}) def options(self, request): - return text('', headers={'method': 'OPTIONS'}) + return text("", headers={"method": "OPTIONS"}) async def patch(self, request): - return text('', headers={'method': 'PATCH'}) + return text("", headers={"method": "PATCH"}) def delete(self, request): - return text('', headers={'method': 'DELETE'}) + return text("", headers={"method": "DELETE"}) - app.add_route(DummyView.as_view(), '/') + app.add_route(DummyView.as_view(), "/") assert app.is_request_stream is False - request, response = getattr(app.test_client, method.lower())('/') - assert response.headers['method'] == method + request, response = getattr(app.test_client, method.lower())("/") + assert response.headers["method"] == method def test_unexisting_methods(app): - class DummyView(HTTPMethodView): - def get(self, request): - return text('I am get method') + return text("I am get method") - app.add_route(DummyView.as_view(), '/') - request, response = app.test_client.get('/') - assert response.text == 'I am get method' - request, response = app.test_client.post('/') - assert response.text == 'Error: Method POST not allowed for URL /' + app.add_route(DummyView.as_view(), "/") + request, response = app.test_client.get("/") + assert response.text == "I am get method" + request, response = app.test_client.post("/") + assert response.text == "Error: Method POST not allowed for URL /" def test_argument_methods(app): - class DummyView(HTTPMethodView): - def get(self, request, my_param_here): - return text('I am get method with %s' % my_param_here) + return text("I am get method with %s" % my_param_here) - app.add_route(DummyView.as_view(), '/') + app.add_route(DummyView.as_view(), "/") - request, response = app.test_client.get('/test123') + request, response = app.test_client.get("/test123") - assert response.text == 'I am get method with test123' + assert response.text == "I am get method with test123" def test_with_bp(app): - bp = Blueprint('test_text') + bp = Blueprint("test_text") class DummyView(HTTPMethodView): - def get(self, request): assert request.stream is None - return text('I am get method') + return text("I am get method") - bp.add_route(DummyView.as_view(), '/') + bp.add_route(DummyView.as_view(), "/") app.blueprint(bp) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") assert app.is_request_stream is False - assert response.text == 'I am get method' + assert response.text == "I am get method" def test_with_bp_with_url_prefix(app): - bp = Blueprint('test_text', url_prefix='/test1') + bp = Blueprint("test_text", url_prefix="/test1") class DummyView(HTTPMethodView): - def get(self, request): - return text('I am get method') + return text("I am get method") - bp.add_route(DummyView.as_view(), '/') + bp.add_route(DummyView.as_view(), "/") app.blueprint(bp) - request, response = app.test_client.get('/test1/') + request, response = app.test_client.get("/test1/") - assert response.text == 'I am get method' + assert response.text == "I am get method" def test_with_middleware(app): - class DummyView(HTTPMethodView): - def get(self, request): - return text('I am get method') + return text("I am get method") - app.add_route(DummyView.as_view(), '/') + app.add_route(DummyView.as_view(), "/") results = [] @@ -119,41 +109,39 @@ def test_with_middleware(app): async def handler(request): results.append(request) - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == 'I am get method' + assert response.text == "I am get method" assert type(results[0]) is Request def test_with_middleware_response(app): results = [] - @app.middleware('request') + @app.middleware("request") async def process_request(request): results.append(request) - @app.middleware('response') + @app.middleware("response") async def process_response(request, response): results.append(request) results.append(response) class DummyView(HTTPMethodView): - def get(self, request): - return text('I am get method') + return text("I am get method") - app.add_route(DummyView.as_view(), '/') + app.add_route(DummyView.as_view(), "/") - request, response = app.test_client.get('/') + request, response = app.test_client.get("/") - assert response.text == 'I am get method' + assert response.text == "I am get method" assert type(results[0]) is Request assert type(results[1]) is Request assert isinstance(results[2], HTTPResponse) def test_with_custom_class_methods(app): - class DummyView(HTTPMethodView): global_var = 0 @@ -162,12 +150,14 @@ def test_with_custom_class_methods(app): def get(self, request): self._iternal_method() - return text('I am get method and global var ' - 'is {}'.format(self.global_var)) + return text( + "I am get method and global var " + "is {}".format(self.global_var) + ) - app.add_route(DummyView.as_view(), '/') - request, response = app.test_client.get('/') - assert response.text == 'I am get method and global var is 10' + app.add_route(DummyView.as_view(), "/") + request, response = app.test_client.get("/") + assert response.text == "I am get method and global var is 10" def test_with_decorator(app): @@ -177,84 +167,86 @@ def test_with_decorator(app): def decorator(*args, **kwargs): results.append(1) return view(*args, **kwargs) + return decorator class DummyView(HTTPMethodView): decorators = [stupid_decorator] def get(self, request): - return text('I am get method') + return text("I am get method") - app.add_route(DummyView.as_view(), '/') - request, response = app.test_client.get('/') - assert response.text == 'I am get method' + app.add_route(DummyView.as_view(), "/") + request, response = app.test_client.get("/") + assert response.text == "I am get method" assert results[0] == 1 def test_composition_view_rejects_incorrect_methods(): def foo(request): - return text('Foo') + return text("Foo") view = CompositionView() with pytest.raises(InvalidUsage) as e: - view.add(['GET', 'FOO'], foo) + view.add(["GET", "FOO"], foo) - assert str(e.value) == 'FOO is not a valid HTTP method.' + assert str(e.value) == "FOO is not a valid HTTP method." def test_composition_view_rejects_duplicate_methods(): def foo(request): - return text('Foo') + return text("Foo") view = CompositionView() with pytest.raises(InvalidUsage) as e: - view.add(['GET', 'POST', 'GET'], foo) + view.add(["GET", "POST", "GET"], foo) - assert str(e.value) == 'Method GET is already registered.' + assert str(e.value) == "Method GET is already registered." -@pytest.mark.parametrize('method', HTTP_METHODS) +@pytest.mark.parametrize("method", HTTP_METHODS) def test_composition_view_runs_methods_as_expected(app, method): view = CompositionView() def first(request): assert request.stream is None - return text('first method') - view.add(['GET', 'POST', 'PUT'], first) - view.add(['DELETE', 'PATCH'], lambda x: text('second method')) + return text("first method") - app.add_route(view, '/') + view.add(["GET", "POST", "PUT"], first) + view.add(["DELETE", "PATCH"], lambda x: text("second method")) + + app.add_route(view, "/") assert app.is_request_stream is False - if method in ['GET', 'POST', 'PUT']: - request, response = getattr(app.test_client, method.lower())('/') - assert response.text == 'first method' + if method in ["GET", "POST", "PUT"]: + request, response = getattr(app.test_client, method.lower())("/") + assert response.text == "first method" response = view(request) - assert response.body.decode() == 'first method' + assert response.body.decode() == "first method" - if method in ['DELETE', 'PATCH']: - request, response = getattr(app.test_client, method.lower())('/') - assert response.text == 'second method' + if method in ["DELETE", "PATCH"]: + request, response = getattr(app.test_client, method.lower())("/") + assert response.text == "second method" response = view(request) - assert response.body.decode() == 'second method' + assert response.body.decode() == "second method" -@pytest.mark.parametrize('method', HTTP_METHODS) +@pytest.mark.parametrize("method", HTTP_METHODS) def test_composition_view_rejects_invalid_methods(app, method): view = CompositionView() - view.add(['GET', 'POST', 'PUT'], lambda x: text('first method')) + view.add(["GET", "POST", "PUT"], lambda x: text("first method")) - app.add_route(view, '/') + app.add_route(view, "/") - if method in ['GET', 'POST', 'PUT']: - request, response = getattr(app.test_client, method.lower())('/') + if method in ["GET", "POST", "PUT"]: + request, response = getattr(app.test_client, method.lower())("/") assert response.status == 200 - assert response.text == 'first method' + assert response.text == "first method" - if method in ['DELETE', 'PATCH']: - request, response = getattr(app.test_client, method.lower())('/') + if method in ["DELETE", "PATCH"]: + request, response = getattr(app.test_client, method.lower())("/") assert response.status == 405 diff --git a/tests/test_worker.py b/tests/test_worker.py index 7c0f3149..1fad4f28 100644 --- a/tests/test_worker.py +++ b/tests/test_worker.py @@ -10,13 +10,13 @@ import asyncio import pytest -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def gunicorn_worker(): command = ( - 'gunicorn ' - '--bind 127.0.0.1:1337 ' - '--worker-class sanic.worker.GunicornWorker ' - 'examples.simple_server:app' + "gunicorn " + "--bind 127.0.0.1:1337 " + "--worker-class sanic.worker.GunicornWorker " + "examples.simple_server:app" ) worker = subprocess.Popen(shlex.split(command)) time.sleep(3) @@ -25,13 +25,12 @@ def gunicorn_worker(): def test_gunicorn_worker(gunicorn_worker): - with urllib.request.urlopen('http://localhost:1337/') as f: + with urllib.request.urlopen("http://localhost:1337/") as f: res = json.loads(f.read(100).decode()) - assert res['test'] + assert res["test"] class GunicornTestWorker(GunicornWorker): - def __init__(self): self.app = mock.Mock() self.app.callable = Sanic("test_gunicorn_worker") @@ -47,7 +46,7 @@ def worker(): def test_worker_init_process(worker): - with mock.patch('sanic.worker.asyncio') as mock_asyncio: + with mock.patch("sanic.worker.asyncio") as mock_asyncio: try: worker.init_process() except TypeError: @@ -65,7 +64,7 @@ def test_worker_init_signals(worker): def test_handle_abort(worker): - with mock.patch('sanic.worker.sys') as mock_sys: + with mock.patch("sanic.worker.sys") as mock_sys: worker.handle_abort(object(), object()) assert not worker.alive assert worker.exit_code == 1 @@ -83,7 +82,7 @@ def test_run_max_requests_exceeded(worker): worker.ppid = 1 worker.alive = True sock = mock.Mock() - sock.cfg_addr = ('localhost', 8080) + sock.cfg_addr = ("localhost", 8080) worker.sockets = [sock] worker.wsgi = mock.Mock() worker.connections = set() @@ -102,8 +101,9 @@ def test_run_max_requests_exceeded(worker): assert not worker.alive worker.notify.assert_called_with() - worker.log.info.assert_called_with("Max requests exceeded, shutting " - "down: %s", worker) + worker.log.info.assert_called_with( + "Max requests exceeded, shutting " "down: %s", worker + ) def test_worker_close(worker): @@ -125,11 +125,10 @@ def test_worker_close(worker): worker.loop = loop server = mock.Mock() server.close = mock.Mock(wraps=lambda *a, **kw: None) - server.wait_closed = mock.Mock(wraps=asyncio.coroutine( - lambda *a, **kw: None)) - worker.servers = { - server: {"requests_count": 14}, - } + server.wait_closed = mock.Mock( + wraps=asyncio.coroutine(lambda *a, **kw: None) + ) + worker.servers = {server: {"requests_count": 14}} worker.max_requests = 10 # close worker From aea4a8ed3367c86c29ee7cbc2ede563d539c48ee Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Sun, 30 Dec 2018 13:46:08 +0200 Subject: [PATCH 5/9] Modify test_logo runner --- tests/test_logo.py | 67 +++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/tests/test_logo.py b/tests/test_logo.py index 3f39bf3d..b98f77e5 100644 --- a/tests/test_logo.py +++ b/tests/test_logo.py @@ -5,29 +5,36 @@ import pytest from sanic.config import BASE_LOGO -@pytest.fixture -def server(app): +def test_logo_base(app, caplog): server = app.create_server(debug=True) - loop = asyncio.get_event_loop() - task = asyncio.ensure_future(server) - return loop, task + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop._stopping = False - -def test_logo_base(app, server, caplog): - loop, task = server with caplog.at_level(logging.DEBUG): - runner = loop.run_until_complete(task) - runner.close() + _server = loop.run_until_complete(server) + + _server.close() + loop.run_until_complete(_server.wait_closed()) + app.stop() assert caplog.record_tuples[0] == ("sanic.root", logging.DEBUG, BASE_LOGO) -def test_logo_false(app, server, caplog): +def test_logo_false(app, caplog): app.config.LOGO = False - loop, task = server + + server = app.create_server(debug=True) + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop._stopping = False + with caplog.at_level(logging.DEBUG): - runner = loop.run_until_complete(task) - runner.close() + _server = loop.run_until_complete(server) + + _server.close() + loop.run_until_complete(_server.wait_closed()) + app.stop() assert caplog.record_tuples[0] == ( "sanic.root", @@ -36,22 +43,38 @@ def test_logo_false(app, server, caplog): ) -def test_logo_true(app, server, caplog): +def test_logo_true(app, caplog): app.config.LOGO = True - loop, task = server + + server = app.create_server(debug=True) + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop._stopping = False + with caplog.at_level(logging.DEBUG): - runner = loop.run_until_complete(task) - runner.close() + _server = loop.run_until_complete(server) + + _server.close() + loop.run_until_complete(_server.wait_closed()) + app.stop() assert caplog.record_tuples[0] == ("sanic.root", logging.DEBUG, BASE_LOGO) -def test_logo_custom(app, server, caplog): +def test_logo_custom(app, caplog): app.config.LOGO = "My Custom Logo" - loop, task = server + + server = app.create_server(debug=True) + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop._stopping = False + with caplog.at_level(logging.DEBUG): - runner = loop.run_until_complete(task) - runner.close() + _server = loop.run_until_complete(server) + + _server.close() + loop.run_until_complete(_server.wait_closed()) + app.stop() assert caplog.record_tuples[0] == ( "sanic.root", From 94e85686b5a83a13ef7b94542b7a1b16ac1c4184 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Sun, 30 Dec 2018 14:07:21 +0200 Subject: [PATCH 6/9] Ignore first row of logs when no uvloop --- tests/test_logo.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/test_logo.py b/tests/test_logo.py index b98f77e5..c99ee5b6 100644 --- a/tests/test_logo.py +++ b/tests/test_logo.py @@ -1,9 +1,14 @@ import logging import asyncio -import pytest from sanic.config import BASE_LOGO +try: + import uvloop # noqa + ROW = 0 +except BaseException: + ROW = 1 + def test_logo_base(app, caplog): server = app.create_server(debug=True) @@ -18,7 +23,8 @@ def test_logo_base(app, caplog): loop.run_until_complete(_server.wait_closed()) app.stop() - assert caplog.record_tuples[0] == ("sanic.root", logging.DEBUG, BASE_LOGO) + assert caplog.record_tuples[ROW][1] == logging.DEBUG + assert caplog.record_tuples[ROW][2] == BASE_LOGO def test_logo_false(app, caplog): @@ -36,11 +42,8 @@ def test_logo_false(app, caplog): loop.run_until_complete(_server.wait_closed()) app.stop() - assert caplog.record_tuples[0] == ( - "sanic.root", - logging.INFO, - "Goin' Fast @ http://127.0.0.1:8000", - ) + assert caplog.record_tuples[ROW][1] == logging.INFO + assert caplog.record_tuples[ROW][2] == "Goin' Fast @ http://127.0.0.1:8000" def test_logo_true(app, caplog): @@ -58,7 +61,8 @@ def test_logo_true(app, caplog): loop.run_until_complete(_server.wait_closed()) app.stop() - assert caplog.record_tuples[0] == ("sanic.root", logging.DEBUG, BASE_LOGO) + assert caplog.record_tuples[ROW][1] == logging.DEBUG + assert caplog.record_tuples[ROW][2] == BASE_LOGO def test_logo_custom(app, caplog): @@ -76,8 +80,5 @@ def test_logo_custom(app, caplog): loop.run_until_complete(_server.wait_closed()) app.stop() - assert caplog.record_tuples[0] == ( - "sanic.root", - logging.DEBUG, - "My Custom Logo", - ) + assert caplog.record_tuples[ROW][1] == logging.DEBUG + assert caplog.record_tuples[ROW][2] == "My Custom Logo" From f5162f8ab1878f8454755ef0e7424668d5e43e53 Mon Sep 17 00:00:00 2001 From: Jitesh Nair Date: Mon, 31 Dec 2018 16:00:34 +0530 Subject: [PATCH 7/9] Update README.rst Made the optional Environment variable declaration for installation more clear. --- README.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 9141d4f6..06a9232b 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,11 @@ Installation Sanic makes use of ``uvloop`` and ``ujson`` to help with performance. If you do not want to use those packages, simply add an environmental variable ``SANIC_NO_UVLOOP=true`` or ``SANIC_NO_UJSON=true`` at install time. - ``SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip3 install sanic`` + .. code:: shell + + $ export SANIC_NO_UVLOOP=true + $ export SANIC_NO_UJSON=true + $ pip3 install sanic Hello World Example From ca179c12a1e5512d7439b621e2450c989f8c050a Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Mon, 31 Dec 2018 18:47:27 +0200 Subject: [PATCH 8/9] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 9141d4f6..e09e41a5 100644 --- a/README.rst +++ b/README.rst @@ -45,7 +45,7 @@ Sanic | Build fast. Run fast. .. end-badges -Sanic is a Python web server that's written to go fast. It allows usage the `async` and `await` syntax added in Python 3.5, which makes your code non-blocking and speedy. +Sanic is a Python web framework that's written to go fast. It allows usage the `async` and `await` syntax added in Python 3.5, which makes your code non-blocking and speedy. `Source code on GitHub `_ | `Help and discussion board `_. From 9b6b93d467633e65984a9d2a00408f30f9abb047 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Mon, 31 Dec 2018 21:41:35 +0200 Subject: [PATCH 9/9] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e09e41a5..f50a15bf 100644 --- a/README.rst +++ b/README.rst @@ -45,7 +45,7 @@ Sanic | Build fast. Run fast. .. end-badges -Sanic is a Python web framework that's written to go fast. It allows usage the `async` and `await` syntax added in Python 3.5, which makes your code non-blocking and speedy. +Sanic is a Python web server and web framework that's written to go fast. It allows usage the `async` and `await` syntax added in Python 3.5, which makes your code non-blocking and speedy. `Source code on GitHub `_ | `Help and discussion board `_.