Merge pull request #1443 from huge-success/new-readme

Update README with new logo, change Congfig.LOGO, run linter
This commit is contained in:
7 2018-12-30 13:23:12 -08:00 committed by GitHub
commit ff38a3c6b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 3169 additions and 2921 deletions

View File

@ -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 <https://magic.io/blog/uvloop-blazing-fast-python-networking/>`_.
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 <https://github.com/huge-success/sanic/>`_ | `Help and discussion board <https://community.sanicframework.org/>`_.
Sanic is developed `on GitHub <https://github.com/huge-success/sanic/>`_. We also have `a community discussion board <https://community.sanicframework.org/>`_. 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 <https://github.com/huge-success/sanic/issues/396>`_ 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 <https://community.sanicframework.org/>`_.
Contribution
------------
Examples
--------
`Non-Core examples <https://github.com/huge-success/sanic/wiki/Examples/>`_. Examples of plugins and Sanic that are outside the scope of Sanic core.
`Extensions <https://github.com/huge-success/sanic/wiki/Extensions/>`_. Sanic extensions created by the community.
`Projects <https://github.com/huge-success/sanic/wiki/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 <https://github.com/huge-success/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner>`_, and welcome `questions on the forums <https://community.sanicframework.org/>`_. Please take a look at our `Contribution guidelines <https://github.com/huge-success/sanic/blob/master/CONTRIBUTING.md>`_.

View File

@ -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 BASE_LOGO, Config
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

View File

@ -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

View File

@ -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"]

View File

@ -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)

View File

@ -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()

View File

@ -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())

View File

@ -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()
kyk.run()

View File

@ -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

View File

@ -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])

View File

@ -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):

View File

@ -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)

View File

@ -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!")

View File

@ -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/'",
)

View File

@ -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"

View File

@ -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='/<resource_id>')
bp_resource = Blueprint("bp_resource", url_prefix="/<resource_id>")
@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"

View File

@ -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):

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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/<param>', methods=['GET'])
@app.route("/overload/<param>", methods=["GET"])
async def handler1(request, param):
return text('OK1 ' + param)
return text("OK1 " + param)
@app.route('/overload/<param>', methods=['POST', 'PUT'])
@app.route("/overload/<param>", 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/<param>', methods=['GET'])
@app.route("/overload/<param>", methods=["GET"])
async def handler1(request, param):
return text('OK1 ' + param)
return text("OK1 " + param)
@app.route('/overload/<param>', methods=['POST', 'PUT'])
@app.route("/overload/<param>", 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/<param>', methods=['PUT', 'DELETE'])
@app.route("/overload/<param>", methods=["PUT", "DELETE"])
async def handler3(request):
return text('Duplicated')
return text("Duplicated")

View File

@ -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"

View File

@ -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/<arg:int>')
@exception_handler_app.route("/6/<arg:int>")
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

View File

@ -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"},
),
)

View File

@ -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]
)

View File

@ -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

84
tests/test_logo.py Normal file
View File

@ -0,0 +1,84 @@
import logging
import asyncio
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)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop._stopping = False
with caplog.at_level(logging.DEBUG):
_server = loop.run_until_complete(server)
_server.close()
loop.run_until_complete(_server.wait_closed())
app.stop()
assert caplog.record_tuples[ROW][1] == logging.DEBUG
assert caplog.record_tuples[ROW][2] == BASE_LOGO
def test_logo_false(app, caplog):
app.config.LOGO = False
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):
_server = loop.run_until_complete(server)
_server.close()
loop.run_until_complete(_server.wait_closed())
app.stop()
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):
app.config.LOGO = True
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):
_server = loop.run_until_complete(server)
_server.close()
loop.run_until_complete(_server.wait_closed())
app.stop()
assert caplog.record_tuples[ROW][1] == logging.DEBUG
assert caplog.record_tuples[ROW][2] == BASE_LOGO
def test_logo_custom(app, caplog):
app.config.LOGO = "My Custom Logo"
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):
_server = loop.run_until_complete(server)
_server.close()
loop.run_until_complete(_server.wait_closed())
app.stop()
assert caplog.record_tuples[ROW][1] == logging.DEBUG
assert caplog.record_tuples[ROW][2] == "My Custom Logo"

View File

@ -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]

View File

@ -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"

View File

@ -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>', name='route_dynamic')
@app.route("/folder/<name>", name="route_dynamic")
async def handler(request, name):
results.append(name)
return text('OK')
return text("OK")
assert app.router.routes_all['/folder/<name>'].name == 'route_dynamic'
assert app.url_for('route_dynamic', name='test') == '/folder/test'
assert app.router.routes_all["/folder/<name>"].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/<folder_id:[A-Za-z0-9]{0,4}>', name='route_re')
@app.route("/folder/<folder_id:[A-Za-z0-9]{0,4}>", name="route_re")
async def handler(request, folder_id):
return text('OK')
return text("OK")
route = app.router.routes_all['/folder/<folder_id:[A-Za-z0-9]{0,4}>']
assert route.name == 'route_re'
assert app.url_for('route_re', folder_id='test') == '/folder/test'
route = app.router.routes_all["/folder/<folder_id:[A-Za-z0-9]{0,4}>"]
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('/<path:path>/info', name='route_dynamic_path')
@app.route("/<path:path>/info", name="route_dynamic_path")
async def handler(request, path):
return text('OK')
return text("OK")
route = app.router.routes_all['/<path:path>/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["/<path:path>/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/<unhashable:[A-Za-z0-9/]+>/end/',
name='route_unhashable')
@app.route(
"/folder/<unhashable:[A-Za-z0-9/]+>/end/", name="route_unhashable"
)
async def handler(request, unhashable):
return text('OK')
return text("OK")
route = app.router.routes_all['/folder/<unhashable:[A-Za-z0-9/]+>/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/<unhashable:[A-Za-z0-9/]+>/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>', name='route_dynamic')
assert app.router.routes_all['/folder/<name>'].name == 'route_dynamic'
assert app.url_for('route_dynamic', name='test') == '/folder/test'
app.add_route(handler, "/folder/<name>", name="route_dynamic")
assert app.router.routes_all["/folder/<name>"].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/<unhashable:[A-Za-z0-9/]+>/end/',
name='route_unhashable')
route = app.router.routes_all['/folder/<unhashable:[A-Za-z0-9/]+>/end/']
assert route.name == 'route_unhashable'
url = app.url_for('route_unhashable', unhashable='folder1')
assert url == '/folder/folder1/end'
app.add_route(
handler,
"/folder/<unhashable:[A-Za-z0-9/]+>/end/",
name="route_unhashable",
)
route = app.router.routes_all["/folder/<unhashable:[A-Za-z0-9/]+>/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")

View File

@ -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"

View File

@ -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/<test>/")
async def init_handler(request, test):
assert test == test_str

View File

@ -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/<id>', stream=True)
@app.post("/post/<id>", 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)

View File

@ -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

View File

@ -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/<id>')
@app.post("/_post/<id>")
async def _post(request, id):
assert request.stream is None
return text('_POST')
return text("_POST")
@app.post('/post/<id>', stream=True)
@app.post("/post/<id>", 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/<id>', stream=True)
@app.post("/post/<id>", 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/<id>')
@bp.post("/_post/<id>")
async def _post(request, id):
assert request.stream is None
return text('_POST')
return text("_POST")
@bp.post('/post/<id>', stream=True)
@bp.post("/post/<id>", 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

View File

@ -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"

View File

@ -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/<id:int>/bar/<name:[A-z]+>')
@app.route("/foo/<id:int>/bar/<name:[A-z]+>")
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/<id:int>/bar/<name:[A-z]+>'
request, response = app.test_client.get("/foo/123/bar/baz")
assert request.uri_template == "/foo/<id:int>/bar/<name:[A-z]+>"
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/<user_id>/')
@app.route("/api/v1/user/<user_id>/")
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) == '<Request: GET />'
assert repr(request) == "<Request: GET />"
@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: GET />'
request, response = app.test_client.get("/")
assert repr(request) == "<Request: GET />"
request.method = None
assert repr(request) == '<Request>'
assert repr(request) == "<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 == {}

View File

@ -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/<filename>', methods=['GET'])
@app.route("/files/<filename>", 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/<filename>', methods=['GET'])
def test_file_response_custom_filename(
app, source, dest, static_file_directory
):
@app.route("/files/<filename>", 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/<filename>', methods=['GET', 'HEAD'])
@app.route("/files/<filename>", 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/<filename>', 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/<filename>', 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/<filename>', 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/<filename>', methods=['GET'])
def test_file_stream_response(app, file_name, static_file_directory):
@app.route("/files/<filename>", 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/<filename>", 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/<filename>", 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/<filename>", 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"

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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 = (
'/<foo:int>/<four_letter_string:[A-z]{4}>/'
'<two_letter_string:[A-z]{2}>/<normal_string>/<some_number:number>')
"/<foo:int>/<four_letter_string:[A-z]{4}>/"
"<two_letter_string:[A-z]{2}>/<normal_string>/<some_number:number>"
)
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/<param>')
@first_print.route("/foo/<param>")
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/<param>') # noqa
@second_print.route("/foo/<param>") # 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"

View File

@ -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)),
)

View File

@ -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"

View File

@ -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

View File

@ -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(), '/<my_param_here>')
app.add_route(DummyView.as_view(), "/<my_param_here>")
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

View File

@ -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