* add Request.not_grouped_args, deprecation warning Request.raw_args
* add 1 more test for coverage
* custom parser for Request.args and Request.query_args, some additional tests
* add docs for custom queryset parsing
* fix import sorting
* docstrings for get_query_args and get_args methods
* lost import
* enable blueprint group middleware support
This commit will enable the users to implement a middleware at the
blueprint group level whereby enforcing the middleware automatically to
each of the available Blueprints that are part of the group.
This will eanble a simple way in which a certain set of common features
and criteria can be enforced on a Blueprint group. i.e. authentication
and authorization
This commit will address the feature request raised as part of Issue #1386
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* enable indexing of BlueprintGroup object
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* rename blueprint group file to fix spelling error
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* add documentation and additional unit tests
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* cleanup and optimize headers in unit test file
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* fix Bluprint Group iteratable method
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* add additional unit test to check StopIteration condition
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* cleanup iter protocol implemenation for blueprint group and add slots
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* fix blueprint group middleware invocation identification
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* feat: enable list behavior on blueprint group object and use append instead of properly to add blueprint to group
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* suport filename length is 0
* 1. suport filename length is zero for multipart/form-data.
2. Now recognizes non-ASCII filenames in RFC 2231, "filename*" format
3. Add some test cases in tests/test_requests.py::test_request_multipart_files.
* reformat sanic/request.py
- adding 2 new parameters to Sanic.create_server:
* return_asyncio_server=False - defines whether there's
a need to return an asyncio.Server or run it right away
* asyncio_server_kwargs=None - for python 3.7 uvloop doesn't
support all necessary features like "start_serving",
so, in order to make sanic work well with asyncio from 3.7
there's a need to introduce generic way for passing
kwargs for "loop.create_server"
Closes: #1469
* Add tests for remove_route()
* Add tests for sanic/router.py
* Add tests for sanic/cookies.py
* Disable reset logging in test_logging.py
* Add tests for sanic/request.py
* Add tests for ContentRangeHandler
* Add tests for exception at response middleware
* Fix cached_handlers for ErrorHandler.lookup()
* Add test for websocket request timeout
* Add tests for getting cookies of StreamResponse, Remove some unused variables in tests/test_cookies.py
* Add tests for nested error handle
* add unit tests to completely cover blueprints
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* fix typo in the unit test code
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
* created methods to append and finish body content on request.py so the underlying body instance can have certain flexibility; modified server.py to reflect these changes
* - made some adjustments (including the Request.body_init method) as requested by @ahopkins;
- created a new test with a custom Request class implementation of the flexibility provided by the new methods;
The current implementation of `sanic` attempts to make use of `ujson` if
it's available in the system and if not, it will default to the inbuilt
`json` module provided by python.
The current implementation of `ujson` does not provide a mechanism to
provide a custom `seperators` parameter as part of the `dumps` method
invocation and the default behavior of the module is to strip all the
spaces around seperators such as `:` and `,`. This leads to an
inconsistency in the response length when the response is generated
using the `ujson` and in built `json` module provided by python.
To maintain the consistency, this commit overrides the default behavior
of the `dumps` method provided by the `json` module to add a `seperators`
argument that will strip the white spaces around these character like
the default behavior of `ujson`
This addresses the issue referenced in #1398
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
This commit fixes the issue in the `Range` header handling that was done
while serving the file contents.
As per the HTTP response standards, a status code of 206 will be used in
case if the Range is returning a partial value and default of 200 in
other cases.
Signed-off-by: Harsha Narayana <harsha2k4@gmail.com>
Change the string passed in the "name" section of the namedtuples in Blueprint to match the name of the Blueprint module attribute name.
This allows blueprints to be pickled and unpickled, without errors, which is a requirment of running Sanic in multiprocessing mode in Windows.
Added a test for pickling and unpickling blueprints
Added a test for pickling and unpickling sanic itself
Added a test for enabling multiprocessing on an app with a blueprint (only useful to catch this bug if the tests are run on Windows).
* This commit adds handlers for the asyncio/uvloop protocol callbacks for pause_writing and resume_writing.
These are needed for the correct functioning of built-in tcp flow-control provided by uvloop and asyncio.
This is somewhat of a breaking change, because the `write` function in user streaming callbacks now must be `await`ed.
This is necessary because it is possible now that the http protocol may be paused, and any calls to write may need to wait on an async event to be called to become unpaused.
Updated examples and tests to reflect this change.
This change does not apply to websocket connections. A change to websocket connections may be required to match this change.
* Fix a couple of PEP8 errors caused by previous rebase.
* update docs
add await syntax to response.write in response-streaming docs.
* remove commented out code from a test file
* Fix two problems with the auto_reloader in Linux.
1) Change 'posix' to 'linux' in sys.plaform check, because 'posix' is an invalid value and 'linux' is the correct value to use here.
2) In kill_process_children, don't just kill the 2nd level procs, also kill the 1st level procs.
Also in kill_process_children, catch and ignore errors in the case that the child proc is already killed.
* Fix flake8 formatting on PR
The Canceled exception handler purposely sets `response` to `None` to drop references to the handler coroutine, in an attempt to preemptively release resources.
This commit also fixes a possible reference-before-assignment of the `response` variable in the `handle_request` function.
Finally, another byproduct of this change is that ResponseMiddleware will no longer run if the `response` is `None`.
* Add content_type flag to Sanic.static
Fixes#1266
* Fix flake8 error in travis
Add line to document `content_type` arg
* Fix content_type for file streams
Update tests
herp derp
* Remove content_type as an arg to HTTPResponse
`response.HTTPResponse` will default to `headers['Content-Type']` instead of `content_type`
https://github.com/channelcat/sanic/pull/1267#discussion_r204190913
* URL Quote the URL before redirecting
* Use safe url instead of unsafe one
* Fix query params
* fix build
* Whitelist all reserved characters from rfc3986
* Add tests for redirect url sanitizing
* Remove check for resulting URL on header injection test
The thing the tests are testing for can be implemented in other
ways that don't redirect to 100% the same address, but they'll all have
to match the remaining parts of the test to succeed.
* add unit tests, which should fail
* fix CIDict
* moving CIDict to avoid circular imports
* fix unit tests
* use multidict for headers
* fix cookie
* add version constraint for multidict
* omit test coverage for __main__.py
* make flake8 happy
* consolidate check in for loop
* travisci retry build
* introduced basic entity and hopbyhop header identification
* removed entity headers
* coding style fixes
* remove unneeded header check
* moved from bytes to unicode in headers
* changed list to tuple in empty response statuses
In aiohttp 3.1.0 there were some breaking changes that caused the custom methods to be no longer compatible with latest upstream aiohttp Client class.
See: 903073283f
and: b42e0ced46
This commit adds aiohttp version checks to adapt to these changes.
causes a route to be added twice. One without the slash, the other with the
Setting strict_slashes to false when a route does not end with slashes
slash. This is ok if the Router._add method runs linearly, but problematic
when it runs recursively. Unfortunately recursion is triggered when
the host param to the Router._add function is a list of hosts.
A field name in the Content-Disposition header is required by the multipart/form-data spec. If one field/part does not have it, it will be omitted from the request. When this happens, we log it to DEBUG.
Sanic automatically assumes that a form field is a file if it has a content-type header, even though the header is text/plain or application/json. This is a fix for it, I took into account the RFC7578 specification regarding the defaults.
When passing a null value as parameter (ex.: 0, None or False), Sanic said "Error: Required parameter `param` was not passed to url_for"
Example:
```
@app.route("/<idx>")
def route(rq, idx):
pass
```
```
url_for("route", idx=0)
```
No longer raises: `Error: Required parameter `idx` was not passed to url_for`
Change auto reloader enviroment varible name to SANIC_SERVER_RUNNING
Fix some typo mistakes, flake uncompatibilities and such problems.
Raise NotImplementedError for operating systems except posix systems for auto reloading.
Before: Even after raising ResponseTimeout, server still processes
remaining tasks until it is done
After: Before raising ResponseTimeout, server stops working task.
It seems that due to (recent?) changes in the websocket library, we
now need to call "connection_open" to flag that the websocket is now
ready to use. I've added that call just after the call to
"connection_made".
* Replaced COMMON_STATUS_CODES with a simple 200 check for more fast
* Added IPware algorithm
* Remove HTTP prefix from Django-style headers
Remove right_most_proxy because it's outside spec
* Remove obvious docstrings
* Revert "Replaced COMMON_STATUS_CODES with a simple 200 check for more fast"
This reverts commit 15b6980
* Revert "Added IPware algorithm"
This reverts commit bdf66cb
WTF HOW DO I GIT
* Revert "Revert "Replaced COMMON_STATUS_CODES with a simple 200 check for more fast""
This reverts commit d8df095
* Revert "Added IPware algorithm"
This reverts commit bdf66cb
* Delete ip.py
I made a new tool for devs to use for easily and quickly creating Sanic Plugins (extensions), and for application builders to easily use those plugins in their app.
Fixed error where KeepAliveTimeout wasn't being triggered in the test suite, when using uvloop
Fixed test cases when using other asyncio loops such as uvloop
Fixed Flake8 linting errors
The reason is: aiohttp with disabled access log shows about 16,000 RPS on sanic's own benchmark.
It's pretty much faster than 3,000 RPS from the table.
I'm not a Sanic dev team member. You should not trust users to update this table but manage periodic updates yourself.
If you don't want to do it --- it's up to you.
Please just drop very incorrect and outdated numbers from README in this case.
It doesn't really make sense to have a `realm` parameter in the method signature.
Instead, one can simply set the realm in the `challenge` dict if necessary.
Also fixed the tests accordingly (and added a new one for "Bearer" auth-scheme).
Removed the test for "Authentication: Bearer Token <TOKEN>" which was not supposed to exist (see https://github.com/channelcat/sanic/pull/821)
Also added a call to `split` when retrieving the token value to handle cases where there are leading or trailing spaces.
* add recycling feature to gunicorn worker
* add unit tests
* add more unit tests, and remove redundant trigger_events call
* fixed up unit tests
* make flake8 happy
* address feedbacks
* make flake8 happy
* add doc
When creating the `Sanic` instance I provide it with a customized `log_config`.
Calling `run` overrides these settings unless I provide it *again* with the same `log_config`.
This is confusing and error prone. `run` shouldnt override configurations set in the `Sanic` constructor...
For now, `Sanic.is_running` is set when the worker is started but not
unset when it is about to stopped. Setting the flag for quit signal
will not affect working requests, but the `Sanic.is_running` flag still
can be used to support graceful termination.
By default uses a 1M threshold.
ie. if the static file to serve is >= 1M it will stream the file.
This threshold value is configurable by passing an int instead of a bool to `stream_large_files` parameter of `static()`.
For streaming large static files
Like `file()` but breaks the file into chunks and sends it with a `StreamingHTTPResponse`
Chunk size is configurable, but defaults to 4k, this seemed to be the sweet spot in my testing.
Also supports ContentRange same as `file()` does.
socket.getpeername() returns AF_INET6 address family four-tuple, with
flowid and scopeid.
In server's write_response, an exception is raised when an IPv6 client
connects due to four-tuple elements having two unused elements (flowid
and scopeid).
This makes sure that only the first two (host and port) are used in log
string formatting.
* Migrated `%` string formating
* double if statement
combined double 'if' to a single 'if' with 'and'
* Revert "Fix "Prefer `format()` over string interpolation operator" issue"
Fixes issue #629. Printing a unicode string at the end of the
setup.py script is asking for trouble. It's also redundant:
the pip tool itself tells the user whether the installation was
successful or not.
Allowing a custom Request class to be defined would enable either a different Request class or a subclass of Request to be used, providing more flexibility.
aiohttp decided to use yarl for their new URL objects so that they
aren't plain strings anymore which means that this single test fails.
Not a huge change but this should fix the testing suite.
In my benchmarks I was able to obtain a 17% performance
improvement over the current asyncpg demo code with a shared
connection pool.
Resolves: #540
See also: #531
Allows for injection of the app object into the request object through
the request handler.
This allows for users to setup things like database connections etc. in
listeners and then utilize them throughout the their various route
handlers.
Usage is fairly simple like so:
```python
@app.get('/')
async def handler(request):
request.app.anything
```
Name is up in the air but I'll leave this up for a few days and I'll
change it if we get a consensus
- Prevent to fall into error logging recursion when it doesn't have
request info (Print 'Unknown' when the request is still `None`
- Print repr(e) rather than str(e)
Before we didn't check if the response object was actually a response
object. This PR catches the exception should it happen and reports it to
the user.
Functionality wise this won't change much for most users, unless you
were directly importing from `sanic.sanic` in which case I am sorry if
you're affected by this.
Main motivation was because jedi autocompletion didn't work with this
and we were using relative imports to compensate for the fact that
having a module inside of your module with the same name creates major
namespace problems.
Changes from #378 introduced about a 10k request/sec slowdown. This
tries to rememdy it while keeping the same functionality but it's still
not as fast as 0.3.1
This is a tricky issue, but essentially uvloop is unavailable on windows. This means for windows users, we have to install Sanic with no requirements, and then manually specify all requirements apart from uvloop.
However, Sanic will work with standard asyncio event loop. So, I propose we remove the uvloop requirement on windows. This patch doesn't touch any demo imports.
Original sanic exception handler only could handle exact matching
exceptions. New `lookup` method will provide ability to looking up
their ancestors without additional cost of performance.
Adds a test to test for serving a static directory at the root uri '/'
to address concerns found in #374. Also rewrites the tests so that they
are parametrized and do more with less.
If we don"t `export` the variable, it's not available in subcommand:
MYAPP_SETTINGS=/path/to/config_file; python3 -c "import os; os.environ['MYAPP_SETTINGS']"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python3.5/os.py", line 725, in __getitem__
raise KeyError(key) from None
KeyError: 'MYAPP_SETTINGS'
The ';' is the culprit here.
Blueprints currently queue functions to be called, which are simple, yet
hard to inspect. These changes allow tools to be built that analyze
blueprints more easily.
This is by no means the final solution but it's a start in the right
direction. Eventually what needs to happen is we need to reduce the
complexity of the routing. CompsitionView can probably be removed later
on in favor of better Route objects. Also in the next version of sanic
we need to move merge_route and add_parameter out of the add_route logic
and just have them as standalone methods.
The tests should cover everything that we need so that if any changes
are made we can identify regression.
Addresses #353, now dynamic routes work alongside our newly minted
overloaded routes! Also fixed an unintended side effect where methods
were still being passed in as None for `Sanic.add_route`.
* Move serve_multiple, remove stop_events, fix tests
Moves serve_multiple out of the app, removes stop_event (adds a
deprecation warning, but it also wasn't doing anything) fixes
multiprocessing tests so that they don't freeze pytest's runner.
Other notes:
Also moves around some imports so that they are better optimized as
well.
* Re-add in stop_event, maybe it wasn't so bad!
* Get rid of unused warnings import
* Caching example using aiocache
* Caching example using aiocache
* Added aiocache to requirements
* Fixed example with newest aiocache
* Fixed bug in cache example
Simplifies request parameters, it defined a bit more than it had too,
added some docstrings and made the code simpler as well. Should now
raise a KeyError on __getitem__ as @amsb had noted on commit 9dd954b
* Reorder and clarify the 'Request Data' guide, adding a section on RequestParameters
* Clarify routing guide, adding introduction and HTTP types sections
* Clarify the use-cases of middleware
* Clean up formatting in the exceptions guide and add some common exceptions.
* Fix formatting of blueprints and add use-case example.
* Clarify the class-based views guide
* Clarify and fix formatting of cookies guide
* Clarify static files guide
* Clarify the custom protocols guide.
* Add more information to the deploying guide
* Fix broken list in the community extensions list.
* Add introduction and improve warning to contributing guide
* Expand getting started guide
* Reorder guides and add links between them
* Standardise heading capitalisation
Adds handling for closed transports in the server for `write_response`
as well as `write_error`, letting it all flow to `bail_out` seemed to be
a little light handed in terms of telling the logs where the
error actually occured.
Handling to fix the infinite `write_error` loop is still there and those
exceptions will get reported on in the debug logs.
When user specifies HTTP methods to function handlers, it automatically
will be overloaded unless they duplicate.
Example:
# This is a new route. It works as before.
@app.route('/overload', methods=['GET'])
async def handler1(request):
return text('OK1')
# This is the exiting route but a new method. They are merged and
# work as combined. The route will serve all of GET, POST and PUT.
@app.route('/overload', methods=['POST', 'PUT'])
async def handler2(request):
return text('OK2')
# This is the existing route and PUT method is the duplicated method.
# It raises RouteExists.
@app.route('/overload', methods=['PUT', 'DELETE'])
async def handler3(request):
return text('Duplicated')
This commit creates configuration files and an index page for
documentation using Sphinx. The recommonmark package is used to enable
Markdown support for Sphinx, using the Common Mark specification. This
means that the current documentation doesn't need to be rewritten.
- Improved codebase test coverage from 81% to 91%.
- Added stream_large_files and host examples in static_file document
- Added methods to append and finish body content on Request (#1379)
- Integrated with .appveyor.yml for windows ci support
- Added documentation for AF_INET6 and AF_UNIX socket usage
- Adopt black/isort for codestyle
- Cancel task when connection_lost
- Simplify request ip and port retrieval logic
- Handle config error in load config file.
- Integrate with codecov for CI
- Add missed documentation for config section.
- Deprecate Handler.log
- Pinned httptools requirement to version 0.0.10+
- Fixes:
- Fix `remove_entity_headers` helper function (#1415)
- Fix TypeError when use Blueprint.group() to group blueprint with default url_prefix, Use os.path.normpath to avoid invalid url_prefix like api//v1
f8a6af1 Rename the `http` module to `helpers` to prevent conflicts with the built-in Python http library (fixes #1323)
- Fix unittests on windows
- Fix Namespacing of sanic logger
- Fix missing quotes in decorator example
- Fix redirect with quoted param
- Fix doc for latest blueprint code
- Fix build of latex documentation relating to markdown lists
- Fix loop exception handling in app.py
- Fix content length mismatch in windows and other platform
- Fix Range header handling for static files (#1402)
- Fix the logger and make it work (#1397)
- Fix type pikcle->pickle in multiprocessing test
- Fix pickling blueprints Change the string passed in the "name" section of the namedtuples in Blueprint to match the name of the Blueprint module attribute name. This allows blueprints to be pickled and unpickled, without errors, which is a requirment of running Sanic in multiprocessing mode in Windows. Added a test for pickling and unpickling blueprints Added a test for pickling and unpickling sanic itself Added a test for enabling multiprocessing on an app with a blueprint (only useful to catch this bug if the tests are run on Windows).
[](https://gitter.im/sanic-python/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
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/.
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.
## Benchmarks
All tests were run on an AWS medium instance running ubuntu, using 1 process. Each script delivered a small JSON response and was tested with wrk using 100 connections. Pypy was tested for Falcon and Flask but did not speed up requests.
| Server | Implementation | Requests/sec | Avg Latency |
Sanic is a Python web server and web framework that's written to go fast. It allows the usage of the ``async/await`` syntax added in Python 3.5, which makes your code non-blocking and speedy.
`Source code on GitHub <https://github.com/huge-success/sanic/>`_ | `Help and discussion board <https://community.sanicframework.org/>`_.
The project is maintained by the community, for the community **Contributions are welcome!**
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``
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.
..code::shell
$ exportSANIC_NO_UVLOOP=true
$ exportSANIC_NO_UJSON=true
$ pip3 install sanic
Hello World Example
-------------------
..code::python
fromsanicimportSanic
fromsanic.responseimportjson
app=Sanic()
@app.route('/')
asyncdeftest(request):
returnjson({'hello':'world'})
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
`Ask a question or join the conversation <https://community.sanicframework.org/>`_.
Contribution
------------
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>`_.
Sanic has simple class based implementation. You should implement methods(get, post, put, patch, delete) for the class to every HTTP method you want to support. If someone tries to use a method that has not been implemented, there will be 405 response.
## Examples
```python
fromsanicimportSanic
fromsanic.viewsimportHTTPMethodView
fromsanic.responseimporttext
app=Sanic('some_name')
classSimpleView(HTTPMethodView):
defget(self,request):
returntext('I am get method')
defpost(self,request):
returntext('I am post method')
defput(self,request):
returntext('I am put method')
defpatch(self,request):
returntext('I am patch method')
defdelete(self,request):
returntext('I am delete method')
app.add_route(SimpleView.as_view(),'/')
```
If you need any url params just mention them in method definition:
```python
classNameView(HTTPMethodView):
defget(self,request,name):
returntext('Hello {}'.format(name))
app.add_route(NameView.as_view(),'/<name>')
```
If you want to add decorator for class, you could set decorators variable
One of the main goals of Sanic is speed. Code that lowers the performance of Sanic without significant gains in usability, security, or features may not be merged.
You can change the behavior of protocol by using custom protocol.
If you want to use custom protocol, you should put subclass of [protocol class](https://docs.python.org/3/library/asyncio-protocol.html#protocol-classes) in the protocol keyword argument of `sanic.run()`. The constructor of custom protocol class gets following keyword arguments from Sanic.
* loop
`loop` is an asyncio compatible event loop.
* connections
`connections` is a `set object` to store protocol objects.
When Sanic receives `SIGINT` or `SIGTERM`, Sanic executes `protocol.close_if_idle()` for a `protocol objects` stored in connections.
* signal
`signal` is a `sanic.server.Signal object` with `stopped attribute`.
When Sanic receives `SIGINT` or `SIGTERM`, `signal.stopped` becomes `True`.
* request_handler
`request_handler` is a coroutine that takes a `sanic.request.Request` object and a `response callback` as arguments.
* error_handler
`error_handler` is a `sanic.exceptions.Handler` object.
* request_timeout
`request_timeout` is seconds for timeout.
* request_max_size
`request_max_size` is bytes of max request size.
## Example
By default protocol, an error occurs, if the handler does not return an `HTTPResponse object`.
In this example, By rewriting `write_response()`, if the handler returns `str`, it will be converted to an `HTTPResponse object`.
Exceptions can be thrown from within request handlers and will automatically be handled by Sanic. Exceptions take a message as their first argument, and can also take a status_code to be passed back in the HTTP response. Check sanic.exceptions for the full list of exceptions to throw.
## Throwing an exception
```python
fromsanicimportSanic
fromsanic.exceptionsimportServerError
@app.route('/killme')
defi_am_ready_to_die(request):
raiseServerError("Something bad happened")
```
## Handling Exceptions
Just use the @exception decorator. The decorator expects a list of exceptions to handle as arguments. You can pass SanicException to catch them all! The exception handler must expect a request and exception object as arguments.
```python
fromsanicimportSanic
fromsanic.responseimporttext
fromsanic.exceptionsimportNotFound
@app.exception(NotFound)
defignore_404s(request,exception):
returntext("Yep, I totally found the page: {}".format(request.url))
Middleware can be executed before or after requests. It is executed in the order it was registered. If middleware returns a response object, the request will stop processing and a response will be returned.
Middleware is registered via the middleware decorator, and can either be added as 'request' or 'response' middleware, based on the argument provided in the decorator. Response middleware receives both the request and the response as arguments.
## Examples
```python
app=Sanic(__name__)
@app.middleware
asyncdefhalt_request(request):
print("I am a spy")
@app.middleware('request')
asyncdefhalt_request(request):
returntext('I halted the request')
@app.middleware('response')
asyncdefhalt_response(request,response):
returntext('I halted the response')
@app.route('/')
asyncdefhandler(request):
returntext('I would like to speak now please')
app.run(host="0.0.0.0",port=8000)
```
## Middleware chain
If you want to apply the middleware as a chain, applying more than one, is so easy. You only have to be aware that you do **not return** any response in your middleware:
The above code will apply the two middlewares in order. First the middleware **custom_banner** will change the HTTP Response headers *Server* by *Fake-Server*, and the second middleware **prevent_xss** will add the HTTP Headers for prevent Cross-Site-Scripting (XSS) attacks.
Sanic comes with a basic router that supports request parameters. To specify a parameter, surround it with carrots like so: `<PARAM>`. Request parameters will be passed to the request handler functions as keyword arguments. To specify a type, add a :type after the parameter name, in the carrots. If the parameter does not match the type supplied, Sanic will throw a NotFound exception, resulting in a 404 page not found error.
Blueprints may also be registered as part of a list or tuple, where the registrar will recursively cycle through any sub-sequences of blueprints and register them accordingly. The `Blueprint.group` method is provided to simplify this process, allowing a 'mock' backend directory structure mimicking what's seen from the front end. Consider this (quite contrived) example:
```
api/
├──content/
│ ├──authors.py
│ ├──static.py
│ └──__init__.py
├──info.py
└──__init__.py
app.py
```
Initialization of this app's blueprint hierarchy could go as follows:
- Improved codebase test coverage from 81% to 91%.
- Added stream_large_files and host examples in static_file document
- Added methods to append and finish body content on Request (#1379)
- Integrated with .appveyor.yml for windows ci support
- Added documentation for AF_INET6 and AF_UNIX socket usage
- Adopt black/isort for codestyle
- Cancel task when connection_lost
- Simplify request ip and port retrieval logic
- Handle config error in load config file.
- Integrate with codecov for CI
- Add missed documentation for config section.
- Deprecate Handler.log
- Pinned httptools requirement to version 0.0.10+
- Fixes:
- Fix `remove_entity_headers` helper function (#1415)
- Fix TypeError when use Blueprint.group() to group blueprint with default url_prefix, Use os.path.normpath to avoid invalid url_prefix like api//v1
f8a6af1 Rename the `http` module to `helpers` to prevent conflicts with the built-in Python http library (fixes #1323)
- Fix unittests on windows
- Fix Namespacing of sanic logger
- Fix missing quotes in decorator example
- Fix redirect with quoted param
- Fix doc for latest blueprint code
- Fix build of latex documentation relating to markdown lists
- Fix loop exception handling in app.py
- Fix content length mismatch in windows and other platform
- Fix Range header handling for static files (#1402)
- Fix the logger and make it work (#1397)
- Fix type pikcle->pickle in multiprocessing test
- Fix pickling blueprints Change the string passed in the "name" section of the namedtuples in Blueprint to match the name of the Blueprint module attribute name. This allows blueprints to be pickled and unpickled, without errors, which is a requirment of running Sanic in multiprocessing mode in Windows. Added a test for pickling and unpickling blueprints Added a test for pickling and unpickling sanic itself Added a test for enabling multiprocessing on an app with a blueprint (only useful to catch this bug if the tests are run on Windows).
Any reasonably complex application will need configuration that is not baked into the actual code. Settings might be different for different environments or installations.
## Basics
Sanic holds the configuration in the `config` attribute of the application object. The configuration object is merely an object that can be modified either using dot-notation or like a dictionary:
```
app = Sanic('myapp')
app.config.DB_NAME = 'appdb'
app.config.DB_USER = 'appuser'
```
Since the config object actually is a dictionary, you can use its `update` method in order to set several values at once:
```
db_settings = {
'DB_HOST': 'localhost',
'DB_NAME': 'appdb',
'DB_USER': 'appuser'
}
app.config.update(db_settings)
```
In general the convention is to only have UPPERCASE configuration parameters. The methods described below for loading configuration only look for such uppercase parameters.
## Loading Configuration
There are several ways how to load configuration.
### From Environment Variables
Any variables defined with the `SANIC_` prefix will be applied to the sanic config. For example, setting `SANIC_REQUEST_TIMEOUT` will be loaded by the application automatically and fed into the `REQUEST_TIMEOUT` config variable. You can pass a different prefix to Sanic:
```python
app=Sanic(load_env='MYAPP_')
```
Then the above variable would be `MYAPP_REQUEST_TIMEOUT`. If you want to disable loading from environment variables you can set it to `False` instead:
```python
app=Sanic(load_env=False)
```
### From an Object
If there are a lot of configuration values and they have sensible defaults it might be helpful to put them into a module:
```
import myapp.default_settings
app = Sanic('myapp')
app.config.from_object(myapp.default_settings)
```
You could use a class or any other object as well.
### From a File
Usually you will want to load configuration from a file that is not part of the distributed application. You can load configuration from a file using `from_pyfile(/path/to/config_file)`. However, that requires the program to know the path to the config file. So instead you can specify the location of the config file in an environment variable and tell Sanic to use that to find the config file:
```
app = Sanic('myapp')
app.config.from_envvar('MYAPP_SETTINGS')
```
Then you can run your application with the `MYAPP_SETTINGS` environment variable set:
The config files are regular Python files which are executed in order to load them. This allows you to use arbitrary logic for constructing the right configuration. Only uppercase variables are added to the configuration. Most commonly the configuration consists of simple key value pairs:
```
# config_file
DB_HOST = 'localhost'
DB_NAME = 'appdb'
DB_USER = 'appuser'
```
## Builtin Configuration Values
Out of the box there are just a few predefined values which can be overwritten when creating the application.
Since Sanic handlers are simple Python functions, you can apply decorators to them in a similar manner to Flask. A typical use case is when you want some code to run before a handler's code is executed.
## Authorization Decorator
Let's say you want to check that a user is authorized to access a particular endpoint. You can create a decorator that wraps a handler function, checks a request if the client is authorized to access a resource, and sends the appropriate response.
A list of Sanic extensions created by the community.
## Extension and Plugin Development
- [Sanic-Plugins-Framework](https://github.com/ashleysommer/sanicpluginsframework): Library for easily creating and using Sanic plugins.
- [sanic-script](https://github.com/tim2anna/sanic-script): An extension for Sanic that adds support for writing commands to your application.
## Security
- [Sanic JWT](https://github.com/ahopkins/sanic-jwt): Authentication, JWT, and permission scoping for Sanic.
- [Secure](https://github.com/cakinney/secure): Secure 🔒 is a lightweight package that adds optional security headers and cookie attributes for Python web frameworks.
- [Sessions](https://github.com/subyraman/sanic_session): Support for sessions. Allows using redis, memcache or an in memory store.
- [CORS](https://github.com/ashleysommer/sanic-cors): A port of flask-cors.
- [Sanic-JWT-Extended](https://github.com/devArtoria/Sanic-JWT-Extended): Provides extended JWT support for
- [UserAgent](https://github.com/lixxu/sanic-useragent): Add `user_agent` to request
- [Limiter](https://github.com/bohea/sanic-limiter): Rate limiting for sanic.
- [sanic-oauth](https://gitlab.com/SirEdvin/sanic-oauth): OAuth Library with many provider and OAuth1/OAuth2 support.
- [Sanic-Auth](https://github.com/pyx/sanic-auth): A minimal backend agnostic session-based user authentication mechanism for Sanic.
- [Sanic-CookieSession](https://github.com/pyx/sanic-cookiesession): A client-side only, cookie-based session, similar to the built-in session in Flask.
## Documentation
- [OpenAPI/Swagger](https://github.com/channelcat/sanic-openapi): OpenAPI support, plus a Swagger UI.
- [Sanic-RestPlus](https://github.com/ashleysommer/sanic-restplus): A port of Flask-RestPlus for Sanic. Full-featured REST API with SwaggerUI generation.
- [sanic-transmute](https://github.com/yunstanford/sanic-transmute): A Sanic extension that generates APIs from python function and classes, and also generates Swagger UI/documentation automatically.
## ORM and Database Integration
- [Motor](https://github.com/lixxu/sanic-motor): Simple motor wrapper.
- [Sanic CRUD](https://github.com/Typhon66/sanic_crud): CRUD REST API generation with peewee models.
- [sanic-graphql](https://github.com/graphql-python/sanic-graphql): GraphQL integration with Sanic
- [GINO](https://github.com/fantix/gino): An asyncio ORM on top of SQLAlchemy core, delivered with a Sanic extension. ([Documentation](https://python-gino.readthedocs.io/))
- [Databases](https://github.com/encode/databases): Async database access for SQLAlchemy core, with support for PostgreSQL, MySQL, and SQLite.
## Unit Testing
- [pytest-sanic](https://github.com/yunstanford/pytest-sanic): A pytest plugin for Sanic. It helps you to test your code asynchronously.
## Project Creation Template
- [cookiecutter-sanic](https://github.com/harshanarayana/cookiecutter-sanic): Get your sanic application up and running in a matter of second in a well defined project structure.
Batteries included for deployment, unit testing, automated release management and changelog generation.
## Templating
- [Sanic-WTF](https://github.com/pyx/sanic-wtf): Sanic-WTF makes using WTForms with Sanic and CSRF (Cross-Site Request Forgery) protection a little bit easier.
- [Jinja2](https://github.com/lixxu/sanic-jinja2): Support for Jinja2 template.
- [jinja2-sanic](https://github.com/yunstanford/jinja2-sanic): a jinja2 template renderer for Sanic.([Documentation](http://jinja2-sanic.readthedocs.io/en/latest/))
## API Helper Utilities
- [sanic-sse](https://github.com/inn0kenty/sanic_sse): [Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events) implementation for Sanic.
- [Compress](https://github.com/subyraman/sanic_compress): Allows you to easily gzip Sanic responses. A port of Flask-Compress.
- [Sanic EnvConfig](https://github.com/jamesstidard/sanic-envconfig): Pull environment variables into your sanic config.
## i18n/l10n Support
- [Babel](https://github.com/lixxu/sanic-babel): Adds i18n/l10n support to Sanic applications with the help of the `Babel` library
## Custom Middlewares
- [Dispatch](https://github.com/ashleysommer/sanic-dispatcher): A dispatcher inspired by `DispatcherMiddleware` in werkzeug. Can act as a Sanic-to-WSGI adapter.
## Monitoring and Reporting
- [sanic-prometheus](https://github.com/dkruchinin/sanic-prometheus): Prometheus metrics for Sanic
- [sanic-zipkin](https://github.com/kevinqqnj/sanic-zipkin): Easily report request/function/RPC traces to zipkin/jaeger, through aiozipkin.
## Sample Applications
- [Sanic-nginx-docker-example](https://github.com/itielshwartz/sanic-nginx-docker-example): Simple and easy to use example of Sanic behined nginx using docker-compose.
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/>`_.
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.
Sanic is developed `on GitHub <https://github.com/channelcat/sanic/>`_. Contributions are welcome!
- `body` (bytes) - Posted raw body. This property allows retrieval of the
request's raw data, regardless of content type.
```python
from sanic.response import text
@app.route("/users", methods=["POST",])
def create_user(request):
return text("You are trying to create a user with the following POST: %s" % request.body)
```
- `headers` (dict) - A case-insensitive dictionary that contains the request headers.
- `method` (str) - HTTP method of the request (ie `GET`, `POST`).
- `ip` (str) - IP address of the requester.
- `port` (str) - Port address of the requester.
- `socket` (tuple) - (IP, port) of the requester.
- `app` - a reference to the Sanic application object that is handling this request. This is useful when inside blueprints or other handlers in modules that do not have access to the global `app` object.
```python
from sanic.response import json
from sanic import Blueprint
bp = Blueprint('my_blueprint')
@bp.route('/')
async def bp_root(request):
if request.app.config['DEBUG']:
return json({'status': 'debug'})
else:
return json({'status': 'production'})
```
- `url`: The full URL of the request, ie: `http://localhost:8000/posts/1/?foo=bar`
- `scheme`: The URL scheme associated with the request: `http` or `https`
- `host`: The host associated with the request: `localhost:8080`
- `path`: The path of the request: `/posts/1/`
- `query_string`: The query string of the request: `foo=bar` or a blank string `''`
- `uri_template`: Template for matching route handler: `/posts/<id>/`
- `token`: The value of Authorization header: `Basic YWRtaW46YWRtaW4=`
## Changing the default parsing rules of the queryset
The default parameters that are using internally in `args` and `query_args` properties to parse queryset:
- `keep_blank_values` (bool): `False` - flag indicating whether blank values in
percent-encoded queries should be treated as blank strings.
A true value indicates that blanks should be retained as blank
strings. The default false value indicates that blank values
are to be ignored and treated as if they were not included.
- `strict_parsing` (bool): `False` - flag indicating what to do with parsing errors. If
false (the default), errors are silently ignored. If true,
errors raise a ValueError exception.
- `encoding` and `errors` (str): 'utf-8' and 'replace' - specify how to decode percent-encoded sequences
into Unicode characters, as accepted by the bytes.decode() method.
If you would like to change that default parameters you could call `get_args` and `get_query_args` methods
with the new values.
For the queryset `/?test1=value1&test2=&test3=value3`:
There is also an optional `host` argument (which can be a list or a string). This restricts a route to the host or hosts provided. If there is a also a route with no host, it will be the default.
Sanic provides a `url_for` method, to generate URLs based on the handler method name. This is useful if you want to avoid hardcoding url paths into your app; instead, you can just reference the handler name. For example:
```python
fromsanic.responseimportredirect
@app.route('/')
asyncdefindex(request):
# generate a URL for the endpoint `post_handler`
url=app.url_for('post_handler',post_id=5)
# the URL is `/posts/5`, redirect to it
returnredirect(url)
@app.route('/posts/<post_id>')
asyncdefpost_handler(request,post_id):
returntext('Post - {}'.format(post_id))
```
Other things to keep in mind when using `url_for`:
- Keyword arguments passed to `url_for` that are not request parameters will be included in the URL's query string. For example:
- Also some special arguments (`_anchor`, `_external`, `_scheme`, `_method`, `_server`) passed to `url_for` will have special url building (`_method` is not supported now and will be ignored). For example:
- All valid parameters must be passed to `url_for` to build a URL. If a parameter is not supplied, or if a parameter does not match the specified type, a `URLBuildError` will be raised.
## WebSocket routes
Routes for the WebSocket protocol can be defined with the `@app.websocket`
decorator:
```python
@app.websocket('/feed')
asyncdeffeed(request,ws):
whileTrue:
data='hello!'
print('Sending: '+data)
awaitws.send(data)
data=awaitws.recv()
print('Received: '+data)
```
Alternatively, the `app.add_websocket_route` method can be used instead of the
> **Note:** Sanic does not provide directory index when you serve a static directory.
## Virtual Host
The `app.static()` method also support **virtual host**. You can serve your static files with specific **virtual host** with `host` argument. For example:
In some cases, you might server large file(ex: videos, images, etc.) with Sanic. You can choose to use **streaming file** rather than download directly.
When `stream_large_files` is `True`, Sanic will use `file_stream()` instead of `file()` to serve static files. This will use **1KB** as the default chunk size. And, if needed, you can also use a custom chunk size. For example:
Sanic allows you to get request data by stream, as below. When the request ends, `await request.stream.read()` returns `None`. Only post, put and patch decorator have stream argument.
```python
fromsanicimportSanic
fromsanic.viewsimportCompositionView
fromsanic.viewsimportHTTPMethodView
fromsanic.viewsimportstreamasstream_decorator
fromsanic.blueprintsimportBlueprint
fromsanic.responseimportstream,text
bp=Blueprint('blueprint_request_stream')
app=Sanic('request_stream')
classSimpleView(HTTPMethodView):
@stream_decorator
asyncdefpost(self,request):
result=''
whileTrue:
body=awaitrequest.stream.read()
ifbodyisNone:
break
result+=body.decode('utf-8')
returntext(result)
@app.post('/stream',stream=True)
asyncdefhandler(request):
asyncdefstreaming(response):
whileTrue:
body=awaitrequest.stream.read()
ifbodyisNone:
break
body=body.decode('utf-8').replace('1','A')
awaitresponse.write(body)
returnstream(streaming)
@bp.put('/bp_stream',stream=True)
asyncdefbp_put_handler(request):
result=''
whileTrue:
body=awaitrequest.stream.read()
ifbodyisNone:
break
result+=body.decode('utf-8').replace('1','A')
returntext(result)
# You can also use `bp.add_route()` with stream argument
Sanic allows you to stream content to the client with the `stream` method. This method accepts a coroutine callback which is passed a `StreamingHTTPResponse` object that is written to. A simple example is like follows:
This is useful in situations where you want to stream content to the client that originates in an external service, like a database. For example, you can stream database records to the client with the asynchronous cursor that `asyncpg` provides:
You can pass the `version` keyword to the route decorators, or to a blueprint initializer. It will result in the `v{version}` url prefix where `{version}` is the version number.
## Per route
You can pass a version number to the routes directly.
```python
fromsanicimportresponse
@app.route('/text',version=1)
defhandle_request(request):
returnresponse.text('Hello world! Version 1')
@app.route('/text',version=2)
defhandle_request(request):
returnresponse.text('Hello world! Version 2')
app.run(port=80)
```
Then with curl:
```bash
curl localhost/v1/text
curl localhost/v2/text
```
## Global blueprint version
You can also pass a version number to the blueprint, which will apply to all routes.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.