Resolve merge conflict

This commit is contained in:
Adam Hopkins 2021-02-16 11:36:06 +02:00
commit 9e23e75fb4
15 changed files with 553 additions and 337 deletions

View File

@ -1,3 +1,31 @@
Version 20.12.2
===============
Dependencies
************
*
`#2026 <https://github.com/sanic-org/sanic/pull/2026>`_
Fix uvloop to 0.14 because 0.15 drops Python 3.6 support
*
`#2029 <https://github.com/sanic-org/sanic/pull/2029>`_
Remove old chardet requirement, add in hard multidict requirement
Version 19.12.5
===============
Dependencies
************
*
`#2025 <https://github.com/sanic-org/sanic/pull/2025>`_
Fix uvloop to 0.14 because 0.15 drops Python 3.6 support
*
`#2027 <https://github.com/sanic-org/sanic/pull/2027>`_
Remove old chardet requirement, add in hard multidict requirement
Version 20.12.0
===============
@ -5,83 +33,93 @@ Features
********
*
`#1945 <https://github.com/huge-success/sanic/pull/1945>`_
`#1993 <https://github.com/sanic-org/sanic/pull/1993>`_
Add disable app registry
Version 20.12.0
===============
Features
********
*
`#1945 <https://github.com/sanic-org/sanic/pull/1945>`_
Static route more verbose if file not found
*
`#1954 <https://github.com/huge-success/sanic/pull/1954>`_
`#1954 <https://github.com/sanic-org/sanic/pull/1954>`_
Fix static routes registration on a blueprint
*
`#1961 <https://github.com/huge-success/sanic/pull/1961>`_
`#1961 <https://github.com/sanic-org/sanic/pull/1961>`_
Add Python 3.9 support
*
`#1962 <https://github.com/huge-success/sanic/pull/1962>`_
`#1962 <https://github.com/sanic-org/sanic/pull/1962>`_
Sanic CLI upgrade
*
`#1967 <https://github.com/huge-success/sanic/pull/1967>`_
`#1967 <https://github.com/sanic-org/sanic/pull/1967>`_
Update aiofile version requirements
*
`#1969 <https://github.com/huge-success/sanic/pull/1969>`_
`#1969 <https://github.com/sanic-org/sanic/pull/1969>`_
Update multidict version requirements
*
`#1970 <https://github.com/huge-success/sanic/pull/1970>`_
`#1970 <https://github.com/sanic-org/sanic/pull/1970>`_
Add py.typed file
*
`#1972 <https://github.com/huge-success/sanic/pull/1972>`_
`#1972 <https://github.com/sanic-org/sanic/pull/1972>`_
Speed optimization in request handler
*
`#1979 <https://github.com/huge-success/sanic/pull/1979>`_
`#1979 <https://github.com/sanic-org/sanic/pull/1979>`_
Add app registry and Sanic class level app retrieval
Bugfixes
********
*
`#1965 <https://github.com/huge-success/sanic/pull/1965>`_
`#1965 <https://github.com/sanic-org/sanic/pull/1965>`_
Fix Chunked Transport-Encoding in ASGI streaming response
Deprecations and Removals
*************************
*
`#1981 <https://github.com/huge-success/sanic/pull/1981>`_
`#1981 <https://github.com/sanic-org/sanic/pull/1981>`_
Cleanup and remove deprecated code
Developer infrastructure
************************
*
`#1956 <https://github.com/huge-success/sanic/pull/1956>`_
`#1956 <https://github.com/sanic-org/sanic/pull/1956>`_
Fix load module test
*
`#1973 <https://github.com/huge-success/sanic/pull/1973>`_
`#1973 <https://github.com/sanic-org/sanic/pull/1973>`_
Transition Travis from .org to .com
*
`#1986 <https://github.com/huge-success/sanic/pull/1986>`_
`#1986 <https://github.com/sanic-org/sanic/pull/1986>`_
Update tox requirements
Improved Documentation
**********************
*
`#1951 <https://github.com/huge-success/sanic/pull/1951>`_
`#1951 <https://github.com/sanic-org/sanic/pull/1951>`_
Documentation improvements
*
`#1983 <https://github.com/huge-success/sanic/pull/1983>`_
`#1983 <https://github.com/sanic-org/sanic/pull/1983>`_
Remove duplicate contents in testing.rst
*
`#1984 <https://github.com/huge-success/sanic/pull/1984>`_
`#1984 <https://github.com/sanic-org/sanic/pull/1984>`_
Fix typo in routing.rst
@ -92,10 +130,10 @@ Bugfixes
********
*
`#1954 <https://github.com/huge-success/sanic/pull/1954>`_
`#1954 <https://github.com/sanic-org/sanic/pull/1954>`_
Fix static route registration on blueprints
*
`#1957 <https://github.com/huge-success/sanic/pull/1957>`_
`#1957 <https://github.com/sanic-org/sanic/pull/1957>`_
Removes duplicate headers in ASGI streaming body
@ -106,7 +144,7 @@ Bugfixes
********
*
`#1959 <https://github.com/huge-success/sanic/pull/1959>`_
`#1959 <https://github.com/sanic-org/sanic/pull/1959>`_
Removes duplicate headers in ASGI streaming body
@ -118,65 +156,65 @@ Features
********
*
`#1887 <https://github.com/huge-success/sanic/pull/1887>`_
`#1887 <https://github.com/sanic-org/sanic/pull/1887>`_
Pass subprotocols in websockets (both sanic server and ASGI)
*
`#1894 <https://github.com/huge-success/sanic/pull/1894>`_
`#1894 <https://github.com/sanic-org/sanic/pull/1894>`_
Automatically set ``test_mode`` flag on app instance
*
`#1903 <https://github.com/huge-success/sanic/pull/1903>`_
`#1903 <https://github.com/sanic-org/sanic/pull/1903>`_
Add new unified method for updating app values
*
`#1906 <https://github.com/huge-success/sanic/pull/1906>`_,
`#1909 <https://github.com/huge-success/sanic/pull/1909>`_
`#1906 <https://github.com/sanic-org/sanic/pull/1906>`_,
`#1909 <https://github.com/sanic-org/sanic/pull/1909>`_
Adds WEBSOCKET_PING_TIMEOUT and WEBSOCKET_PING_INTERVAL configuration values
*
`#1935 <https://github.com/huge-success/sanic/pull/1935>`_
`#1935 <https://github.com/sanic-org/sanic/pull/1935>`_
httpx version dependency updated, it is slated for removal as a dependency in v20.12
*
`#1937 <https://github.com/huge-success/sanic/pull/1937>`_
`#1937 <https://github.com/sanic-org/sanic/pull/1937>`_
Added auto, text, and json fallback error handlers (in v21.3, the default will change form html to auto)
Bugfixes
********
*
`#1897 <https://github.com/huge-success/sanic/pull/1897>`_
`#1897 <https://github.com/sanic-org/sanic/pull/1897>`_
Resolves exception from unread bytes in stream
Deprecations and Removals
*************************
*
`#1903 <https://github.com/huge-success/sanic/pull/1903>`_
`#1903 <https://github.com/sanic-org/sanic/pull/1903>`_
config.from_envar, config.from_pyfile, and config.from_object are deprecated and set to be removed in v21.3
Developer infrastructure
************************
*
`#1890 <https://github.com/huge-success/sanic/pull/1890>`_,
`#1891 <https://github.com/huge-success/sanic/pull/1891>`_
`#1890 <https://github.com/sanic-org/sanic/pull/1890>`_,
`#1891 <https://github.com/sanic-org/sanic/pull/1891>`_
Update isort calls to be compatible with new API
*
`#1893 <https://github.com/huge-success/sanic/pull/1893>`_
`#1893 <https://github.com/sanic-org/sanic/pull/1893>`_
Remove version section from setup.cfg
*
`#1924 <https://github.com/huge-success/sanic/pull/1924>`_
`#1924 <https://github.com/sanic-org/sanic/pull/1924>`_
Adding --strict-markers for pytest
Improved Documentation
**********************
*
`#1922 <https://github.com/huge-success/sanic/pull/1922>`_
`#1922 <https://github.com/sanic-org/sanic/pull/1922>`_
Add explicit ASGI compliance to the README
@ -187,7 +225,7 @@ Bugfixes
********
*
`#1884 <https://github.com/huge-success/sanic/pull/1884>`_
`#1884 <https://github.com/sanic-org/sanic/pull/1884>`_
Revert change to multiprocessing mode
@ -198,7 +236,7 @@ Features
********
*
`#1641 <https://github.com/huge-success/sanic/pull/1641>`_
`#1641 <https://github.com/sanic-org/sanic/pull/1641>`_
Socket binding implemented properly for IPv6 and UNIX sockets
@ -209,60 +247,60 @@ Features
********
*
`#1760 <https://github.com/huge-success/sanic/pull/1760>`_
`#1760 <https://github.com/sanic-org/sanic/pull/1760>`_
Add version parameter to websocket routes
*
`#1866 <https://github.com/huge-success/sanic/pull/1866>`_
`#1866 <https://github.com/sanic-org/sanic/pull/1866>`_
Add ``sanic`` as an entry point command
*
`#1880 <https://github.com/huge-success/sanic/pull/1880>`_
`#1880 <https://github.com/sanic-org/sanic/pull/1880>`_
Add handler names for websockets for url_for usage
Bugfixes
********
*
`#1776 <https://github.com/huge-success/sanic/pull/1776>`_
`#1776 <https://github.com/sanic-org/sanic/pull/1776>`_
Bug fix for host parameter issue with lists
*
`#1842 <https://github.com/huge-success/sanic/pull/1842>`_
`#1842 <https://github.com/sanic-org/sanic/pull/1842>`_
Fix static _handler pickling error
*
`#1827 <https://github.com/huge-success/sanic/pull/1827>`_
`#1827 <https://github.com/sanic-org/sanic/pull/1827>`_
Fix reloader on OSX py38 and Windows
*
`#1848 <https://github.com/huge-success/sanic/pull/1848>`_
`#1848 <https://github.com/sanic-org/sanic/pull/1848>`_
Reverse named_response_middlware execution order, to match normal response middleware execution order
*
`#1853 <https://github.com/huge-success/sanic/pull/1853>`_
`#1853 <https://github.com/sanic-org/sanic/pull/1853>`_
Fix pickle error when attempting to pickle an application which contains websocket routes
Deprecations and Removals
*************************
*
`#1739 <https://github.com/huge-success/sanic/pull/1739>`_
`#1739 <https://github.com/sanic-org/sanic/pull/1739>`_
Deprecate body_bytes to merge into body
Developer infrastructure
************************
*
`#1852 <https://github.com/huge-success/sanic/pull/1852>`_
`#1852 <https://github.com/sanic-org/sanic/pull/1852>`_
Fix naming of CI test env on Python nightlies
*
`#1857 <https://github.com/huge-success/sanic/pull/1857>`_
`#1857 <https://github.com/sanic-org/sanic/pull/1857>`_
Adjust websockets version to setup.py
*
`#1869 <https://github.com/huge-success/sanic/pull/1869>`_
`#1869 <https://github.com/sanic-org/sanic/pull/1869>`_
Wrap run()'s "protocol" type annotation in Optional[]
@ -270,11 +308,11 @@ Improved Documentation
**********************
*
`#1846 <https://github.com/huge-success/sanic/pull/1846>`_
`#1846 <https://github.com/sanic-org/sanic/pull/1846>`_
Update docs to clarify response middleware execution order
*
`#1865 <https://github.com/huge-success/sanic/pull/1865>`_
`#1865 <https://github.com/sanic-org/sanic/pull/1865>`_
Fixing rst format issue that was hiding documentation
@ -291,127 +329,127 @@ Features
********
*
`#1762 <https://github.com/huge-success/sanic/pull/1762>`_
`#1762 <https://github.com/sanic-org/sanic/pull/1762>`_
Add ``srv.start_serving()`` and ``srv.serve_forever()`` to ``AsyncioServer``
*
`#1767 <https://github.com/huge-success/sanic/pull/1767>`_
`#1767 <https://github.com/sanic-org/sanic/pull/1767>`_
Make Sanic usable on ``hypercorn -k trio myweb.app``
*
`#1768 <https://github.com/huge-success/sanic/pull/1768>`_
`#1768 <https://github.com/sanic-org/sanic/pull/1768>`_
No tracebacks on normal errors and prettier error pages
*
`#1769 <https://github.com/huge-success/sanic/pull/1769>`_
`#1769 <https://github.com/sanic-org/sanic/pull/1769>`_
Code cleanup in file responses
*
`#1793 <https://github.com/huge-success/sanic/pull/1793>`_ and
`#1819 <https://github.com/huge-success/sanic/pull/1819>`_
`#1793 <https://github.com/sanic-org/sanic/pull/1793>`_ and
`#1819 <https://github.com/sanic-org/sanic/pull/1819>`_
Upgrade ``str.format()`` to f-strings
*
`#1798 <https://github.com/huge-success/sanic/pull/1798>`_
`#1798 <https://github.com/sanic-org/sanic/pull/1798>`_
Allow multiple workers on MacOS with Python 3.8
*
`#1820 <https://github.com/huge-success/sanic/pull/1820>`_
`#1820 <https://github.com/sanic-org/sanic/pull/1820>`_
Do not set content-type and content-length headers in exceptions
Bugfixes
********
*
`#1748 <https://github.com/huge-success/sanic/pull/1748>`_
`#1748 <https://github.com/sanic-org/sanic/pull/1748>`_
Remove loop argument in ``asyncio.Event`` in Python 3.8
*
`#1764 <https://github.com/huge-success/sanic/pull/1764>`_
`#1764 <https://github.com/sanic-org/sanic/pull/1764>`_
Allow route decorators to stack up again
*
`#1789 <https://github.com/huge-success/sanic/pull/1789>`_
`#1789 <https://github.com/sanic-org/sanic/pull/1789>`_
Fix tests using hosts yielding incorrect ``url_for``
*
`#1808 <https://github.com/huge-success/sanic/pull/1808>`_
`#1808 <https://github.com/sanic-org/sanic/pull/1808>`_
Fix Ctrl+C and tests on Windows
Deprecations and Removals
*************************
*
`#1800 <https://github.com/huge-success/sanic/pull/1800>`_
`#1800 <https://github.com/sanic-org/sanic/pull/1800>`_
Begin deprecation in way of first-class streaming, removal of ``body_init``, ``body_push``, and ``body_finish``
*
`#1801 <https://github.com/huge-success/sanic/pull/1801>`_
Complete deprecation from `#1666 <https://github.com/huge-success/sanic/pull/1666>`_ of dictionary context on ``request`` objects.
`#1801 <https://github.com/sanic-org/sanic/pull/1801>`_
Complete deprecation from `#1666 <https://github.com/sanic-org/sanic/pull/1666>`_ of dictionary context on ``request`` objects.
*
`#1807 <https://github.com/huge-success/sanic/pull/1807>`_
`#1807 <https://github.com/sanic-org/sanic/pull/1807>`_
Remove server config args that can be read directly from app
*
`#1818 <https://github.com/huge-success/sanic/pull/1818>`_
`#1818 <https://github.com/sanic-org/sanic/pull/1818>`_
Complete deprecation of ``app.remove_route`` and ``request.raw_args``
Dependencies
************
*
`#1794 <https://github.com/huge-success/sanic/pull/1794>`_
`#1794 <https://github.com/sanic-org/sanic/pull/1794>`_
Bump ``httpx`` to 0.11.1
*
`#1806 <https://github.com/huge-success/sanic/pull/1806>`_
`#1806 <https://github.com/sanic-org/sanic/pull/1806>`_
Import ``ASGIDispatch`` from top-level ``httpx`` (from third-party deprecation)
Developer infrastructure
************************
*
`#1833 <https://github.com/huge-success/sanic/pull/1833>`_
`#1833 <https://github.com/sanic-org/sanic/pull/1833>`_
Resolve broken documentation builds
Improved Documentation
**********************
*
`#1755 <https://github.com/huge-success/sanic/pull/1755>`_
`#1755 <https://github.com/sanic-org/sanic/pull/1755>`_
Usage of ``response.empty()``
*
`#1778 <https://github.com/huge-success/sanic/pull/1778>`_
`#1778 <https://github.com/sanic-org/sanic/pull/1778>`_
Update README
*
`#1783 <https://github.com/huge-success/sanic/pull/1783>`_
`#1783 <https://github.com/sanic-org/sanic/pull/1783>`_
Fix typo
*
`#1784 <https://github.com/huge-success/sanic/pull/1784>`_
Corrected changelog for docs move of MD to RST (`#1691 <https://github.com/huge-success/sanic/pull/1691>`_)
`#1784 <https://github.com/sanic-org/sanic/pull/1784>`_
Corrected changelog for docs move of MD to RST (`#1691 <https://github.com/sanic-org/sanic/pull/1691>`_)
*
`#1803 <https://github.com/huge-success/sanic/pull/1803>`_
`#1803 <https://github.com/sanic-org/sanic/pull/1803>`_
Update config docs to match DEFAULT_CONFIG
*
`#1814 <https://github.com/huge-success/sanic/pull/1814>`_
`#1814 <https://github.com/sanic-org/sanic/pull/1814>`_
Update getting_started.rst
*
`#1821 <https://github.com/huge-success/sanic/pull/1821>`_
`#1821 <https://github.com/sanic-org/sanic/pull/1821>`_
Update to deployment
*
`#1822 <https://github.com/huge-success/sanic/pull/1822>`_
`#1822 <https://github.com/sanic-org/sanic/pull/1822>`_
Update docs with changes done in 20.3
*
`#1834 <https://github.com/huge-success/sanic/pull/1834>`_
`#1834 <https://github.com/sanic-org/sanic/pull/1834>`_
Order of listeners
@ -431,11 +469,11 @@ Bugfixes
- If you register a middleware via :code:`@blueprint.middleware` then it will apply only to the routes defined by the blueprint.
- If you register a middleware via :code:`@blueprint_group.middleware` then it will apply to all blueprint based routes that are part of the group.
- If you define a middleware via :code:`@app.middleware` then it will be applied on all available routes (`#37 <https://github.com/huge-success/sanic/issues/37>`__)
- If you define a middleware via :code:`@app.middleware` then it will be applied on all available routes (`#37 <https://github.com/sanic-org/sanic/issues/37>`__)
- Fix `url_for` behavior with missing SERVER_NAME
If the `SERVER_NAME` was missing in the `app.config` entity, the `url_for` on the `request` and `app` were failing
due to an `AttributeError`. This fix makes the availability of `SERVER_NAME` on our `app.config` an optional behavior. (`#1707 <https://github.com/huge-success/sanic/issues/1707>`__)
due to an `AttributeError`. This fix makes the availability of `SERVER_NAME` on our `app.config` an optional behavior. (`#1707 <https://github.com/sanic-org/sanic/issues/1707>`__)
Improved Documentation
@ -444,10 +482,10 @@ Improved Documentation
- Move docs from MD to RST
Moved all docs from markdown to restructured text like the rest of the docs to unify the scheme and make it easier in
the future to update documentation. (`#1691 <https://github.com/huge-success/sanic/issues/1691>`__)
the future to update documentation. (`#1691 <https://github.com/sanic-org/sanic/issues/1691>`__)
- Fix documentation for `get` and `getlist` of the `request.args`
Add additional example for showing the usage of `getlist` and fix the documentation string for `request.args` behavior (`#1704 <https://github.com/huge-success/sanic/issues/1704>`__)
Add additional example for showing the usage of `getlist` and fix the documentation string for `request.args` behavior (`#1704 <https://github.com/sanic-org/sanic/issues/1704>`__)
Version 19.6.3
@ -459,7 +497,7 @@ Features
- Enable Towncrier Support
As part of this feature, `towncrier` is being introduced as a mechanism to partially automate the process
of generating and managing change logs as part of each of pull requests. (`#1631 <https://github.com/huge-success/sanic/issues/1631>`__)
of generating and managing change logs as part of each of pull requests. (`#1631 <https://github.com/sanic-org/sanic/issues/1631>`__)
Improved Documentation
@ -470,7 +508,7 @@ Improved Documentation
- Enable having a single common `CHANGELOG` file for both GitHub page and documentation
- Fix Sphinix deprecation warnings
- Fix documentation warnings due to invalid `rst` indentation
- Enable common contribution guidelines file across GitHub and documentation via `CONTRIBUTING.rst` (`#1631 <https://github.com/huge-success/sanic/issues/1631>`__)
- Enable common contribution guidelines file across GitHub and documentation via `CONTRIBUTING.rst` (`#1631 <https://github.com/sanic-org/sanic/issues/1631>`__)
Version 19.6.2
@ -480,16 +518,16 @@ Features
********
*
`#1562 <https://github.com/huge-success/sanic/pull/1562>`_
`#1562 <https://github.com/sanic-org/sanic/pull/1562>`_
Remove ``aiohttp`` dependency and create new ``SanicTestClient`` based upon
`requests-async <https://github.com/encode/requests-async>`_
*
`#1475 <https://github.com/huge-success/sanic/pull/1475>`_
`#1475 <https://github.com/sanic-org/sanic/pull/1475>`_
Added ASGI support (Beta)
*
`#1436 <https://github.com/huge-success/sanic/pull/1436>`_
`#1436 <https://github.com/sanic-org/sanic/pull/1436>`_
Add Configure support from object string
@ -497,34 +535,34 @@ Bugfixes
********
*
`#1587 <https://github.com/huge-success/sanic/pull/1587>`_
`#1587 <https://github.com/sanic-org/sanic/pull/1587>`_
Add missing handle for Expect header.
*
`#1560 <https://github.com/huge-success/sanic/pull/1560>`_
`#1560 <https://github.com/sanic-org/sanic/pull/1560>`_
Allow to disable Transfer-Encoding: chunked.
*
`#1558 <https://github.com/huge-success/sanic/pull/1558>`_
`#1558 <https://github.com/sanic-org/sanic/pull/1558>`_
Fix graceful shutdown.
*
`#1594 <https://github.com/huge-success/sanic/pull/1594>`_
`#1594 <https://github.com/sanic-org/sanic/pull/1594>`_
Strict Slashes behavior fix
Deprecations and Removals
*************************
*
`#1544 <https://github.com/huge-success/sanic/pull/1544>`_
`#1544 <https://github.com/sanic-org/sanic/pull/1544>`_
Drop dependency on distutil
*
`#1562 <https://github.com/huge-success/sanic/pull/1562>`_
`#1562 <https://github.com/sanic-org/sanic/pull/1562>`_
Drop support for Python 3.5
*
`#1568 <https://github.com/huge-success/sanic/pull/1568>`_
`#1568 <https://github.com/sanic-org/sanic/pull/1568>`_
Deprecate route removal.
.. warning::
@ -541,39 +579,39 @@ Features
********
*
`#1497 <https://github.com/huge-success/sanic/pull/1497>`_
`#1497 <https://github.com/sanic-org/sanic/pull/1497>`_
Add support for zero-length and RFC 5987 encoded filename for
multipart/form-data requests.
*
`#1484 <https://github.com/huge-success/sanic/pull/1484>`_
`#1484 <https://github.com/sanic-org/sanic/pull/1484>`_
The type of ``expires`` attribute of ``sanic.cookies.Cookie`` is now
enforced to be of type ``datetime``.
*
`#1482 <https://github.com/huge-success/sanic/pull/1482>`_
`#1482 <https://github.com/sanic-org/sanic/pull/1482>`_
Add support for the ``stream`` parameter of ``sanic.Sanic.add_route()``
available to ``sanic.Blueprint.add_route()``.
*
`#1481 <https://github.com/huge-success/sanic/pull/1481>`_
`#1481 <https://github.com/sanic-org/sanic/pull/1481>`_
Accept negative values for route parameters with type ``int`` or ``number``.
*
`#1476 <https://github.com/huge-success/sanic/pull/1476>`_
`#1476 <https://github.com/sanic-org/sanic/pull/1476>`_
Deprecated the use of ``sanic.request.Request.raw_args`` - it has a
fundamental flaw in which is drops repeated query string parameters.
Added ``sanic.request.Request.query_args`` as a replacement for the
original use-case.
*
`#1472 <https://github.com/huge-success/sanic/pull/1472>`_
`#1472 <https://github.com/sanic-org/sanic/pull/1472>`_
Remove an unwanted ``None`` check in Request class ``repr`` implementation.
This changes the default ``repr`` of a Request from ``<Request>`` to
``<Request: None />``
*
`#1470 <https://github.com/huge-success/sanic/pull/1470>`_
`#1470 <https://github.com/sanic-org/sanic/pull/1470>`_
Added 2 new parameters to ``sanic.app.Sanic.create_server``\ :
@ -584,21 +622,21 @@ Features
This is a breaking change.
*
`#1499 <https://github.com/huge-success/sanic/pull/1499>`_
`#1499 <https://github.com/sanic-org/sanic/pull/1499>`_
Added a set of test cases that test and benchmark route resolution.
*
`#1457 <https://github.com/huge-success/sanic/pull/1457>`_
`#1457 <https://github.com/sanic-org/sanic/pull/1457>`_
The type of the ``"max-age"`` value in a ``sanic.cookies.Cookie`` is now
enforced to be an integer. Non-integer values are replaced with ``0``.
*
`#1445 <https://github.com/huge-success/sanic/pull/1445>`_
`#1445 <https://github.com/sanic-org/sanic/pull/1445>`_
Added the ``endpoint`` attribute to an incoming ``request``\ , containing the
name of the handler function.
*
`#1423 <https://github.com/huge-success/sanic/pull/1423>`_
`#1423 <https://github.com/sanic-org/sanic/pull/1423>`_
Improved request streaming. ``request.stream`` is now a bounded-size buffer
instead of an unbounded queue. Callers must now call
``await request.stream.read()`` instead of ``await request.stream.get()``
@ -611,33 +649,33 @@ Bugfixes
*
`#1502 <https://github.com/huge-success/sanic/pull/1502>`_
`#1502 <https://github.com/sanic-org/sanic/pull/1502>`_
Sanic was prefetching ``time.time()`` and updating it once per second to
avoid excessive ``time.time()`` calls. The implementation was observed to
cause memory leaks in some cases. The benefit of the prefetch appeared
to negligible, so this has been removed. Fixes
`#1500 <https://github.com/huge-success/sanic/pull/1500>`_
`#1500 <https://github.com/sanic-org/sanic/pull/1500>`_
*
`#1501 <https://github.com/huge-success/sanic/pull/1501>`_
`#1501 <https://github.com/sanic-org/sanic/pull/1501>`_
Fix a bug in the auto-reloader when the process was launched as a module
i.e. ``python -m init0.mod1`` where the sanic server is started
in ``init0/mod1.py`` with ``debug`` enabled and imports another module in
``init0``.
*
`#1376 <https://github.com/huge-success/sanic/pull/1376>`_
`#1376 <https://github.com/sanic-org/sanic/pull/1376>`_
Allow sanic test client to bind to a random port by specifying
``port=None`` when constructing a ``SanicTestClient``
*
`#1399 <https://github.com/huge-success/sanic/pull/1399>`_
`#1399 <https://github.com/sanic-org/sanic/pull/1399>`_
Added the ability to specify middleware on a blueprint group, so that all
routes produced from the blueprints in the group have the middleware
applied.
*
`#1442 <https://github.com/huge-success/sanic/pull/1442>`_
`#1442 <https://github.com/sanic-org/sanic/pull/1442>`_
Allow the the use the ``SANIC_ACCESS_LOG`` environment variable to
enable/disable the access log when not explicitly passed to ``app.run()``.
This allows the access log to be disabled for example when running via
@ -646,29 +684,29 @@ Bugfixes
Developer infrastructure
************************
* `#1529 <https://github.com/huge-success/sanic/pull/1529>`_ Update project PyPI credentials
* `#1515 <https://github.com/huge-success/sanic/pull/1515>`_ fix linter issue causing travis build failures (fix #1514)
* `#1490 <https://github.com/huge-success/sanic/pull/1490>`_ Fix python version in doc build
* `#1478 <https://github.com/huge-success/sanic/pull/1478>`_ Upgrade setuptools version and use native docutils in doc build
* `#1464 <https://github.com/huge-success/sanic/pull/1464>`_ Upgrade pytest, and fix caplog unit tests
* `#1529 <https://github.com/sanic-org/sanic/pull/1529>`_ Update project PyPI credentials
* `#1515 <https://github.com/sanic-org/sanic/pull/1515>`_ fix linter issue causing travis build failures (fix #1514)
* `#1490 <https://github.com/sanic-org/sanic/pull/1490>`_ Fix python version in doc build
* `#1478 <https://github.com/sanic-org/sanic/pull/1478>`_ Upgrade setuptools version and use native docutils in doc build
* `#1464 <https://github.com/sanic-org/sanic/pull/1464>`_ Upgrade pytest, and fix caplog unit tests
Improved Documentation
**********************
* `#1516 <https://github.com/huge-success/sanic/pull/1516>`_ Fix typo at the exception documentation
* `#1510 <https://github.com/huge-success/sanic/pull/1510>`_ fix typo in Asyncio example
* `#1486 <https://github.com/huge-success/sanic/pull/1486>`_ Documentation typo
* `#1477 <https://github.com/huge-success/sanic/pull/1477>`_ Fix grammar in README.md
* `#1489 <https://github.com/huge-success/sanic/pull/1489>`_ Added "databases" to the extensions list
* `#1483 <https://github.com/huge-success/sanic/pull/1483>`_ Add sanic-zipkin to extensions list
* `#1487 <https://github.com/huge-success/sanic/pull/1487>`_ Removed link to deleted repo, Sanic-OAuth, from the extensions list
* `#1460 <https://github.com/huge-success/sanic/pull/1460>`_ 18.12 changelog
* `#1449 <https://github.com/huge-success/sanic/pull/1449>`_ Add example of amending request object
* `#1446 <https://github.com/huge-success/sanic/pull/1446>`_ Update README
* `#1444 <https://github.com/huge-success/sanic/pull/1444>`_ Update README
* `#1443 <https://github.com/huge-success/sanic/pull/1443>`_ Update README, including new logo
* `#1440 <https://github.com/huge-success/sanic/pull/1440>`_ fix minor type and pip install instruction mismatch
* `#1424 <https://github.com/huge-success/sanic/pull/1424>`_ Documentation Enhancements
* `#1516 <https://github.com/sanic-org/sanic/pull/1516>`_ Fix typo at the exception documentation
* `#1510 <https://github.com/sanic-org/sanic/pull/1510>`_ fix typo in Asyncio example
* `#1486 <https://github.com/sanic-org/sanic/pull/1486>`_ Documentation typo
* `#1477 <https://github.com/sanic-org/sanic/pull/1477>`_ Fix grammar in README.md
* `#1489 <https://github.com/sanic-org/sanic/pull/1489>`_ Added "databases" to the extensions list
* `#1483 <https://github.com/sanic-org/sanic/pull/1483>`_ Add sanic-zipkin to extensions list
* `#1487 <https://github.com/sanic-org/sanic/pull/1487>`_ Removed link to deleted repo, Sanic-OAuth, from the extensions list
* `#1460 <https://github.com/sanic-org/sanic/pull/1460>`_ 18.12 changelog
* `#1449 <https://github.com/sanic-org/sanic/pull/1449>`_ Add example of amending request object
* `#1446 <https://github.com/sanic-org/sanic/pull/1446>`_ Update README
* `#1444 <https://github.com/sanic-org/sanic/pull/1444>`_ Update README
* `#1443 <https://github.com/sanic-org/sanic/pull/1443>`_ Update README, including new logo
* `#1440 <https://github.com/sanic-org/sanic/pull/1440>`_ fix minor type and pip install instruction mismatch
* `#1424 <https://github.com/sanic-org/sanic/pull/1424>`_ Documentation Enhancements
Note: 19.3.0 was skipped for packagement purposes and not released on PyPI
@ -725,7 +763,7 @@ Version 0.8
* Changes:
* Ownership changed to org 'huge-success'
* Ownership changed to org 'sanic-org'
0.8.0
*****

View File

@ -61,7 +61,6 @@ from sanic.server import (
serve_multiple,
trigger_events,
)
from sanic.static import register as static_register
from sanic.websocket import ConnectionClosed, WebSocketProtocol
@ -282,7 +281,7 @@ class Sanic(BaseSanic):
return self.router.add(**params)
def _apply_static(self, static: FutureStatic) -> Route:
return static_register(self, static)
return self._register_static(static)
def _apply_middleware(
self,

View File

@ -34,7 +34,7 @@ class Header(CIMultiDict):
use_trio = argv[0].endswith("hypercorn") and "trio" in argv
if use_trio:
if use_trio: # pragma: no cover
import trio # type: ignore
def stat_async(path):

View File

@ -8,7 +8,7 @@ class ExceptionMixin:
self._future_exceptions: Set[FutureException] = set()
def _apply_exception_handler(self, handler: FutureException):
raise NotImplementedError
raise NotImplementedError # noqa
def exception(self, *exceptions, apply=True):
"""

View File

@ -20,7 +20,7 @@ class ListenerMixin:
self._future_listeners: List[FutureListener] = list()
def _apply_listener(self, listener: FutureListener):
raise NotImplementedError
raise NotImplementedError # noqa
def listener(
self,

View File

@ -9,7 +9,7 @@ class MiddlewareMixin:
self._future_middleware: List[FutureMiddleware] = list()
def _apply_middleware(self, middleware: FutureMiddleware):
raise NotImplementedError
raise NotImplementedError # noqa
def middleware(
self, middleware_or_request, attach_to="request", apply=True
@ -45,8 +45,14 @@ class MiddlewareMixin:
register_middleware, attach_to=middleware_or_request
)
def on_request(self, middleware):
return self.middleware(middleware, "request")
def on_request(self, middleware=None):
if callable(middleware):
return self.middleware(middleware, "request")
else:
return partial(self.middleware, attach_to="request")
def on_response(self, middleware):
return self.middleware(middleware, "response")
def on_response(self, middleware=None):
if callable(middleware):
return self.middleware(middleware, "response")
else:
return partial(self.middleware, attach_to="response")

View File

@ -1,11 +1,27 @@
from functools import partial, wraps
from inspect import signature
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from re import sub
from time import gmtime, strftime
from typing import Iterable, List, Optional, Set, Union
from urllib.parse import unquote
from sanic_routing.route import Route # type: ignore
from sanic.compat import stat_async
from sanic.constants import HTTP_METHODS
from sanic.exceptions import (
ContentRangeError,
FileNotFound,
HeaderNotFound,
InvalidUsage,
)
from sanic.handlers import ContentRangeHandler
from sanic.log import error_logger
from sanic.models.futures import FutureRoute, FutureStatic
from sanic.response import HTTPResponse, file, file_stream
from sanic.views import CompositionView
@ -17,10 +33,10 @@ class RouteMixin:
self.strict_slashes = False
def _apply_route(self, route: FutureRoute) -> Route:
raise NotImplementedError
raise NotImplementedError # noqa
def _apply_static(self, static: FutureStatic) -> Route:
raise NotImplementedError
raise NotImplementedError # noqa
def route(
self,
@ -595,10 +611,191 @@ class RouteMixin:
else:
break
if not name:
raise Exception("...")
if not name: # noq
raise ValueError("Could not generate a name for handler")
if not name.startswith(f"{self.name}."):
name = f"{self.name}.{name}"
return name
async def _static_request_handler(
self,
file_or_directory,
use_modified_since,
use_content_range,
stream_large_files,
request,
content_type=None,
file_uri=None,
):
# Using this to determine if the URL is trying to break out of the path
# served. os.path.realpath seems to be very slow
if file_uri and "../" in file_uri:
raise InvalidUsage("Invalid URL")
# Merge served directory and requested file if provided
# Strip all / that in the beginning of the URL to help prevent python
# from herping a derp and treating the uri as an absolute path
root_path = file_path = file_or_directory
if file_uri:
file_path = path.join(
file_or_directory, sub("^[/]*", "", file_uri)
)
# URL decode the path sent by the browser otherwise we won't be able to
# match filenames which got encoded (filenames with spaces etc)
file_path = path.abspath(unquote(file_path))
if not file_path.startswith(path.abspath(unquote(root_path))):
error_logger.exception(
f"File not found: path={file_or_directory}, "
f"relative_url={file_uri}"
)
raise FileNotFound(
"File not found", path=file_or_directory, relative_url=file_uri
)
try:
headers = {}
# Check if the client has been sent this file before
# and it has not been modified since
stats = None
if use_modified_since:
stats = await stat_async(file_path)
modified_since = strftime(
"%a, %d %b %Y %H:%M:%S GMT", gmtime(stats.st_mtime)
)
if request.headers.get("If-Modified-Since") == modified_since:
return HTTPResponse(status=304)
headers["Last-Modified"] = modified_since
_range = None
if use_content_range:
_range = None
if not stats:
stats = await stat_async(file_path)
headers["Accept-Ranges"] = "bytes"
headers["Content-Length"] = str(stats.st_size)
if request.method != "HEAD":
try:
_range = ContentRangeHandler(request, stats)
except HeaderNotFound:
pass
else:
del headers["Content-Length"]
for key, value in _range.headers.items():
headers[key] = value
if "content-type" not in headers:
content_type = (
content_type
or guess_type(file_path)[0]
or "application/octet-stream"
)
if "charset=" not in content_type and (
content_type.startswith("text/")
or content_type == "application/javascript"
):
content_type += "; charset=utf-8"
headers["Content-Type"] = content_type
if request.method == "HEAD":
return HTTPResponse(headers=headers)
else:
if stream_large_files:
if type(stream_large_files) == int:
threshold = stream_large_files
else:
threshold = 1024 * 1024
if not stats:
stats = await stat_async(file_path)
if stats.st_size >= threshold:
return await file_stream(
file_path, headers=headers, _range=_range
)
return await file(file_path, headers=headers, _range=_range)
except ContentRangeError:
raise
except Exception:
error_logger.exception(
f"File not found: path={file_or_directory}, "
f"relative_url={file_uri}"
)
raise FileNotFound(
"File not found", path=file_or_directory, relative_url=file_uri
)
def _register_static(
self,
static: FutureStatic,
):
# TODO: Though sanic is not a file server, I feel like we should
# at least make a good effort here. Modified-since is nice, but
# we could also look into etags, expires, and caching
"""
Register a static directory handler with Sanic by adding a route to the
router and registering a handler.
:param app: Sanic
:param file_or_directory: File or directory path to serve from
:type file_or_directory: Union[str,bytes,Path]
:param uri: URL to serve from
:type uri: str
:param pattern: regular expression used to match files in the URL
:param use_modified_since: If true, send file modified time, and return
not modified if the browser's matches the
server's
:param use_content_range: If true, process header for range requests
and sends the file part that is requested
:param stream_large_files: If true, use the file_stream() handler
rather than the file() handler to send the file
If this is an integer, this represents the
threshold size to switch to file_stream()
:param name: user defined name used for url_for
:type name: str
:param content_type: user defined content type for header
:return: registered static routes
:rtype: List[sanic.router.Route]
"""
if isinstance(static.file_or_directory, bytes):
file_or_directory = static.file_or_directory.decode("utf-8")
elif isinstance(static.file_or_directory, PurePath):
file_or_directory = str(static.file_or_directory)
elif not isinstance(static.file_or_directory, str):
raise ValueError("Invalid file path string.")
else:
file_or_directory = static.file_or_directory
uri = static.uri
name = static.name
# If we're not trying to match a file directly,
# serve from the folder
if not path.isfile(file_or_directory):
uri += "/<file_uri>"
# special prefix for static files
# if not static.name.startswith("_static_"):
# name = f"_static_{static.name}"
_handler = wraps(self._static_request_handler)(
partial(
self._static_request_handler,
file_or_directory,
static.use_modified_since,
static.use_content_range,
static.stream_large_files,
content_type=static.content_type,
)
)
route, _ = self.route(
uri=uri,
methods=["GET", "HEAD"],
name=name,
host=static.host,
strict_slashes=static.strict_slashes,
static=True,
)(_handler)
return route

View File

@ -1,186 +0,0 @@
from functools import partial, wraps
from mimetypes import guess_type
from os import path
from pathlib import PurePath
from re import sub
from time import gmtime, strftime
from urllib.parse import unquote
from sanic.compat import stat_async
from sanic.exceptions import (
ContentRangeError,
FileNotFound,
HeaderNotFound,
InvalidUsage,
)
from sanic.handlers import ContentRangeHandler
from sanic.log import error_logger
from sanic.models.futures import FutureStatic
from sanic.response import HTTPResponse, file, file_stream
async def _static_request_handler(
file_or_directory,
use_modified_since,
use_content_range,
stream_large_files,
request,
content_type=None,
file_uri=None,
):
# Using this to determine if the URL is trying to break out of the path
# served. os.path.realpath seems to be very slow
if file_uri and "../" in file_uri:
raise InvalidUsage("Invalid URL")
# Merge served directory and requested file if provided
# Strip all / that in the beginning of the URL to help prevent python
# from herping a derp and treating the uri as an absolute path
root_path = file_path = file_or_directory
if file_uri:
file_path = path.join(file_or_directory, sub("^[/]*", "", file_uri))
# URL decode the path sent by the browser otherwise we won't be able to
# match filenames which got encoded (filenames with spaces etc)
file_path = path.abspath(unquote(file_path))
if not file_path.startswith(path.abspath(unquote(root_path))):
error_logger.exception(
f"File not found: path={file_or_directory}, "
f"relative_url={file_uri}"
)
raise FileNotFound(
"File not found", path=file_or_directory, relative_url=file_uri
)
try:
headers = {}
# Check if the client has been sent this file before
# and it has not been modified since
stats = None
if use_modified_since:
stats = await stat_async(file_path)
modified_since = strftime(
"%a, %d %b %Y %H:%M:%S GMT", gmtime(stats.st_mtime)
)
if request.headers.get("If-Modified-Since") == modified_since:
return HTTPResponse(status=304)
headers["Last-Modified"] = modified_since
_range = None
if use_content_range:
_range = None
if not stats:
stats = await stat_async(file_path)
headers["Accept-Ranges"] = "bytes"
headers["Content-Length"] = str(stats.st_size)
if request.method != "HEAD":
try:
_range = ContentRangeHandler(request, stats)
except HeaderNotFound:
pass
else:
del headers["Content-Length"]
for key, value in _range.headers.items():
headers[key] = value
headers["Content-Type"] = (
content_type or guess_type(file_path)[0] or "text/plain"
)
if request.method == "HEAD":
return HTTPResponse(headers=headers)
else:
if stream_large_files:
if type(stream_large_files) == int:
threshold = stream_large_files
else:
threshold = 1024 * 1024
if not stats:
stats = await stat_async(file_path)
if stats.st_size >= threshold:
return await file_stream(
file_path, headers=headers, _range=_range
)
return await file(file_path, headers=headers, _range=_range)
except ContentRangeError:
raise
except Exception:
error_logger.exception(
f"File not found: path={file_or_directory}, "
f"relative_url={file_uri}"
)
raise FileNotFound(
"File not found", path=file_or_directory, relative_url=file_uri
)
def register(
app,
static: FutureStatic,
):
# TODO: Though sanic is not a file server, I feel like we should at least
# make a good effort here. Modified-since is nice, but we could
# also look into etags, expires, and caching
"""
Register a static directory handler with Sanic by adding a route to the
router and registering a handler.
:param app: Sanic
:param file_or_directory: File or directory path to serve from
:type file_or_directory: Union[str,bytes,Path]
:param uri: URL to serve from
:type uri: str
:param pattern: regular expression used to match files in the URL
:param use_modified_since: If true, send file modified time, and return
not modified if the browser's matches the
server's
:param use_content_range: If true, process header for range requests
and sends the file part that is requested
:param stream_large_files: If true, use the file_stream() handler rather
than the file() handler to send the file
If this is an integer, this represents the
threshold size to switch to file_stream()
:param name: user defined name used for url_for
:type name: str
:param content_type: user defined content type for header
:return: registered static routes
:rtype: List[sanic.router.Route]
"""
if isinstance(static.file_or_directory, bytes):
file_or_directory = static.file_or_directory.decode("utf-8")
elif isinstance(static.file_or_directory, PurePath):
file_or_directory = str(static.file_or_directory)
elif not isinstance(static.file_or_directory, str):
raise ValueError("Invalid file path string.")
else:
file_or_directory = static.file_or_directory
uri = static.uri
name = static.name
# If we're not trying to match a file directly,
# serve from the folder
if not path.isfile(file_or_directory):
uri += "/<file_uri>"
# special prefix for static files
# if not static.name.startswith("_static_"):
# name = f"_static_{static.name}"
_handler = wraps(_static_request_handler)(
partial(
_static_request_handler,
file_or_directory,
static.use_modified_since,
static.use_content_range,
static.stream_large_files,
content_type=static.content_type,
)
)
route, _ = app.route(
uri=uri,
methods=["GET", "HEAD"],
name=name,
host=static.host,
strict_slashes=static.strict_slashes,
static=True,
)(_handler)
return route

View File

@ -44,7 +44,7 @@ def str_to_bool(val: str) -> bool:
def load_module_from_file_location(
location: Union[bytes, str, Path], encoding: str = "utf8", *args, **kwargs
):
): # noqa
"""Returns loaded module provided as a file path.
:param args:

View File

@ -57,7 +57,8 @@ setup_kwargs = {
"author": "Sanic Community",
"author_email": "admhpkns@gmail.com",
"description": (
"A web server and web framework that's written to go fast. Build fast. Run fast."
"A web server and web framework that's written to go fast. "
"Build fast. Run fast."
),
"long_description": long_description,
"packages": ["sanic"],
@ -80,7 +81,7 @@ env_dependency = (
'; sys_platform != "win32" ' 'and implementation_name == "cpython"'
)
ujson = "ujson>=1.35" + env_dependency
uvloop = "uvloop>=0.5.3" + env_dependency
uvloop = "uvloop>=0.5.3,<0.15.0" + env_dependency
requirements = [
"sanic-routing",

View File

@ -110,6 +110,11 @@ def test_bp_group(app: Sanic):
global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["request"] += 1
@blueprint_group_1.middleware
def blueprint_group_1_middleware_not_called(request):
global MIDDLEWARE_INVOKE_COUNTER
MIDDLEWARE_INVOKE_COUNTER["request"] += 1
@blueprint_3.route("/")
def blueprint_3_default_route(request):
return text("BP3_OK")
@ -142,7 +147,7 @@ def test_bp_group(app: Sanic):
assert response.text == "BP3_OK"
assert MIDDLEWARE_INVOKE_COUNTER["response"] == 3
assert MIDDLEWARE_INVOKE_COUNTER["request"] == 2
assert MIDDLEWARE_INVOKE_COUNTER["request"] == 4
def test_bp_group_list_operations(app: Sanic):
@ -179,3 +184,19 @@ def test_bp_group_list_operations(app: Sanic):
assert len(blueprint_group_1) == 2
assert blueprint_group_1.url_prefix == "/bp"
def test_bp_group_as_list():
blueprint_1 = Blueprint("blueprint_1", url_prefix="/bp1")
blueprint_2 = Blueprint("blueprint_2", url_prefix="/bp2")
blueprint_group_1 = Blueprint.group([blueprint_1, blueprint_2])
assert len(blueprint_group_1) == 2
def test_bp_group_as_nested_group():
blueprint_1 = Blueprint("blueprint_1", url_prefix="/bp1")
blueprint_2 = Blueprint("blueprint_2", url_prefix="/bp2")
blueprint_group_1 = Blueprint.group(
Blueprint.group(blueprint_1, blueprint_2)
)
assert len(blueprint_group_1) == 2

View File

@ -30,6 +30,23 @@ def test_middleware_request(app):
assert type(results[0]) is Request
def test_middleware_request_as_convenience(app):
results = []
@app.on_request
async def handler1(request):
results.append(request)
@app.route("/")
async def handler2(request):
return text("OK")
request, response = app.test_client.get("/")
assert response.text == "OK"
assert type(results[0]) is Request
def test_middleware_response(app):
results = []
@ -54,6 +71,54 @@ def test_middleware_response(app):
assert isinstance(results[2], HTTPResponse)
def test_middleware_response_as_convenience(app):
results = []
@app.on_request
async def process_request(request):
results.append(request)
@app.on_response
async def process_response(request, response):
results.append(request)
results.append(response)
@app.route("/")
async def handler(request):
return text("OK")
request, response = app.test_client.get("/")
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_as_convenience_called(app):
results = []
@app.on_request()
async def process_request(request):
results.append(request)
@app.on_response()
async def process_response(request, response):
results.append(request)
results.append(response)
@app.route("/")
async def handler(request):
return text("OK")
request, response = app.test_client.get("/")
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": "middleware not run"}

View File

@ -633,6 +633,19 @@ def test_websocket_route(app, url):
assert ev.is_set()
def test_websocket_route_invalid_handler(app):
with pytest.raises(ValueError) as e:
@app.websocket("/")
async def handler():
...
assert e.match(
r"Required parameter `request` and/or `ws` missing in the "
r"handler\(\) route\?"
)
@pytest.mark.asyncio
@pytest.mark.parametrize("url", ["/ws", "ws"])
async def test_websocket_route_asgi(app, url):

View File

@ -8,6 +8,8 @@ import pytest
from sanic_testing.testing import HOST, PORT
from sanic.exceptions import InvalidUsage
AVAILABLE_LISTENERS = [
"before_server_start",
@ -80,6 +82,18 @@ def test_all_listeners(app):
assert app.name + listener_name == output.pop()
@skipif_no_alarm
def test_all_listeners_as_convenience(app):
output = []
for listener_name in AVAILABLE_LISTENERS:
listener = create_listener(listener_name, output)
method = getattr(app, listener_name)
method(listener)
start_stop_app(app)
for listener_name in AVAILABLE_LISTENERS:
assert app.name + listener_name == output.pop()
@pytest.mark.asyncio
async def test_trigger_before_events_create_server(app):
class MySanicDb:
@ -95,6 +109,20 @@ async def test_trigger_before_events_create_server(app):
assert isinstance(app.db, MySanicDb)
@pytest.mark.asyncio
async def test_trigger_before_events_create_server_missing_event(app):
class MySanicDb:
pass
with pytest.raises(InvalidUsage):
@app.listener
async def init_db(app, loop):
app.db = MySanicDb()
assert not hasattr(app, "db")
def test_create_server_trigger_events(app):
"""Test if create_server can trigger server events"""

View File

@ -127,6 +127,40 @@ def test_static_file_content_type(app, static_file_directory, file_name):
assert response.headers["Content-Type"] == "text/html; charset=utf-8"
@pytest.mark.parametrize(
"file_name,expected",
[
("test.html", "text/html; charset=utf-8"),
("decode me.txt", "text/plain; charset=utf-8"),
("test.file", "application/octet-stream"),
],
)
def test_static_file_content_type_guessed(
app, static_file_directory, file_name, expected
):
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)
assert response.headers["Content-Type"] == expected
def test_static_file_content_type_with_charset(app, static_file_directory):
app.static(
"/testing.file",
get_file_path(static_file_directory, "decode me.txt"),
content_type="text/plain;charset=ISO-8859-1",
)
request, response = app.test_client.get("/testing.file")
assert response.status == 200
assert response.headers["Content-Type"] == "text/plain;charset=ISO-8859-1"
@pytest.mark.parametrize(
"file_name", ["test.file", "decode me.txt", "symlink", "hard_link"]
)