From c5efc4b64b417b758911fed1b44b43a64fad821a Mon Sep 17 00:00:00 2001 From: Mike Yusko Date: Sun, 12 May 2019 15:32:34 +0300 Subject: [PATCH 01/19] Added documentation for missed arguments --- sanic/app.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sanic/app.py b/sanic/app.py index ce8770bd..fdc473cc 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -441,8 +441,12 @@ class Sanic: ): """Decorate a function to be registered as a websocket route :param uri: path of the URL + :param host: Host IP or FQDN details + :param strict_slashes: If the API endpoint needs to terminate + with a "/" or not :param subprotocols: optional list of str with supported subprotocols - :param host: + :param name: A unique name assigned to the URL so that it can + be used with :func:`url_for` :return: decorated function """ self.enable_websocket() From 4c8cc84b64633ab9556ddefc25c3b61efc1b499b Mon Sep 17 00:00:00 2001 From: Mike Yusko Date: Sun, 12 May 2019 15:36:13 +0300 Subject: [PATCH 02/19] Delete unnecessary whitespace --- sanic/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/app.py b/sanic/app.py index fdc473cc..5fa7b872 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -445,7 +445,7 @@ class Sanic: :param strict_slashes: If the API endpoint needs to terminate with a "/" or not :param subprotocols: optional list of str with supported subprotocols - :param name: A unique name assigned to the URL so that it can + :param name: A unique name assigned to the URL so that it can be used with :func:`url_for` :return: decorated function """ From 601e158ffe99fd3dae06a3f0c408bbd937348173 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Tue, 14 May 2019 10:50:34 +0300 Subject: [PATCH 03/19] Add stale to repo --- .github/stale.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..bf9b0fb3 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 90 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 30 +# Issues with these labels will never be considered stale +exemptLabels: + - bug + - urgent +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. If this + is incorrect, please respond with an update. Thank you for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false \ No newline at end of file From 193dbe89cd31aefcbff7f9b4fd06c722d64371a4 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Tue, 14 May 2019 11:21:24 +0300 Subject: [PATCH 04/19] Remove Python 3.5 references in docs --- docs/sanic/getting_started.md | 2 +- docs/sanic/index.rst | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/sanic/getting_started.md b/docs/sanic/getting_started.md index 0c05389d..babafc65 100644 --- a/docs/sanic/getting_started.md +++ b/docs/sanic/getting_started.md @@ -1,7 +1,7 @@ # Getting Started Make sure you have both [pip](https://pip.pypa.io/en/stable/installing/) and at -least version 3.5 of Python before starting. Sanic uses the new `async`/`await` +least version 3.6 of Python before starting. Sanic uses the new `async`/`await` syntax, so earlier versions of python won't work. ## 1. Install Sanic diff --git a/docs/sanic/index.rst b/docs/sanic/index.rst index 08797e9f..a76f5884 100644 --- a/docs/sanic/index.rst +++ b/docs/sanic/index.rst @@ -1,9 +1,9 @@ Sanic ================================= -Sanic is a Flask-like Python 3.5+ web server that's written to go fast. It's based on the work done by the amazing folks at magicstack, and was inspired by `this article `_. +Sanic is a Python 3.6+ 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. -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. +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. Sanic is developed `on GitHub `_. Contributions are welcome! @@ -22,4 +22,8 @@ Sanic aspires to be simple return json({"hello": "world"}) if __name__ == "__main__": - app.run(host="0.0.0.0", port=8000) \ No newline at end of file + app.run(host="0.0.0.0", port=8000) + +.. note:: + + Sanic does not support Python 3.5 from version 19.6 and forward. However, version 18.12LTS is supported thru December 2020. Official Python support for version 3.5 is set to expire in September 2020. \ No newline at end of file From 262048df9599c9aff8ee8d8ad677fb0b41861c31 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Wed, 15 May 2019 07:46:58 +0300 Subject: [PATCH 05/19] Update stale.yml --- .github/stale.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index bf9b0fb3..8055777d 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -6,6 +6,7 @@ daysUntilClose: 30 exemptLabels: - bug - urgent + - necessary # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable @@ -14,4 +15,4 @@ markComment: > recent activity. It will be closed if no further activity occurs. If this is incorrect, please respond with an update. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false From bb800c9db852cbdcb48e3ff4c309669cddd504f6 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Wed, 15 May 2019 09:54:02 +0300 Subject: [PATCH 06/19] Add conda install and download stats --- README.rst | 5 ++++- docs/sanic/getting_started.md | 13 ++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index d98e8736..334704b7 100644 --- a/README.rst +++ b/README.rst @@ -18,7 +18,7 @@ Sanic | Build fast. Run fast. * - Support - | |Forums| |Join the chat at https://gitter.im/sanic-python/Lobby| |Awesome| * - Stats - - | |Downloads| + - | |Downloads| |Conda downloads| .. |Forums| image:: https://img.shields.io/badge/forums-community-ff0068.svg :target: https://community.sanicframework.org/ @@ -50,6 +50,9 @@ Sanic | Build fast. Run fast. .. |Downloads| image:: https://pepy.tech/badge/sanic/month :alt: Downloads :target: https://pepy.tech/project/sanic +.. |Conda downloads| image:: https://img.shields.io/conda/dn/conda-forge/sanic.svg + :alt: Downloads + :target: https://anaconda.org/conda-forge/sanic .. end-badges diff --git a/docs/sanic/getting_started.md b/docs/sanic/getting_started.md index 0c05389d..8c9ec495 100644 --- a/docs/sanic/getting_started.md +++ b/docs/sanic/getting_started.md @@ -6,9 +6,9 @@ syntax, so earlier versions of python won't work. ## 1. Install Sanic - ``` - pip3 install sanic - ``` +```bash +pip3 install sanic +``` To install sanic without `uvloop` or `ujson` using bash, you can provide either or both of these environmental variables using any truthy string like `'y', 'yes', 't', 'true', 'on', '1'` and setting the `SANIC_NO_X` (`X` = `UVLOOP`/`UJSON`) @@ -18,6 +18,13 @@ to true will stop that features installation. SANIC_NO_UVLOOP=true SANIC_NO_UJSON=true pip3 install sanic ``` +You can also install Sanic from [`conda-forge`](https://anaconda.org/conda-forge/sanic) + +```bash +conda config --add channels conda-forge +conda install sanic +``` + ## 2. Create a file called `main.py` ```python From 3661afa4614aac0a2c605a22204159bada0ff65d Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Thu, 16 May 2019 08:56:25 -0700 Subject: [PATCH 07/19] bump request-async version for fixing build time issue --- environment.yml | 2 +- setup.py | 4 ++-- tox.ini | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/environment.yml b/environment.yml index e9b832b4..e42a97ef 100644 --- a/environment.yml +++ b/environment.yml @@ -13,7 +13,7 @@ dependencies: - sphinx==1.8.3 - sphinx_rtd_theme==0.4.2 - recommonmark==0.5.0 - - requests-async==0.4.0 + - requests-async==0.5.0 - sphinxcontrib-asyncio>=0.2.0 - docutils==0.14 - pygments==2.3.1 diff --git a/setup.py b/setup.py index 2cd973b7..861ce013 100644 --- a/setup.py +++ b/setup.py @@ -89,8 +89,8 @@ tests_require = [ "multidict>=4.0,<5.0", "gunicorn", "pytest-cov", - "httpcore==0.1.1", - "requests-async==0.4.0", + "httpcore==0.3.0", + "requests-async==0.5.0", "beautifulsoup4", uvloop, ujson, diff --git a/tox.ini b/tox.ini index c825f0de..616b7acd 100644 --- a/tox.ini +++ b/tox.ini @@ -12,8 +12,8 @@ deps = pytest-cov pytest-sanic pytest-sugar - httpcore==0.1.1 - requests-async==0.4.0 + httpcore==0.3.0 + requests-async==0.5.0 chardet<=2.3.0 beautifulsoup4 gunicorn From 046ca6eaf13545ad52098e26425c4ef267429222 Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Thu, 16 May 2019 22:44:46 -0700 Subject: [PATCH 08/19] fix unit tests due to dependency upgrade --- tests/test_keep_alive_timeout.py | 154 ++++++++----------------------- 1 file changed, 38 insertions(+), 116 deletions(-) diff --git a/tests/test_keep_alive_timeout.py b/tests/test_keep_alive_timeout.py index 1d6de63e..9ebd6cbd 100644 --- a/tests/test_keep_alive_timeout.py +++ b/tests/test_keep_alive_timeout.py @@ -16,45 +16,28 @@ from sanic.response import text from sanic.testing import HOST, PORT, SanicTestClient -# import traceback - - - - - - CONFIG_FOR_TESTS = {"KEEP_ALIVE_TIMEOUT": 2, "KEEP_ALIVE": True} old_conn = None class ReusableSanicConnectionPool(httpcore.ConnectionPool): - async def acquire_connection(self, url, ssl, timeout): + async def acquire_connection(self, origin): global old_conn - if timeout.connect_timeout and not timeout.pool_timeout: - timeout.pool_timeout = timeout.connect_timeout - key = (url.scheme, url.hostname, url.port, ssl, timeout) - try: - connection = self._keepalive_connections[key].pop() - if not self._keepalive_connections[key]: - del self._keepalive_connections[key] - self.num_keepalive_connections -= 1 - self.num_active_connections += 1 + connection = self.active_connections.pop_by_origin(origin, http2_only=True) + if connection is None: + connection = self.keepalive_connections.pop_by_origin(origin) - except (KeyError, IndexError): - ssl_context = await self.get_ssl_context(url, ssl) - try: - await asyncio.wait_for( - self._max_connections.acquire(), timeout.pool_timeout - ) - except asyncio.TimeoutError: - raise PoolTimeout() - release = functools.partial(self.release_connection, key=key) - connection = httpcore.connections.Connection( - timeout=timeout, on_release=release + if connection is None: + await self.max_connections.acquire() + connection = httpcore.HTTPConnection( + origin, + ssl=self.ssl, + timeout=self.timeout, + backend=self.backend, + release_func=self.release_connection, ) - self.num_active_connections += 1 - await connection.open(url.hostname, url.port, ssl=ssl_context) + self.active_connections.add(connection) if old_conn is not None: if old_conn != connection: @@ -70,62 +53,6 @@ class ReusableSanicAdapter(requests.adapters.HTTPAdapter): def __init__(self): self.pool = ReusableSanicConnectionPool() - async def send( - self, - request, - stream=False, - timeout=None, - verify=True, - cert=None, - proxies=None, - ): - - method = request.method - url = request.url - headers = [ - (_encode(k), _encode(v)) for k, v in request.headers.items() - ] - - if not request.body: - body = b"" - elif isinstance(request.body, str): - body = _encode(request.body) - else: - body = request.body - - if isinstance(timeout, tuple): - timeout_kwargs = { - "connect_timeout": timeout[0], - "read_timeout": timeout[1], - } - else: - timeout_kwargs = { - "connect_timeout": timeout, - "read_timeout": timeout, - } - - ssl = httpcore.SSLConfig(cert=cert, verify=verify) - timeout = httpcore.TimeoutConfig(**timeout_kwargs) - - try: - response = await self.pool.request( - method, - url, - headers=headers, - body=body, - stream=stream, - ssl=ssl, - timeout=timeout, - ) - except (httpcore.BadResponse, socket.error) as err: - raise ConnectionError(err, request=request) - except httpcore.ConnectTimeout as err: - raise requests.exceptions.ConnectTimeout(err, request=request) - except httpcore.ReadTimeout as err: - raise requests.exceptions.ReadTimeout(err, request=request) - - return self.build_response(request, response) - class ResusableSanicSession(requests.Session): def __init__(self, *args, **kwargs) -> None: @@ -153,13 +80,14 @@ class ReuseableSanicTestClient(SanicTestClient): uri="/", gather_request=True, debug=False, - server_kwargs={"return_asyncio_server": True}, + server_kwargs=None, *request_args, **request_kwargs, ): loop = self._loop results = [None, None] exceptions = [] + server_kwargs = server_kwargs or {"return_asyncio_server": True} if gather_request: def _collect_request(request): @@ -187,7 +115,6 @@ class ReuseableSanicTestClient(SanicTestClient): ) results[-1] = response except Exception as e2: - # traceback.print_tb(e2.__traceback__) exceptions.append(e2) if self._server is not None: @@ -205,7 +132,6 @@ class ReuseableSanicTestClient(SanicTestClient): loop._stopping = False _server = loop.run_until_complete(_server_co) except Exception as e1: - # traceback.print_tb(e1.__traceback__) raise e1 self._server = _server server.trigger_events(self.app.listeners["after_server_start"], loop) @@ -257,36 +183,32 @@ class ReuseableSanicTestClient(SanicTestClient): request_keepalive = kwargs.pop( "request_keepalive", CONFIG_FOR_TESTS["KEEP_ALIVE_TIMEOUT"] ) - if self._session: - _session = self._session - else: - _session = ResusableSanicSession() - self._session = _session - async with _session as session: - try: - response = await getattr(session, method.lower())( - url, - verify=False, - timeout=request_keepalive, - *args, - **kwargs, - ) - except NameError: - raise Exception(response.status_code) + if not self._session: + self._session = ResusableSanicSession() + try: + response = await getattr(self._session, method.lower())( + url, + verify=False, + timeout=request_keepalive, + *args, + **kwargs, + ) + except NameError: + raise Exception(response.status_code) - try: - response.json = response.json() - except (JSONDecodeError, UnicodeDecodeError): - response.json = None + try: + response.json = response.json() + except (JSONDecodeError, UnicodeDecodeError): + response.json = None - response.body = await response.read() - response.status = response.status_code - response.content_type = response.headers.get("content-type") + response.body = await response.read() + response.status = response.status_code + response.content_type = response.headers.get("content-type") - if raw_cookies: - response.raw_cookies = {} - for cookie in response.cookies: - response.raw_cookies[cookie.name] = cookie + if raw_cookies: + response.raw_cookies = {} + for cookie in response.cookies: + response.raw_cookies[cookie.name] = cookie return response From 2a64dabe82da02136377339b92d7f9de187db746 Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Fri, 17 May 2019 00:22:34 -0700 Subject: [PATCH 09/19] fix request_timeout and request_streaming tests --- tests/test_request_stream.py | 143 +++++++++++++++------------------- tests/test_request_timeout.py | 37 ++++----- 2 files changed, 76 insertions(+), 104 deletions(-) diff --git a/tests/test_request_stream.py b/tests/test_request_stream.py index c1457c8f..d845dc85 100644 --- a/tests/test_request_stream.py +++ b/tests/test_request_stream.py @@ -71,15 +71,13 @@ def test_request_stream_app(app): @app.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) @app.put("/_put") async def _put(request): @@ -89,15 +87,13 @@ def test_request_stream_app(app): @app.put("/put", stream=True) async def put(request): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) @app.patch("/_patch") async def _patch(request): @@ -107,15 +103,14 @@ def test_request_stream_app(app): @app.patch("/patch", stream=True) async def patch(request): assert isinstance(request.stream, StreamBuffer) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) assert app.is_request_stream is True @@ -166,15 +161,13 @@ def test_request_stream_handle_exception(app): @app.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) # 404 request, response = app.test_client.post("/in_valid_post", data=data) @@ -222,15 +215,13 @@ def test_request_stream_blueprint(app): @bp.post("/post/", stream=True) async def post(request, id): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) @bp.put("/_put") async def _put(request): @@ -240,15 +231,13 @@ def test_request_stream_blueprint(app): @bp.put("/put", stream=True) async def put(request): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) @bp.patch("/_patch") async def _patch(request): @@ -258,27 +247,23 @@ def test_request_stream_blueprint(app): @bp.patch("/patch", stream=True) async def patch(request): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) async def post_add_route(request): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) bp.add_route( post_add_route, "/post/add_route", methods=["POST"], stream=True @@ -388,15 +373,13 @@ def test_request_stream(app): @app.post("/stream", stream=True) async def handler(request): assert isinstance(request.stream, StreamBuffer) - - async def streaming(response): - while True: - body = await request.stream.read() - if body is None: - break - await response.write(body.decode("utf-8")) - - return stream(streaming) + result = "" + while True: + body = await request.stream.read() + if body is None: + break + result += body.decode("utf-8") + return text(result) @app.get("/get") async def get(request): diff --git a/tests/test_request_timeout.py b/tests/test_request_timeout.py index e59f2d2f..3a41e462 100644 --- a/tests/test_request_timeout.py +++ b/tests/test_request_timeout.py @@ -13,37 +13,26 @@ class DelayableSanicConnectionPool(httpcore.ConnectionPool): self._request_delay = request_delay super().__init__(*args, **kwargs) - async def request( + async def send( self, - method, - url, - headers=(), - body=b"", + request, stream=False, ssl=None, timeout=None, ): - if ssl is None: - ssl = self.ssl_config - if timeout is None: - timeout = self.timeout - - parsed_url = httpcore.URL(url) - request = httpcore.Request( - method, parsed_url, headers=headers, body=body - ) - connection = await self.acquire_connection( - parsed_url, ssl=ssl, timeout=timeout - ) + connection = await self.acquire_connection(request.url.origin) + if connection.h11_connection is None and connection.h2_connection is None: + await connection.connect(ssl=ssl, timeout=timeout) if self._request_delay: - print(f"\t>> Sleeping ({self._request_delay})") await asyncio.sleep(self._request_delay) - response = await connection.send(request) - if not stream: - try: - await response.read() - finally: - await response.close() + try: + response = await connection.send( + request, stream=stream, ssl=ssl, timeout=timeout + ) + except BaseException as exc: + self.active_connections.remove(connection) + self.max_connections.release() + raise exc return response From a2dbbb25a1dac04215d318f2147adce37f89671d Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Fri, 17 May 2019 00:25:46 -0700 Subject: [PATCH 10/19] add try/finally block for always clean up resources --- tests/test_keep_alive_timeout.py | 106 ++++++++++++++++--------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/tests/test_keep_alive_timeout.py b/tests/test_keep_alive_timeout.py index 9ebd6cbd..c6fc0831 100644 --- a/tests/test_keep_alive_timeout.py +++ b/tests/test_keep_alive_timeout.py @@ -241,42 +241,46 @@ def test_keep_alive_timeout_reuse(): """If the server keep-alive timeout and client keep-alive timeout are both longer than the delay, the client _and_ server will successfully reuse the existing connection.""" - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - client = ReuseableSanicTestClient(keep_alive_timeout_app_reuse, loop) - headers = {"Connection": "keep-alive"} - request, response = client.get("/1", headers=headers) - assert response.status == 200 - assert response.text == "OK" - loop.run_until_complete(aio_sleep(1)) - request, response = client.get("/1") - assert response.status == 200 - assert response.text == "OK" - client.kill_server() + try: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + client = ReuseableSanicTestClient(keep_alive_timeout_app_reuse, loop) + headers = {"Connection": "keep-alive"} + request, response = client.get("/1", headers=headers) + assert response.status == 200 + assert response.text == "OK" + loop.run_until_complete(aio_sleep(1)) + request, response = client.get("/1") + assert response.status == 200 + assert response.text == "OK" + finally: + client.kill_server() def test_keep_alive_client_timeout(): """If the server keep-alive timeout is longer than the client keep-alive timeout, client will try to create a new connection here.""" - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - client = ReuseableSanicTestClient(keep_alive_app_client_timeout, loop) - headers = {"Connection": "keep-alive"} try: - request, response = client.get( - "/1", headers=headers, request_keepalive=1 - ) - assert response.status == 200 - assert response.text == "OK" - loop.run_until_complete(aio_sleep(2)) - exception = None - request, response = client.get("/1", request_keepalive=1) - except ValueError as e: - exception = e - assert exception is not None - assert isinstance(exception, ValueError) - assert "got a new connection" in exception.args[0] - client.kill_server() + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + client = ReuseableSanicTestClient(keep_alive_app_client_timeout, loop) + headers = {"Connection": "keep-alive"} + try: + request, response = client.get( + "/1", headers=headers, request_keepalive=1 + ) + assert response.status == 200 + assert response.text == "OK" + loop.run_until_complete(aio_sleep(2)) + exception = None + request, response = client.get("/1", request_keepalive=1) + except ValueError as e: + exception = e + assert exception is not None + assert isinstance(exception, ValueError) + assert "got a new connection" in exception.args[0] + finally: + client.kill_server() def test_keep_alive_server_timeout(): @@ -284,25 +288,27 @@ def test_keep_alive_server_timeout(): keep-alive timeout, the client will either a 'Connection reset' error _or_ a new connection. Depending on how the event-loop handles the broken server connection.""" - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - client = ReuseableSanicTestClient(keep_alive_app_server_timeout, loop) - headers = {"Connection": "keep-alive"} try: - request, response = client.get( - "/1", headers=headers, request_keepalive=60 + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + client = ReuseableSanicTestClient(keep_alive_app_server_timeout, loop) + headers = {"Connection": "keep-alive"} + try: + request, response = client.get( + "/1", headers=headers, request_keepalive=60 + ) + assert response.status == 200 + assert response.text == "OK" + loop.run_until_complete(aio_sleep(3)) + exception = None + request, response = client.get("/1", request_keepalive=60) + except ValueError as e: + exception = e + assert exception is not None + assert isinstance(exception, ValueError) + assert ( + "Connection reset" in exception.args[0] + or "got a new connection" in exception.args[0] ) - assert response.status == 200 - assert response.text == "OK" - loop.run_until_complete(aio_sleep(3)) - exception = None - request, response = client.get("/1", request_keepalive=60) - except ValueError as e: - exception = e - assert exception is not None - assert isinstance(exception, ValueError) - assert ( - "Connection reset" in exception.args[0] - or "got a new connection" in exception.args[0] - ) - client.kill_server() + finally: + client.kill_server() From 28a897e599b98f094924c917d61b09ec1e61e725 Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Sat, 18 May 2019 11:02:46 -0700 Subject: [PATCH 11/19] add help wanted in stale.yml --- .github/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/stale.yml b/.github/stale.yml index 8055777d..1ddb59e7 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -7,6 +7,7 @@ exemptLabels: - bug - urgent - necessary + - help wanted # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable From 6d1741694d2ba76f806e85e2a7947d8bae20bd42 Mon Sep 17 00:00:00 2001 From: zach valenta Date: Sat, 18 May 2019 15:05:03 -0400 Subject: [PATCH 12/19] fix typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 334704b7..66e8db15 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,7 @@ Sanic is a **Python 3.6+** web server and web framework that's written to go fas `Source code on GitHub `_ | `Help and discussion board `_. -The project is maintained by the community, for the community **Contributions are welcome!** +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. From 29bf967a7ea53ee2fa4c040e8f0405c8cc3afbd2 Mon Sep 17 00:00:00 2001 From: Harsha Narayana Date: Mon, 20 May 2019 06:46:18 +0530 Subject: [PATCH 13/19] doc: GIT-1582: add fedora package dependency Signed-off-by: Harsha Narayana --- README.rst | 6 ++++++ docs/sanic/getting_started.md | 2 ++ 2 files changed, 8 insertions(+) diff --git a/README.rst b/README.rst index 66e8db15..c7d22cbc 100644 --- a/README.rst +++ b/README.rst @@ -78,6 +78,12 @@ Installation $ pip3 install --no-binary :all: sanic +.. note:: + + If you are running on a clean install of Fedora 28 or above, please make sure you have the ``redhat-rpm-config`` package installed in case if you want to + use ``sanic`` with ``ujson`` dependency. + + Hello World Example ------------------- diff --git a/docs/sanic/getting_started.md b/docs/sanic/getting_started.md index daae4d66..c6a688a4 100644 --- a/docs/sanic/getting_started.md +++ b/docs/sanic/getting_started.md @@ -6,6 +6,8 @@ syntax, so earlier versions of python won't work. ## 1. Install Sanic +> If you are running on a clean install of Fedora 28 or above, please make sure you have the ``redhat-rpm-config`` package installed in case if you want to use ``sanic`` with ``ujson`` dependency. + ```bash pip3 install sanic ``` From b6453e9fac243f522c939ccd9eabdc3e9dfcd3f0 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Wed, 15 May 2019 07:46:58 +0300 Subject: [PATCH 14/19] Update stale.yml --- .github/stale.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index bf9b0fb3..8055777d 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -6,6 +6,7 @@ daysUntilClose: 30 exemptLabels: - bug - urgent + - necessary # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable @@ -14,4 +15,4 @@ markComment: > recent activity. It will be closed if no further activity occurs. If this is incorrect, please respond with an update. Thank you for your contributions. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false From 1b984422dbf97adf93afdfe235f657264c94677d Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Sat, 18 May 2019 11:02:46 -0700 Subject: [PATCH 15/19] add help wanted in stale.yml --- .github/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/stale.yml b/.github/stale.yml index 8055777d..1ddb59e7 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -7,6 +7,7 @@ exemptLabels: - bug - urgent - necessary + - help wanted # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable From 1c9141bd5dff6edb1bdf387f72595f93ecc33a94 Mon Sep 17 00:00:00 2001 From: zach valenta Date: Sat, 18 May 2019 15:05:03 -0400 Subject: [PATCH 16/19] fix typo --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 334704b7..66e8db15 100644 --- a/README.rst +++ b/README.rst @@ -60,7 +60,7 @@ Sanic is a **Python 3.6+** web server and web framework that's written to go fas `Source code on GitHub `_ | `Help and discussion board `_. -The project is maintained by the community, for the community **Contributions are welcome!** +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. From 83e3d4ca1f366a033a17485a7163ef807a4c1bd2 Mon Sep 17 00:00:00 2001 From: Harsha Narayana Date: Mon, 20 May 2019 06:46:18 +0530 Subject: [PATCH 17/19] doc: GIT-1582: add fedora package dependency Signed-off-by: Harsha Narayana --- README.rst | 6 ++++++ docs/sanic/getting_started.md | 2 ++ 2 files changed, 8 insertions(+) diff --git a/README.rst b/README.rst index 66e8db15..c7d22cbc 100644 --- a/README.rst +++ b/README.rst @@ -78,6 +78,12 @@ Installation $ pip3 install --no-binary :all: sanic +.. note:: + + If you are running on a clean install of Fedora 28 or above, please make sure you have the ``redhat-rpm-config`` package installed in case if you want to + use ``sanic`` with ``ujson`` dependency. + + Hello World Example ------------------- diff --git a/docs/sanic/getting_started.md b/docs/sanic/getting_started.md index daae4d66..c6a688a4 100644 --- a/docs/sanic/getting_started.md +++ b/docs/sanic/getting_started.md @@ -6,6 +6,8 @@ syntax, so earlier versions of python won't work. ## 1. Install Sanic +> If you are running on a clean install of Fedora 28 or above, please make sure you have the ``redhat-rpm-config`` package installed in case if you want to use ``sanic`` with ``ujson`` dependency. + ```bash pip3 install sanic ``` From 16d262e3e5787726a500190570e4d61a544a73cb Mon Sep 17 00:00:00 2001 From: Yun Xu Date: Wed, 22 May 2019 15:10:32 -0700 Subject: [PATCH 18/19] release: v19.6.0 --- sanic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sanic/__init__.py b/sanic/__init__.py index c7c69bd4..a1a2bf49 100644 --- a/sanic/__init__.py +++ b/sanic/__init__.py @@ -2,6 +2,6 @@ from sanic.app import Sanic from sanic.blueprints import Blueprint -__version__ = "19.03.1" +__version__ = "19.6.0" __all__ = ["Sanic", "Blueprint"] From 18cd4caf707054217aa020c676b3ccd029244fb6 Mon Sep 17 00:00:00 2001 From: Adam Hopkins Date: Thu, 23 May 2019 23:58:15 +0300 Subject: [PATCH 19/19] Create SECURITY.md --- SECURITY.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..dfa29fa4 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security Policy + +## Supported Versions + +Sanic releases long term support release once a year in December. LTS releases receive bug and security updates for **24 months**. Interim releases throughout the year occur every three months, and are supported until the subsequent interim release. + +| Version | LTS | Supported | +| ------- | ------------------ | ------------------ | +| 19.6.0 | | :white_check_mark: | +| 19.3.1 | | :heavy_check_mark: | +| 18.12.0 | :heavy_check_mark: | :heavy_check_mark: | +| 0.8.3 | | :x: | +| 0.7.0 | | :x: | +| 0.6.0 | | :x: | +| 0.5.4 | | :x: | +| 0.4.1 | | :x: | +| 0.3.1 | | :x: | +| 0.2.0 | | :x: | +| 0.1.9 | | :x: | + +## Reporting a Vulnerability + +If you discover a security vulnerability, we ask that you **do not** create an issue on GitHub. Instead, please [send a message to the core-devs](https://community.sanicframework.org/g/core-devs) on the community forums. Once logged in, you can send a message to the core-devs by clicking the message button. + +This will help to not publicize the issue until the team can address it and resolve it.