Compare commits

..

12 Commits

Author SHA1 Message Date
Adam Hopkins
ad9183d21d Merge branch 'main' of github.com:sanic-org/sanic into current-release 2022-10-31 13:22:47 +02:00
Adam Hopkins
d70636ba2e Add GenericCreator for loading SSL certs in processes (#2578) 2022-10-31 13:22:30 +02:00
Adam Hopkins
da23f85675 Set version 2022-10-31 13:20:17 +02:00
Adam Hopkins
3f4663b9f8 Resolve edge case in nested BP Groups (#2592) 2022-10-31 12:58:41 +02:00
Adam Hopkins
65d7447cf6 Add interval sleep in reloader (#2595) 2022-10-31 12:34:01 +02:00
Adam Hopkins
5369291c27 22.9 Docs (#2556) 2022-10-31 11:47:23 +02:00
Ryu Juheon
1c4925edf7 fix: sideeffects created by changing fork to spawn (#2591) 2022-10-27 20:39:17 +03:00
Santi Cardozo
6b9edfd05c improve error message if no apps found in registry (#2585) 2022-10-25 16:54:44 +03:00
Adam Hopkins
97f33f42df Update SECURITY.md 2022-10-25 13:05:13 +03:00
Adam Hopkins
15a588a90c Upgrade markdown templates to issue forms (#2588) 2022-10-25 13:04:11 +03:00
Ryu Juheon
82421e7efc docs: sanic now supports windows. (#2582) 2022-10-21 14:31:22 +03:00
Adam Hopkins
f891995b48 Start v22.12 2022-09-29 13:04:46 +03:00
26 changed files with 304 additions and 108 deletions

66
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: 🐞 Bug report
description: Create a report to help us improve
labels: ["bug", "triage"]
body:
- type: checkboxes
id: existing
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: textarea
id: description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is, make sure to paste any exceptions and tracebacks using markdown code-block syntax to make it easier to read.
validations:
required: true
- type: textarea
id: code
attributes:
label: Code snippet
description: Relevant source code, make sure to remove what is not necessary.
validations:
required: false
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: false
- type: dropdown
id: running
attributes:
label: How do you run Sanic?
options:
- Sanic CLI
- As a module
- As a script (`app.run` or `Sanic.serve`)
- ASGI
validations:
required: true
- type: input
id: os
attributes:
label: Operating System
description: What OS?
validations:
required: true
- type: input
id: version
attributes:
label: Sanic Version
description: Check startup logs or try `sanic --version`
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional context
description: Add any other context about the problem here.
validations:
required: false

View File

@@ -1,27 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
labels: ["bug"]
---
**Describe the bug**
<!-- A clear and concise description of what the bug is, make sure to paste any exceptions and tracebacks. -->
**Code snippet**
<!-- Relevant source code, make sure to remove what is not necessary. -->
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Environment (please complete the following information):**
<!-- Please provide the information below. Instead, you can copy and paste the message that Sanic shows on startup. If you do, please remember to format it with ``` -->
- OS:
- Sanic Version:
**Additional context**
<!-- Add any other context about the problem here. -->

View File

@@ -1,4 +1,4 @@
blank_issues_enabled: true blank_issues_enabled: false
contact_links: contact_links:
- name: Questions and Help - name: Questions and Help
url: https://community.sanicframework.org/c/questions-and-help url: https://community.sanicframework.org/c/questions-and-help

View File

@@ -0,0 +1,34 @@
name: 🌟 Feature request
description: Suggest an enhancement for Sanic
labels: ["feature request"]
body:
- type: checkboxes
id: existing
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the enhancement you are proposing.
options:
- label: I have searched the existing issues
required: true
- type: textarea
id: description
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: false
- type: textarea
id: code
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: additional
attributes:
label: Additional context
description: Add any other context about the problem here.
validations:
required: false

View File

@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for Sanic
labels: ["feature request"]
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to happen. -->
**Additional context**
<!-- Add any other context or sample code about the feature request here. -->

View File

@@ -102,9 +102,6 @@ Installation
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 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. use ``sanic`` with ``ujson`` dependency.
.. note::
Windows support is currently "experimental" and on a best-effort basis. Multiple workers are also not currently supported on Windows (see `Issue #1517 <https://github.com/sanic-org/sanic/issues/1517>`_), but setting ``workers=1`` should launch the server successfully.
Hello World Example Hello World Example
------------------- -------------------

View File

@@ -7,7 +7,8 @@ Sanic releases long term support release once a year in December. LTS releases r
| Version | LTS | Supported | | Version | LTS | Supported |
| ------- | ------------- | ----------------------- | | ------- | ------------- | ----------------------- |
| 22.6 | | :white_check_mark: | | 22.9 | | :white_check_mark: |
| 22.6 | | :x: |
| 22.3 | | :x: | | 22.3 | | :x: |
| 21.12 | until 2023-12 | :white_check_mark: | | 21.12 | until 2023-12 | :white_check_mark: |
| 21.9 | | :x: | | 21.9 | | :x: |

View File

@@ -2,3 +2,12 @@
.wy-nav-top { .wy-nav-top {
background: #444444; background: #444444;
} }
#changelog section {
padding-left: 3rem;
}
#changelog section h2,
#changelog section h3 {
margin-left: -3rem;
}

View File

@@ -1,6 +1,7 @@
📜 Changelog 📜 Changelog
============ ============
.. mdinclude:: ./releases/22/22.9.md
.. mdinclude:: ./releases/22/22.6.md .. mdinclude:: ./releases/22/22.6.md
.. mdinclude:: ./releases/22/22.3.md .. mdinclude:: ./releases/22/22.3.md
.. mdinclude:: ./releases/21/21.12.md .. mdinclude:: ./releases/21/21.12.md

View File

@@ -1,6 +1,17 @@
## Version 22.6.0 🔶 ## Version 22.6.2
_Current version_ ### Bugfixes
- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI
## Version 22.6.1
### Bugfixes
- [#2477](https://github.com/sanic-org/sanic/pull/2477) Sanic static directory fails when folder name ends with ".."
## Version 22.6.0
### Features ### Features
- [#2378](https://github.com/sanic-org/sanic/pull/2378) Introduce HTTP/3 and autogeneration of TLS certificates in `DEBUG` mode - [#2378](https://github.com/sanic-org/sanic/pull/2378) Introduce HTTP/3 and autogeneration of TLS certificates in `DEBUG` mode

View File

@@ -0,0 +1,47 @@
## Version 22.9.0 🔶
_Current version_
### Features
- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom loads function
- [#2490](https://github.com/sanic-org/sanic/pull/2490) Make `WebsocketImplProtocol` async iterable
- [#2499](https://github.com/sanic-org/sanic/pull/2499) Sanic Server WorkerManager refactor
- [#2506](https://github.com/sanic-org/sanic/pull/2506) Use `pathlib` for path resolution (for static file serving)
- [#2508](https://github.com/sanic-org/sanic/pull/2508) Use `path.parts` instead of `match` (for static file serving)
- [#2513](https://github.com/sanic-org/sanic/pull/2513) Better request cancel handling
- [#2516](https://github.com/sanic-org/sanic/pull/2516) Add request properties for HTTP method info:
- `request.is_safe`
- `request.is_idempotent`
- `request.is_cacheable`
- *See* [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) *for more information about when these apply*
- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI
- [#2526](https://github.com/sanic-org/sanic/pull/2526) Cache control support for static files for returning 304 when appropriate
- [#2533](https://github.com/sanic-org/sanic/pull/2533) Refactor `_static_request_handler`
- [#2540](https://github.com/sanic-org/sanic/pull/2540) Add signals before and after handler execution
- `http.handler.before`
- `http.handler.after`
- [#2542](https://github.com/sanic-org/sanic/pull/2542) Add *[redacted]* to CLI :)
- [#2546](https://github.com/sanic-org/sanic/pull/2546) Add deprecation warning filter
- [#2550](https://github.com/sanic-org/sanic/pull/2550) Middleware priority and performance enhancements
### Bugfixes
- [#2495](https://github.com/sanic-org/sanic/pull/2495) Prevent directory traversion with static files
- [#2515](https://github.com/sanic-org/sanic/pull/2515) Do not apply double slash to paths in certain static dirs in Blueprints
### Deprecations and Removals
- [#2525](https://github.com/sanic-org/sanic/pull/2525) Warn on duplicate route names, will be prevented outright in v23.3
- [#2537](https://github.com/sanic-org/sanic/pull/2537) Raise warning and deprecation notice on duplicate exceptions, will be prevented outright in v23.3
### Developer infrastructure
- [#2504](https://github.com/sanic-org/sanic/pull/2504) Cleanup test suite
- [#2505](https://github.com/sanic-org/sanic/pull/2505) Replace Unsupported Python Version Number from the Contributing Doc
- [#2530](https://github.com/sanic-org/sanic/pull/2530) Do not include tests folder in installed package resolver
### Improved Documentation
- [#2502](https://github.com/sanic-org/sanic/pull/2502) Fix a few typos
- [#2517](https://github.com/sanic-org/sanic/pull/2517) [#2536](https://github.com/sanic-org/sanic/pull/2536) Add some type hints

View File

@@ -1 +1 @@
__version__ = "22.9.0" __version__ = "22.9.1"

View File

@@ -61,7 +61,7 @@ from sanic.exceptions import (
URLBuildError, URLBuildError,
) )
from sanic.handlers import ErrorHandler from sanic.handlers import ErrorHandler
from sanic.helpers import _default from sanic.helpers import Default
from sanic.http import Stage from sanic.http import Stage
from sanic.log import ( from sanic.log import (
LOGGING_CONFIG_DEFAULTS, LOGGING_CONFIG_DEFAULTS,
@@ -480,15 +480,14 @@ class Sanic(BaseSanic, StartupMixin, metaclass=TouchUpMeta):
for item in blueprint: for item in blueprint:
params = {**options} params = {**options}
if isinstance(blueprint, BlueprintGroup): if isinstance(blueprint, BlueprintGroup):
if blueprint.url_prefix:
merge_from = [ merge_from = [
options.get("url_prefix", ""), options.get("url_prefix", ""),
blueprint.url_prefix, blueprint.url_prefix or "",
] ]
if not isinstance(item, BlueprintGroup): if not isinstance(item, BlueprintGroup):
merge_from.append(item.url_prefix or "") merge_from.append(item.url_prefix or "")
merged_prefix = "/".join( merged_prefix = "/".join(
u.strip("/") for u in merge_from u.strip("/") for u in merge_from if u
).rstrip("/") ).rstrip("/")
params["url_prefix"] = f"/{merged_prefix}" params["url_prefix"] = f"/{merged_prefix}"
@@ -1453,7 +1452,14 @@ class Sanic(BaseSanic, StartupMixin, metaclass=TouchUpMeta):
return cls.get_app("__mp_main__", force_create=force_create) return cls.get_app("__mp_main__", force_create=force_create)
if force_create: if force_create:
return cls(name) return cls(name)
raise SanicException(f'Sanic app name "{name}" not found.') raise SanicException(
f"Sanic app name '{name}' not found.\n"
"App instantiation must occur outside "
"if __name__ == '__main__' "
"block or by using an AppLoader.\nSee "
"https://sanic.dev/en/guide/deployment/app-loader.html"
" for more details."
)
@classmethod @classmethod
def _check_uvloop_conflict(cls) -> None: def _check_uvloop_conflict(cls) -> None:
@@ -1495,7 +1501,7 @@ class Sanic(BaseSanic, StartupMixin, metaclass=TouchUpMeta):
if self.state.is_debug and self.config.TOUCHUP is not True: if self.state.is_debug and self.config.TOUCHUP is not True:
self.config.TOUCHUP = False self.config.TOUCHUP = False
elif self.config.TOUCHUP is _default: elif isinstance(self.config.TOUCHUP, Default):
self.config.TOUCHUP = True self.config.TOUCHUP = True
# Setup routers # Setup routers

View File

@@ -7,7 +7,7 @@ from urllib.parse import quote
from sanic.compat import Header from sanic.compat import Header
from sanic.exceptions import ServerError from sanic.exceptions import ServerError
from sanic.helpers import _default from sanic.helpers import Default
from sanic.http import Stage from sanic.http import Stage
from sanic.log import logger from sanic.log import logger
from sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport from sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport
@@ -61,7 +61,7 @@ class Lifespan:
await self.asgi_app.sanic_app._server_event("init", "before") await self.asgi_app.sanic_app._server_event("init", "before")
await self.asgi_app.sanic_app._server_event("init", "after") await self.asgi_app.sanic_app._server_event("init", "after")
if self.asgi_app.sanic_app.config.USE_UVLOOP is not _default: if not isinstance(self.asgi_app.sanic_app.config.USE_UVLOOP, Default):
warnings.warn( warnings.warn(
"You have set the USE_UVLOOP configuration option, but Sanic " "You have set the USE_UVLOOP configuration option, but Sanic "
"cannot control the event loop when running in ASGI mode." "cannot control the event loop when running in ASGI mode."

View File

@@ -199,7 +199,7 @@ class Config(dict, metaclass=DescriptorMeta):
@property @property
def FALLBACK_ERROR_FORMAT(self) -> str: def FALLBACK_ERROR_FORMAT(self) -> str:
if self._FALLBACK_ERROR_FORMAT is _default: if isinstance(self._FALLBACK_ERROR_FORMAT, Default):
return DEFAULT_FORMAT return DEFAULT_FORMAT
return self._FALLBACK_ERROR_FORMAT return self._FALLBACK_ERROR_FORMAT
@@ -207,7 +207,7 @@ class Config(dict, metaclass=DescriptorMeta):
def FALLBACK_ERROR_FORMAT(self, value): def FALLBACK_ERROR_FORMAT(self, value):
self._check_error_format(value) self._check_error_format(value)
if ( if (
self._FALLBACK_ERROR_FORMAT is not _default not isinstance(self._FALLBACK_ERROR_FORMAT, Default)
and value != self._FALLBACK_ERROR_FORMAT and value != self._FALLBACK_ERROR_FORMAT
): ):
error_logger.warning( error_logger.warning(

View File

@@ -72,7 +72,8 @@ def get_ssl_context(
"without passing a TLS certificate. If you are developing " "without passing a TLS certificate. If you are developing "
"locally, please enable DEVELOPMENT mode and Sanic will " "locally, please enable DEVELOPMENT mode and Sanic will "
"generate a localhost TLS certificate. For more information " "generate a localhost TLS certificate. For more information "
"please see: ___." "please see: https://sanic.dev/en/guide/deployment/development."
"html#automatic-tls-certificate."
) )
creator = CertCreator.select( creator = CertCreator.select(
@@ -151,7 +152,8 @@ class CertCreator(ABC):
raise SanicException( raise SanicException(
"Sanic could not find package to create a TLS certificate. " "Sanic could not find package to create a TLS certificate. "
"You must have either mkcert or trustme installed. See " "You must have either mkcert or trustme installed. See "
"_____ for more details." "https://sanic.dev/en/guide/deployment/development.html"
"#automatic-tls-certificate for more details."
) )
return creator return creator
@@ -203,7 +205,8 @@ class MkcertCreator(CertCreator):
"to proceed. Installation instructions can be found here: " "to proceed. Installation instructions can be found here: "
"https://github.com/FiloSottile/mkcert.\n" "https://github.com/FiloSottile/mkcert.\n"
"Find out more information about your options here: " "Find out more information about your options here: "
"_____" "https://sanic.dev/en/guide/deployment/development.html#"
"automatic-tls-certificate"
) from e ) from e
def generate_cert(self, localhost: str) -> ssl.SSLContext: def generate_cert(self, localhost: str) -> ssl.SSLContext:
@@ -260,7 +263,8 @@ class TrustmeCreator(CertCreator):
"to proceed. Installation instructions can be found here: " "to proceed. Installation instructions can be found here: "
"https://github.com/python-trio/trustme.\n" "https://github.com/python-trio/trustme.\n"
"Find out more information about your options here: " "Find out more information about your options here: "
"_____" "https://sanic.dev/en/guide/deployment/development.html#"
"automatic-tls-certificate"
) )
def generate_cert(self, localhost: str) -> ssl.SSLContext: def generate_cert(self, localhost: str) -> ssl.SSLContext:

View File

@@ -41,7 +41,7 @@ from sanic.application.motd import MOTD
from sanic.application.state import ApplicationServerInfo, Mode, ServerStage from sanic.application.state import ApplicationServerInfo, Mode, ServerStage
from sanic.base.meta import SanicMeta from sanic.base.meta import SanicMeta
from sanic.compat import OS_IS_WINDOWS, is_atty from sanic.compat import OS_IS_WINDOWS, is_atty
from sanic.helpers import _default from sanic.helpers import Default
from sanic.http.constants import HTTP from sanic.http.constants import HTTP
from sanic.http.tls import get_ssl_context, process_to_context from sanic.http.tls import get_ssl_context, process_to_context
from sanic.http.tls.context import SanicSSLContext from sanic.http.tls.context import SanicSSLContext
@@ -91,7 +91,8 @@ class StartupMixin(metaclass=SanicMeta):
def setup_loop(self): def setup_loop(self):
if not self.asgi: if not self.asgi:
if self.config.USE_UVLOOP is True or ( if self.config.USE_UVLOOP is True or (
self.config.USE_UVLOOP is _default and not OS_IS_WINDOWS isinstance(self.config.USE_UVLOOP, Default)
and not OS_IS_WINDOWS
): ):
try_use_uvloop() try_use_uvloop()
elif OS_IS_WINDOWS: elif OS_IS_WINDOWS:
@@ -431,7 +432,7 @@ class StartupMixin(metaclass=SanicMeta):
run_async=return_asyncio_server, run_async=return_asyncio_server,
) )
if self.config.USE_UVLOOP is not _default: if not isinstance(self.config.USE_UVLOOP, Default):
error_logger.warning( error_logger.warning(
"You are trying to change the uvloop configuration, but " "You are trying to change the uvloop configuration, but "
"this is only effective when using the run(...) method. " "this is only effective when using the run(...) method. "
@@ -733,8 +734,7 @@ class StartupMixin(metaclass=SanicMeta):
except IndexError: except IndexError:
raise RuntimeError( raise RuntimeError(
f"No server information found for {primary.name}. Perhaps you " f"No server information found for {primary.name}. Perhaps you "
"need to run app.prepare(...)?\n" "need to run app.prepare(...)?"
"See ____ for more information."
) from None ) from None
socks = [] socks = []

View File

@@ -113,13 +113,16 @@ def configure_socket(
backlog=backlog, backlog=backlog,
) )
except OSError as e: # no cov except OSError as e: # no cov
raise ServerError( error = ServerError(
f"Sanic server could not start: {e}.\n" f"Sanic server could not start: {e}.\n\n"
"This may have happened if you are running Sanic in the " "This may have happened if you are running Sanic in the "
"global scope and not inside of a " "global scope and not inside of a "
'`if __name__ == "__main__"` block. See more information: ' '`if __name__ == "__main__"` block.\n\nSee more information: '
"____." "https://sanic.dev/en/guide/deployment/manager.html#"
) from e "how-sanic-server-starts-processes\n"
)
error.quiet = True
raise error
sock.set_inheritable(True) sock.set_inheritable(True)
server_settings["sock"] = sock server_settings["sock"] = sock
server_settings["host"] = None server_settings["host"] = None

View File

@@ -44,7 +44,9 @@ class SharedContext(SimpleNamespace):
f"{Colors.YELLOW}with type {Colors.PURPLE}{type(value)} " f"{Colors.YELLOW}with type {Colors.PURPLE}{type(value)} "
f"{Colors.YELLOW}was added to shared_ctx. It may not " f"{Colors.YELLOW}was added to shared_ctx. It may not "
"not function as intended. Consider using the regular " "not function as intended. Consider using the regular "
f"ctx. For more information, please see ____.{Colors.END}" f"ctx.\nFor more information, please see https://sanic.dev/en"
"/guide/deployment/manager.html#using-shared-context-between-"
f"worker-processes.{Colors.END}"
) )
@property @property

View File

@@ -5,18 +5,10 @@ import sys
from importlib import import_module from importlib import import_module
from pathlib import Path from pathlib import Path
from typing import ( from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union, cast
TYPE_CHECKING,
Any,
Callable,
Dict,
Optional,
Type,
Union,
cast,
)
from sanic.http.tls.creators import CertCreator, MkcertCreator, TrustmeCreator from sanic.http.tls.context import process_to_context
from sanic.http.tls.creators import MkcertCreator, TrustmeCreator
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -106,21 +98,30 @@ class AppLoader:
class CertLoader: class CertLoader:
_creator_class: Type[CertCreator] _creators = {
"mkcert": MkcertCreator,
"trustme": TrustmeCreator,
}
def __init__(self, ssl_data: Dict[str, Union[str, os.PathLike]]): def __init__(self, ssl_data: Dict[str, Union[str, os.PathLike]]):
creator_name = ssl_data.get("creator") self._ssl_data = ssl_data
if creator_name not in ("mkcert", "trustme"):
creator_name = cast(str, ssl_data.get("creator"))
self._creator_class = self._creators.get(creator_name)
if not creator_name:
return
if not self._creator_class:
raise RuntimeError(f"Unknown certificate creator: {creator_name}") raise RuntimeError(f"Unknown certificate creator: {creator_name}")
elif creator_name == "mkcert":
self._creator_class = MkcertCreator
elif creator_name == "trustme":
self._creator_class = TrustmeCreator
self._key = ssl_data["key"] self._key = ssl_data["key"]
self._cert = ssl_data["cert"] self._cert = ssl_data["cert"]
self._localhost = cast(str, ssl_data["localhost"]) self._localhost = cast(str, ssl_data["localhost"])
def load(self, app: SanicApp): def load(self, app: SanicApp):
if not self._creator_class:
return process_to_context(self._ssl_data)
creator = self._creator_class(app, self._key, self._cert) creator = self._creator_class(app, self._key, self._cert)
return creator.generate_cert(self._localhost) return creator.generate_cert(self._localhost)

View File

@@ -9,6 +9,7 @@ from multiprocessing.connection import Connection
from pathlib import Path from pathlib import Path
from signal import SIGINT, SIGTERM from signal import SIGINT, SIGTERM
from signal import signal as signal_func from signal import signal as signal_func
from time import sleep
from typing import Dict, Set from typing import Dict, Set
from sanic.server.events import trigger_events from sanic.server.events import trigger_events
@@ -62,6 +63,7 @@ class Reloader:
self.reload(",".join(changed) if changed else "unknown") self.reload(",".join(changed) if changed else "unknown")
if after_trigger: if after_trigger:
trigger_events(after_trigger, loop, app) trigger_events(after_trigger, loop, app)
sleep(self.interval)
else: else:
if reloader_stop: if reloader_stop:
trigger_events(reloader_stop, loop, app) trigger_events(reloader_stop, loop, app)

View File

@@ -94,8 +94,8 @@ requirements = [
] ]
tests_require = [ tests_require = [
"sanic-testing>=22.9.0b2", "sanic-testing>=22.9.0",
"pytest", "pytest==7.1.*",
"coverage", "coverage",
"beautifulsoup4", "beautifulsoup4",
"pytest-sanic", "pytest-sanic",

View File

@@ -15,7 +15,7 @@ from sanic import Sanic
from sanic.compat import OS_IS_WINDOWS from sanic.compat import OS_IS_WINDOWS
from sanic.config import Config from sanic.config import Config
from sanic.exceptions import SanicException from sanic.exceptions import SanicException
from sanic.helpers import _default from sanic.helpers import Default
from sanic.log import LOGGING_CONFIG_DEFAULTS from sanic.log import LOGGING_CONFIG_DEFAULTS
from sanic.response import text from sanic.response import text
from sanic.router import Route from sanic.router import Route
@@ -347,7 +347,13 @@ def test_app_registry_retrieval_from_multiple():
def test_get_app_does_not_exist(): def test_get_app_does_not_exist():
with pytest.raises( with pytest.raises(
SanicException, match='Sanic app name "does-not-exist" not found.' SanicException,
match="Sanic app name 'does-not-exist' not found.\n"
"App instantiation must occur outside "
"if __name__ == '__main__' "
"block or by using an AppLoader.\nSee "
"https://sanic.dev/en/guide/deployment/app-loader.html"
" for more details."
): ):
Sanic.get_app("does-not-exist") Sanic.get_app("does-not-exist")
@@ -491,7 +497,9 @@ def test_uvloop_cannot_never_called_with_create_server(caplog, monkeypatch):
) )
counter = Counter([(r[1], r[2]) for r in caplog.record_tuples]) counter = Counter([(r[1], r[2]) for r in caplog.record_tuples])
modified = sum(1 for app in apps if app.config.USE_UVLOOP is not _default) modified = sum(
1 for app in apps if not isinstance(app.config.USE_UVLOOP, Default)
)
assert counter[(logging.WARNING, message)] == modified assert counter[(logging.WARNING, message)] == modified

View File

@@ -323,3 +323,20 @@ def test_bp_group_properties():
assert "api/v1/grouped/bp2/" in routes assert "api/v1/grouped/bp2/" in routes
assert "api/v1/primary/grouped/bp1" in routes assert "api/v1/primary/grouped/bp1" in routes
assert "api/v1/primary/grouped/bp2" in routes assert "api/v1/primary/grouped/bp2" in routes
def test_nested_bp_group_properties():
one = Blueprint("one", url_prefix="/one")
two = Blueprint.group(one)
three = Blueprint.group(two, url_prefix="/three")
@one.route("/four")
def handler(request):
return text("pi")
app = Sanic("PropTest")
app.blueprint(three)
app.router.finalize()
routes = [route.path for route in app.router.routes]
assert routes == ["three/one/four"]

View File

@@ -4,6 +4,7 @@ import ssl
import subprocess import subprocess
from contextlib import contextmanager from contextlib import contextmanager
from multiprocessing import Event
from pathlib import Path from pathlib import Path
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from urllib.parse import urlparse from urllib.parse import urlparse
@@ -636,3 +637,29 @@ def test_sanic_ssl_context_create():
assert sanic_context is context assert sanic_context is context
assert isinstance(sanic_context, SanicSSLContext) assert isinstance(sanic_context, SanicSSLContext)
def test_ssl_in_multiprocess_mode(app: Sanic, caplog):
ssl_dict = {"cert": localhost_cert, "key": localhost_key}
event = Event()
@app.main_process_start
async def main_start(app: Sanic):
app.shared_ctx.event = event
@app.after_server_start
async def shutdown(app):
app.shared_ctx.event.set()
app.stop()
assert not event.is_set()
with caplog.at_level(logging.INFO):
app.run(ssl=ssl_dict)
assert event.is_set()
assert (
"sanic.root",
logging.INFO,
"Goin' Fast @ https://127.0.0.1:8000",
) in caplog.record_tuples

View File

@@ -86,6 +86,10 @@ def test_input_is_module():
@patch("sanic.worker.loader.TrustmeCreator") @patch("sanic.worker.loader.TrustmeCreator")
@patch("sanic.worker.loader.MkcertCreator") @patch("sanic.worker.loader.MkcertCreator")
def test_cert_loader(MkcertCreator: Mock, TrustmeCreator: Mock, creator: str): def test_cert_loader(MkcertCreator: Mock, TrustmeCreator: Mock, creator: str):
CertLoader._creators = {
"mkcert": MkcertCreator,
"trustme": TrustmeCreator,
}
MkcertCreator.return_value = MkcertCreator MkcertCreator.return_value = MkcertCreator
TrustmeCreator.return_value = TrustmeCreator TrustmeCreator.return_value = TrustmeCreator
data = { data = {