Compare commits
	
		
			15 Commits
		
	
	
		
			flaky-test
			...
			feat-2394-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 92bfeaefd5 | ||
|   | 5a650f5758 | ||
|   | 850b1f432c | ||
|   | df8480156d | ||
|   | d0cfb69f43 | ||
|   | 19eee8bfb2 | ||
|   | 625cffb1b9 | ||
|   | c5ac28cbcd | ||
|   | e57bea28f7 | ||
|   | 28665e31ce | ||
|   | 9f41936861 | ||
|   | 7835492b09 | ||
|   | ca3bea3425 | ||
|   | 88ca56dda3 | ||
|   | d2ab46d70b | 
							
								
								
									
										1
									
								
								.github/workflows/pr-python310.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/pr-python310.yml
									
									
									
									
										vendored
									
									
								
							| @@ -8,6 +8,7 @@ on: | |||||||
|  |  | ||||||
| jobs: | jobs: | ||||||
|   testPy310: |   testPy310: | ||||||
|  |     if: github.event.pull_request.draft == false | ||||||
|     name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }} |     name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }} | ||||||
|     runs-on: ${{ matrix.os }} |     runs-on: ${{ matrix.os }} | ||||||
|     strategy: |     strategy: | ||||||
|   | |||||||
| @@ -140,7 +140,6 @@ To maintain the code consistency, Sanic uses following tools. | |||||||
| #. `isort <https://github.com/timothycrosley/isort>`_ | #. `isort <https://github.com/timothycrosley/isort>`_ | ||||||
| #. `black <https://github.com/python/black>`_ | #. `black <https://github.com/python/black>`_ | ||||||
| #. `flake8 <https://github.com/PyCQA/flake8>`_ | #. `flake8 <https://github.com/PyCQA/flake8>`_ | ||||||
| #. `slotscheck <https://github.com/ariebovenberg/slotscheck>`_ |  | ||||||
|  |  | ||||||
| isort | isort | ||||||
| ***** | ***** | ||||||
| @@ -168,13 +167,7 @@ flake8 | |||||||
| #. pycodestyle | #. pycodestyle | ||||||
| #. Ned Batchelder's McCabe script | #. Ned Batchelder's McCabe script | ||||||
|  |  | ||||||
| slotscheck | ``isort``\ , ``black`` and ``flake8`` checks are performed during ``tox`` lint checks. | ||||||
| ********** |  | ||||||
|  |  | ||||||
| ``slotscheck`` ensures that there are no problems with ``__slots__`` |  | ||||||
| (e.g. overlaps, or missing slots in base classes). |  | ||||||
|  |  | ||||||
| ``isort``\ , ``black``\ , ``flake8`` and ``slotscheck`` checks are performed during ``tox`` lint checks. |  | ||||||
|  |  | ||||||
| The **easiest** way to make your code conform is to run the following before committing. | The **easiest** way to make your code conform is to run the following before committing. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,5 +6,5 @@ data = "" | |||||||
| for i in range(1, 250000): | for i in range(1, 250000): | ||||||
|     data += str(i) |     data += str(i) | ||||||
|  |  | ||||||
| r = requests.post('http://0.0.0.0:8000/stream', data=data) | r = requests.post("http://0.0.0.0:8000/stream", data=data) | ||||||
| print(r.text) | print(r.text) | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								sanic/app.py
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								sanic/app.py
									
									
									
									
									
								
							| @@ -44,8 +44,11 @@ from typing import ( | |||||||
| from urllib.parse import urlencode, urlunparse | from urllib.parse import urlencode, urlunparse | ||||||
| from warnings import filterwarnings | from warnings import filterwarnings | ||||||
|  |  | ||||||
| from sanic_routing.exceptions import FinalizationError, NotFound | from sanic_routing.exceptions import (  # type: ignore | ||||||
| from sanic_routing.route import Route |     FinalizationError, | ||||||
|  |     NotFound, | ||||||
|  | ) | ||||||
|  | from sanic_routing.route import Route  # type: ignore | ||||||
|  |  | ||||||
| from sanic.application.ext import setup_ext | from sanic.application.ext import setup_ext | ||||||
| from sanic.application.state import ApplicationState, Mode, ServerStage | from sanic.application.state import ApplicationState, Mode, ServerStage | ||||||
| @@ -139,6 +142,7 @@ class Sanic(BaseSanic, RunnerMixin, metaclass=TouchUpMeta): | |||||||
|         "error_handler", |         "error_handler", | ||||||
|         "go_fast", |         "go_fast", | ||||||
|         "listeners", |         "listeners", | ||||||
|  |         "name", | ||||||
|         "named_request_middleware", |         "named_request_middleware", | ||||||
|         "named_response_middleware", |         "named_response_middleware", | ||||||
|         "request_class", |         "request_class", | ||||||
| @@ -1264,9 +1268,10 @@ class Sanic(BaseSanic, RunnerMixin, metaclass=TouchUpMeta): | |||||||
|                 ... |                 ... | ||||||
|  |  | ||||||
|     def purge_tasks(self): |     def purge_tasks(self): | ||||||
|         for key, task in self._task_registry.items(): |         for task in self.tasks: | ||||||
|             if task.done() or task.cancelled(): |             if task.done() or task.cancelled(): | ||||||
|                 self._task_registry[key] = None |                 name = task.get_name() | ||||||
|  |                 self._task_registry[name] = None | ||||||
|  |  | ||||||
|         self._task_registry = { |         self._task_registry = { | ||||||
|             k: v for k, v in self._task_registry.items() if v is not None |             k: v for k, v in self._task_registry.items() if v is not None | ||||||
|   | |||||||
| @@ -16,9 +16,9 @@ class MiddlewareMixin(metaclass=SanicMeta): | |||||||
|         self, middleware_or_request, attach_to="request", apply=True |         self, middleware_or_request, attach_to="request", apply=True | ||||||
|     ): |     ): | ||||||
|         """ |         """ | ||||||
|         Decorate and register middleware to be called before a request |         Decorate and register middleware to be called before a request. | ||||||
|         is handled or after a response is created. Can either be called as |         Can either be called as *@app.middleware* or | ||||||
|         *@app.middleware* or *@app.middleware('request')*. |         *@app.middleware('request')* | ||||||
|  |  | ||||||
|         `See user guide re: middleware |         `See user guide re: middleware | ||||||
|         <https://sanicframework.org/guide/basics/middleware.html>`__ |         <https://sanicframework.org/guide/basics/middleware.html>`__ | ||||||
| @@ -47,25 +47,12 @@ class MiddlewareMixin(metaclass=SanicMeta): | |||||||
|             ) |             ) | ||||||
|  |  | ||||||
|     def on_request(self, middleware=None): |     def on_request(self, middleware=None): | ||||||
|         """Register a middleware to be called before a request is handled. |  | ||||||
|  |  | ||||||
|         This is the same as *@app.middleware('request')*. |  | ||||||
|  |  | ||||||
|         :param: middleware: A callable that takes in request. |  | ||||||
|         """ |  | ||||||
|         if callable(middleware): |         if callable(middleware): | ||||||
|             return self.middleware(middleware, "request") |             return self.middleware(middleware, "request") | ||||||
|         else: |         else: | ||||||
|             return partial(self.middleware, attach_to="request") |             return partial(self.middleware, attach_to="request") | ||||||
|  |  | ||||||
|     def on_response(self, middleware=None): |     def on_response(self, middleware=None): | ||||||
|         """Register a middleware to be called after a response is created. |  | ||||||
|  |  | ||||||
|         This is the same as *@app.middleware('response')*. |  | ||||||
|  |  | ||||||
|         :param: middleware: |  | ||||||
|             A callable that takes in a request and its response. |  | ||||||
|         """ |  | ||||||
|         if callable(middleware): |         if callable(middleware): | ||||||
|             return self.middleware(middleware, "response") |             return self.middleware(middleware, "response") | ||||||
|         else: |         else: | ||||||
|   | |||||||
| @@ -30,6 +30,7 @@ from types import SimpleNamespace | |||||||
| from urllib.parse import parse_qs, parse_qsl, unquote, urlunparse | from urllib.parse import parse_qs, parse_qsl, unquote, urlunparse | ||||||
|  |  | ||||||
| from httptools import parse_url  # type: ignore | from httptools import parse_url  # type: ignore | ||||||
|  | from httptools.parser.errors import HttpParserInvalidURLError # type: ignore | ||||||
|  |  | ||||||
| from sanic.compat import CancelledErrors, Header | from sanic.compat import CancelledErrors, Header | ||||||
| from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE | from sanic.constants import DEFAULT_HTTP_CONTENT_TYPE | ||||||
| @@ -130,7 +131,12 @@ class Request: | |||||||
|  |  | ||||||
|         self.raw_url = url_bytes |         self.raw_url = url_bytes | ||||||
|         # TODO: Content-Encoding detection |         # TODO: Content-Encoding detection | ||||||
|  |         try: | ||||||
|             self._parsed_url = parse_url(url_bytes) |             self._parsed_url = parse_url(url_bytes) | ||||||
|  |         except HttpParserInvalidURLError as InvalidURLError: | ||||||
|  |             raise InvalidUsage( | ||||||
|  |                 "URL is invalid or malformed" | ||||||
|  |             ) from InvalidURLError | ||||||
|         self._id: Optional[Union[uuid.UUID, str, int]] = None |         self._id: Optional[Union[uuid.UUID, str, int]] = None | ||||||
|         self._name: Optional[str] = None |         self._name: Optional[str] = None | ||||||
|         self.app = app |         self.app = app | ||||||
|   | |||||||
| @@ -50,16 +50,6 @@ class BaseHTTPResponse: | |||||||
|     The base class for all HTTP Responses |     The base class for all HTTP Responses | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     __slots__ = ( |  | ||||||
|         "asgi", |  | ||||||
|         "body", |  | ||||||
|         "content_type", |  | ||||||
|         "stream", |  | ||||||
|         "status", |  | ||||||
|         "headers", |  | ||||||
|         "_cookies", |  | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     _dumps = json_dumps |     _dumps = json_dumps | ||||||
|  |  | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
| @@ -166,7 +156,7 @@ class HTTPResponse(BaseHTTPResponse): | |||||||
|     :type content_type: Optional[str] |     :type content_type: Optional[str] | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     __slots__ = () |     __slots__ = ("body", "status", "content_type", "headers", "_cookies") | ||||||
|  |  | ||||||
|     def __init__( |     def __init__( | ||||||
|         self, |         self, | ||||||
|   | |||||||
| @@ -1,12 +1,26 @@ | |||||||
| import asyncio | import asyncio | ||||||
|  |  | ||||||
| from distutils.util import strtobool |  | ||||||
| from os import getenv | from os import getenv | ||||||
|  |  | ||||||
| from sanic.compat import OS_IS_WINDOWS | from sanic.compat import OS_IS_WINDOWS | ||||||
| from sanic.log import error_logger | from sanic.log import error_logger | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def strtobool(query: str) -> bool: | ||||||
|  |     """ | ||||||
|  |     reimplement strtobool per PEP 632 and python 3.12 deprecation | ||||||
|  |  | ||||||
|  |     True values are y, yes, t, true, on and 1; false values are n, no, f, | ||||||
|  |     false, off and 0. Raises ValueError if val is anything else. | ||||||
|  |     """ | ||||||
|  |     if query.lower() in ["y", "yes", "t", "true", "on", "1"]: | ||||||
|  |         return True | ||||||
|  |     elif query.lower() in ["n", "no", "f", "false", "off", "0"]: | ||||||
|  |         return False | ||||||
|  |     else: | ||||||
|  |         raise ValueError(f"String value {query} cannot be converted to bool") | ||||||
|  |  | ||||||
|  |  | ||||||
| def try_use_uvloop() -> None: | def try_use_uvloop() -> None: | ||||||
|     """ |     """ | ||||||
|     Use uvloop instead of the default asyncio loop. |     Use uvloop instead of the default asyncio loop. | ||||||
|   | |||||||
| @@ -11,35 +11,18 @@ from sanic.helpers import import_string | |||||||
|  |  | ||||||
|  |  | ||||||
| def str_to_bool(val: str) -> bool: | def str_to_bool(val: str) -> bool: | ||||||
|     """Takes string and tries to turn it into bool as human would do. |     """ | ||||||
|  |     reimplement strtobool per PEP 632 and python 3.12 deprecation | ||||||
|  |  | ||||||
|     If val is in case insensitive ( |     True values are y, yes, t, true, on and 1; false values are n, no, f, | ||||||
|         "y", "yes", "yep", "yup", "t", |     false, off and 0. Raises ValueError if val is anything else. | ||||||
|         "true", "on", "enable", "enabled", "1" |     """ | ||||||
|     ) returns True. |     if val.lower() in ["y", "yes", "t", "true", "on", "1"]: | ||||||
|     If val is in case insensitive ( |  | ||||||
|         "n", "no", "f", "false", "off", "disable", "disabled", "0" |  | ||||||
|     ) returns False. |  | ||||||
|     Else Raise ValueError.""" |  | ||||||
|  |  | ||||||
|     val = val.lower() |  | ||||||
|     if val in { |  | ||||||
|         "y", |  | ||||||
|         "yes", |  | ||||||
|         "yep", |  | ||||||
|         "yup", |  | ||||||
|         "t", |  | ||||||
|         "true", |  | ||||||
|         "on", |  | ||||||
|         "enable", |  | ||||||
|         "enabled", |  | ||||||
|         "1", |  | ||||||
|     }: |  | ||||||
|         return True |         return True | ||||||
|     elif val in {"n", "no", "f", "false", "off", "disable", "disabled", "0"}: |     elif val.lower() in ["n", "no", "f", "false", "off", "0"]: | ||||||
|         return False |         return False | ||||||
|     else: |     else: | ||||||
|         raise ValueError(f"Invalid truth value {val}") |         raise ValueError(f"String value {val} cannot be converted to bool") | ||||||
|  |  | ||||||
|  |  | ||||||
| def load_module_from_file_location( | def load_module_from_file_location( | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								setup.py
									
									
									
									
									
								
							| @@ -6,8 +6,6 @@ import os | |||||||
| import re | import re | ||||||
| import sys | import sys | ||||||
|  |  | ||||||
| from distutils.util import strtobool |  | ||||||
|  |  | ||||||
| from setuptools import find_packages, setup | from setuptools import find_packages, setup | ||||||
| from setuptools.command.test import test as TestCommand | from setuptools.command.test import test as TestCommand | ||||||
|  |  | ||||||
| @@ -61,7 +59,7 @@ setup_kwargs = { | |||||||
|         "Build fast. Run fast." |         "Build fast. Run fast." | ||||||
|     ), |     ), | ||||||
|     "long_description": long_description, |     "long_description": long_description, | ||||||
|     "packages": find_packages(), |     "packages": find_packages(include=[]), | ||||||
|     "package_data": {"sanic": ["py.typed"]}, |     "package_data": {"sanic": ["py.typed"]}, | ||||||
|     "platforms": "any", |     "platforms": "any", | ||||||
|     "python_requires": ">=3.7", |     "python_requires": ">=3.7", | ||||||
| @@ -112,7 +110,6 @@ tests_require = [ | |||||||
|     "docutils", |     "docutils", | ||||||
|     "pygments", |     "pygments", | ||||||
|     "uvicorn<0.15.0", |     "uvicorn<0.15.0", | ||||||
|     "slotscheck>=0.8.0,<1", |  | ||||||
|     types_ujson, |     types_ujson, | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -133,6 +130,23 @@ dev_require = tests_require + [ | |||||||
|  |  | ||||||
| all_require = list(set(dev_require + docs_require)) | all_require = list(set(dev_require + docs_require)) | ||||||
|  |  | ||||||
|  | # trying to self-refernce this from within sanic prior to install is | ||||||
|  | # problematic | ||||||
|  | def strtobool(val: str) -> bool: | ||||||
|  |     """ | ||||||
|  |     reimplement strtobool per PEP 632 and python 3.12 deprecation | ||||||
|  |  | ||||||
|  |     True values are y, yes, t, true, on and 1; false values are n, no, f, | ||||||
|  |     false, off and 0. Raises ValueError if val is anything else. | ||||||
|  |     """ | ||||||
|  |     if val.lower() in ["y", "yes", "t", "true", "on", "1"]: | ||||||
|  |         return True | ||||||
|  |     elif val.lower() in ["n", "no", "f", "false", "off", "0"]: | ||||||
|  |         return False | ||||||
|  |     else: | ||||||
|  |         raise ValueError(f"String value {val} cannot be converted to bool") | ||||||
|  |  | ||||||
|  |  | ||||||
| if strtobool(os.environ.get("SANIC_NO_UJSON", "no")): | if strtobool(os.environ.get("SANIC_NO_UJSON", "no")): | ||||||
|     print("Installing without uJSON") |     print("Installing without uJSON") | ||||||
|     requirements.remove(ujson) |     requirements.remove(ujson) | ||||||
|   | |||||||
| @@ -21,3 +21,25 @@ def test_bad_request_response(app): | |||||||
|     app.run(host="127.0.0.1", port=42101, debug=False) |     app.run(host="127.0.0.1", port=42101, debug=False) | ||||||
|     assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n" |     assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n" | ||||||
|     assert b"Bad Request" in lines[-2] |     assert b"Bad Request" in lines[-2] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def test_malformed_uri_bad_request(app): | ||||||
|  |     lines = [] | ||||||
|  |  | ||||||
|  |     app.get("/")(lambda x: ...) | ||||||
|  |  | ||||||
|  |     @app.listener("after_server_start") | ||||||
|  |     async def _request(sanic, loop): | ||||||
|  |         connect = asyncio.open_connection("127.0.0.1", 42101) | ||||||
|  |         reader, writer = await connect | ||||||
|  |         writer.write(b"GET /\r\nHost: ---.com\r\n\r\n") | ||||||
|  |         while True: | ||||||
|  |             line = await reader.readline() | ||||||
|  |             if not line: | ||||||
|  |                 break | ||||||
|  |             lines.append(line) | ||||||
|  |         app.stop() | ||||||
|  |  | ||||||
|  |     app.run(host="127.0.0.1", port=42101, debug=False) | ||||||
|  |     assert lines[0] == b"HTTP/1.1 400 Bad Request\r\n" | ||||||
|  |     assert b"Bad Request" in lines[-2] | ||||||
| @@ -5,7 +5,6 @@ from pathlib import Path | |||||||
|  |  | ||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| from pyparsing import line |  | ||||||
| from sanic_routing import __version__ as __routing_version__ | from sanic_routing import __version__ as __routing_version__ | ||||||
|  |  | ||||||
| from sanic import __version__ | from sanic import __version__ | ||||||
| @@ -53,10 +52,8 @@ def test_server_run(appname): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     firstline = lines[starting_line(lines) + 1] |     firstline = lines[starting_line(lines) + 1] | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert exitcode != 1 |     assert exitcode != 1 | ||||||
|     assert lines, error_message |  | ||||||
|     assert firstline == b"Goin' Fast @ http://127.0.0.1:8000" |     assert firstline == b"Goin' Fast @ http://127.0.0.1:8000" | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -83,9 +80,6 @@ def test_tls_options(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     assert exitcode != 1 |     assert exitcode != 1 | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert lines, error_message |  | ||||||
|     firstline = lines[starting_line(lines) + 1] |     firstline = lines[starting_line(lines) + 1] | ||||||
|     assert firstline == b"Goin' Fast @ https://127.0.0.1:9999" |     assert firstline == b"Goin' Fast @ https://127.0.0.1:9999" | ||||||
|  |  | ||||||
| @@ -108,9 +102,7 @@ def test_tls_wrong_options(cmd): | |||||||
|     assert exitcode == 1 |     assert exitcode == 1 | ||||||
|     assert not out |     assert not out | ||||||
|     lines = err.decode().split("\n") |     lines = err.decode().split("\n") | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert lines, error_message |  | ||||||
|     errmsg = lines[6] |     errmsg = lines[6] | ||||||
|     assert errmsg == "TLS certificates must be specified by either of:" |     assert errmsg == "TLS certificates must be specified by either of:" | ||||||
|  |  | ||||||
| @@ -127,11 +119,9 @@ def test_host_port_localhost(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     expected = b"Goin' Fast @ http://localhost:9999" |     expected = b"Goin' Fast @ http://localhost:9999" | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert exitcode != 1 |     assert exitcode != 1 | ||||||
|     assert lines, error_message |     assert expected in lines, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert expected in lines, error_message |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
| @@ -146,11 +136,9 @@ def test_host_port_ipv4(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     expected = b"Goin' Fast @ http://127.0.0.127:9999" |     expected = b"Goin' Fast @ http://127.0.0.127:9999" | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert exitcode != 1 |     assert exitcode != 1 | ||||||
|     assert lines, error_message |     assert expected in lines, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert expected in lines, error_message |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
| @@ -165,11 +153,9 @@ def test_host_port_ipv6_any(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     expected = b"Goin' Fast @ http://[::]:9999" |     expected = b"Goin' Fast @ http://[::]:9999" | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert exitcode != 1 |     assert exitcode != 1 | ||||||
|     assert lines, error_message |     assert expected in lines, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert expected in lines, error_message |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
| @@ -184,11 +170,9 @@ def test_host_port_ipv6_loopback(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     expected = b"Goin' Fast @ http://[::1]:9999" |     expected = b"Goin' Fast @ http://[::1]:9999" | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert exitcode != 1 |     assert exitcode != 1 | ||||||
|     assert lines, error_message |     assert expected in lines, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert expected in lines, error_message |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
| @@ -222,12 +206,12 @@ def test_debug(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     info = read_app_info(lines) |     info = read_app_info(lines) | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert info, error_message |     assert info["debug"] is True, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert info["debug"] is True, error_message |     assert ( | ||||||
|     assert info["auto_reload"] is False, error_message |         info["auto_reload"] is False | ||||||
|     assert "dev" not in info, error_message |     ), f"Lines found: {lines}\nErr output: {err}" | ||||||
|  |     assert "dev" not in info, f"Lines found: {lines}\nErr output: {err}" | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("cmd", ("--dev", "-d")) | @pytest.mark.parametrize("cmd", ("--dev", "-d")) | ||||||
| @@ -236,11 +220,11 @@ def test_dev(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     info = read_app_info(lines) |     info = read_app_info(lines) | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert info, error_message |     assert info["debug"] is True, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert info["debug"] is True, error_message |     assert ( | ||||||
|     assert info["auto_reload"] is True, error_message |         info["auto_reload"] is True | ||||||
|  |     ), f"Lines found: {lines}\nErr output: {err}" | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("cmd", ("--auto-reload", "-r")) | @pytest.mark.parametrize("cmd", ("--auto-reload", "-r")) | ||||||
| @@ -249,12 +233,12 @@ def test_auto_reload(cmd): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     info = read_app_info(lines) |     info = read_app_info(lines) | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert info, error_message |     assert info["debug"] is False, f"Lines found: {lines}\nErr output: {err}" | ||||||
|     assert info["debug"] is False, error_message |     assert ( | ||||||
|     assert info["auto_reload"] is True, error_message |         info["auto_reload"] is True | ||||||
|     assert "dev" not in info, error_message |     ), f"Lines found: {lines}\nErr output: {err}" | ||||||
|  |     assert "dev" not in info, f"Lines found: {lines}\nErr output: {err}" | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
| @@ -265,10 +249,10 @@ def test_access_logs(cmd, expected): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     info = read_app_info(lines) |     info = read_app_info(lines) | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert info, error_message |     assert ( | ||||||
|     assert info["access_log"] is expected, error_message |         info["access_log"] is expected | ||||||
|  |     ), f"Lines found: {lines}\nErr output: {err}" | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize("cmd", ("--version", "-v")) | @pytest.mark.parametrize("cmd", ("--version", "-v")) | ||||||
| @@ -292,7 +276,7 @@ def test_noisy_exceptions(cmd, expected): | |||||||
|     out, err, exitcode = capture(command) |     out, err, exitcode = capture(command) | ||||||
|     lines = out.split(b"\n") |     lines = out.split(b"\n") | ||||||
|     info = read_app_info(lines) |     info = read_app_info(lines) | ||||||
|     error_message = f"Lines found: {lines}\nErr output: {err}" |  | ||||||
|  |  | ||||||
|     assert info, error_message |     assert ( | ||||||
|     assert info["noisy_exceptions"] is expected, error_message |         info["noisy_exceptions"] is expected | ||||||
|  |     ), f"Lines found: {lines}\nErr output: {err}" | ||||||
|   | |||||||
| @@ -80,18 +80,6 @@ async def test_purge_tasks(app: Sanic): | |||||||
|     assert len(app._task_registry) == 0 |     assert len(app._task_registry) == 0 | ||||||
|  |  | ||||||
|  |  | ||||||
| async def test_purge_tasks_with_create_task(app: Sanic): |  | ||||||
|     app.add_task(asyncio.create_task(dummy(3)), name="dummy") |  | ||||||
|  |  | ||||||
|     await app.cancel_task("dummy") |  | ||||||
|  |  | ||||||
|     assert len(app._task_registry) == 1 |  | ||||||
|  |  | ||||||
|     app.purge_tasks() |  | ||||||
|  |  | ||||||
|     assert len(app._task_registry) == 0 |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_shutdown_tasks_on_app_stop(): | def test_shutdown_tasks_on_app_stop(): | ||||||
|     class TestSanic(Sanic): |     class TestSanic(Sanic): | ||||||
|         shutdown_tasks = Mock() |         shutdown_tasks = Mock() | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import pytest | |||||||
|  |  | ||||||
| from sanic.exceptions import LoadFileException | from sanic.exceptions import LoadFileException | ||||||
| from sanic.utils import load_module_from_file_location | from sanic.utils import load_module_from_file_location | ||||||
|  | from sanic.utils import str_to_bool as strtobool | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.mark.parametrize( | @pytest.mark.parametrize( | ||||||
| @@ -48,3 +49,20 @@ def test_load_module_from_file_location_using_env(): | |||||||
|     module = load_module_from_file_location(location) |     module = load_module_from_file_location(location) | ||||||
|  |  | ||||||
|     assert isinstance(module, ModuleType) |     assert isinstance(module, ModuleType) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @pytest.mark.parametrize( | ||||||
|  |     "valid,values", | ||||||
|  |     ( | ||||||
|  |         (True, ["y", "yes", "t", "true", "on", "1", "Y", "yEs", "True"]), | ||||||
|  |         (False, ["n", "no", "f", "false", "off", "0", "N", "No", "False"]), | ||||||
|  |         (None, ["yyy", "foo"]), | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  | def test_strtobool(valid, values): | ||||||
|  |     for value in values: | ||||||
|  |         if valid is None: | ||||||
|  |             with pytest.raises(ValueError): | ||||||
|  |                 strtobool(value) | ||||||
|  |         else: | ||||||
|  |             assert strtobool(value) is valid | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								tox.ini
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								tox.ini
									
									
									
									
									
								
							| @@ -21,7 +21,6 @@ commands = | |||||||
|     flake8 sanic |     flake8 sanic | ||||||
|     black --config ./.black.toml --check --verbose sanic/ |     black --config ./.black.toml --check --verbose sanic/ | ||||||
|     isort --check-only sanic --profile=black |     isort --check-only sanic --profile=black | ||||||
|     slotscheck --verbose -m sanic |  | ||||||
|  |  | ||||||
| [testenv:type-checking] | [testenv:type-checking] | ||||||
| commands = | commands = | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user