Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V24.12 #265

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, "3.10", "3.11"]
python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools<60.0", "wheel"]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[tool.ruff]
Expand Down
21 changes: 13 additions & 8 deletions sanic_ext/bootstrap.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from __future__ import annotations

import os

from types import SimpleNamespace
from typing import Any, Callable, Dict, List, Mapping, Optional, Type, Union
from typing import Any, Callable, Dict, List, Optional, Type, Union
from collections.abc import Mapping
from warnings import warn

from sanic import Sanic, __version__
Expand Down Expand Up @@ -40,7 +43,7 @@


class Extend:
_pre_registry: List[Union[Type[Extension], Extension]] = []
_pre_registry: list[Union[type[Extension], Extension]] = []

if TEMPLATING_ENABLED:
environment: Environment
Expand All @@ -50,9 +53,9 @@ def __init__(
self,
app: Sanic,
*,
extensions: Optional[List[Union[Type[Extension], Extension]]] = None,
extensions: Optional[list[Union[type[Extension], Extension]]] = None,
built_in_extensions: bool = True,
config: Optional[Union[Config, Dict[str, Any]]] = None,
config: Optional[Union[Config, dict[str, Any]]] = None,
**kwargs,
) -> None:
"""
Expand All @@ -79,7 +82,7 @@ def __init__(
self._constant_registry: Optional[ConstantRegistry] = None
self._openapi: Optional[SpecificationBuilder] = None
self.app = app
self.extensions: List[Extension] = []
self.extensions: list[Extension] = []
self.sanic_version = sanic_version
app._ext = self
app.ctx._dependencies = SimpleNamespace()
Expand Down Expand Up @@ -114,6 +117,8 @@ def __init__(
started.add(ext)

def _display(self):
if "SANIC_WORKER_IDENTIFIER" in os.environ:
return
init_logs = ["Sanic Extensions:"]
for extension in self.extensions:
label = extension.render_label()
Expand All @@ -124,7 +129,7 @@ def _display(self):

def injection(
self,
type: Type,
type: type,
constructor: Optional[Callable[..., Any]] = None,
) -> None:
warn(
Expand All @@ -136,7 +141,7 @@ def injection(

def add_dependency(
self,
type: Type,
type: type,
constructor: Optional[Callable[..., Any]] = None,
request_arg: Optional[str] = None,
) -> None:
Expand Down Expand Up @@ -211,7 +216,7 @@ def template(self, template_name: str, **kwargs):
return self.templating.template(template_name, **kwargs)

@classmethod
def register(cls, extension: Union[Type[Extension], Extension]) -> None:
def register(cls, extension: Union[type[Extension], Extension]) -> None:
cls._pre_registry.append(extension)

@classmethod
Expand Down
15 changes: 11 additions & 4 deletions sanic_ext/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import os

from typing import Any, Dict, List, Optional, Sequence, Union
from typing import Any, Dict, List, Optional, Union
from collections.abc import Sequence

from sanic import Sanic
from sanic.config import Config as SanicConfig
Expand All @@ -23,7 +24,7 @@ def __init__(
cors_expose_headers: str = "",
cors_max_age: int = 5,
cors_methods: str = "",
cors_origins: Union[str, List[str]] = "",
cors_origins: Union[str, list[str]] = "",
cors_send_wildcard: bool = False,
cors_supports_credentials: bool = False,
cors_vary_header: bool = True,
Expand All @@ -44,7 +45,13 @@ def __init__(
injection_load_custom_constants: bool = False,
logging: bool = False,
logging_queue_max_size: int = 4096,
loggers: List[str] = ["sanic.access", "sanic.error", "sanic.root"],
loggers: list[str] = [
"sanic.access",
"sanic.error",
"sanic.root",
"sanic.server",
"sanic.websockets",
],
oas: bool = True,
oas_autodoc: bool = True,
oas_custom_file: Optional[os.PathLike] = None,
Expand All @@ -66,7 +73,7 @@ def __init__(
oas_uri_to_redoc: str = "/redoc",
oas_uri_to_swagger: str = "/swagger",
oas_url_prefix: str = "/docs",
swagger_ui_configuration: Optional[Dict[str, Any]] = None,
swagger_ui_configuration: Optional[dict[str, Any]] = None,
templating_path_to_templates: Union[
str, os.PathLike, Sequence[Union[str, os.PathLike]]
] = "templates",
Expand Down
6 changes: 2 additions & 4 deletions sanic_ext/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ class ValidationError(SanicException):
status_code = 400


class InitError(SanicException):
...
class InitError(SanicException): ...


class ExtensionNotFound(SanicException):
...
class ExtensionNotFound(SanicException): ...
7 changes: 3 additions & 4 deletions sanic_ext/extensions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def __setitem__(self, key: Any, value: Any) -> None:


class Extension(ABC):
_name_registry: Dict[str, Type[Extension]] = NoDuplicateDict()
_name_registry: dict[str, type[Extension]] = NoDuplicateDict()
_started: bool
name: str
app: Sanic
Expand Down Expand Up @@ -46,8 +46,7 @@ def _startup(self, bootstrap):
self._started = True

@abstractmethod
def startup(self, bootstrap) -> None:
...
def startup(self, bootstrap) -> None: ...

def label(self):
return ""
Expand All @@ -66,7 +65,7 @@ def included(self):
@classmethod
def create(
cls,
extension: Union[Type[Extension], Extension],
extension: Union[type[Extension], Extension],
app: Sanic,
config: Config,
) -> Extension:
Expand Down
3 changes: 1 addition & 2 deletions sanic_ext/extensions/health/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
from sanic import Sanic


class Stale(ValueError):
...
class Stale(ValueError): ...


@dataclass
Expand Down
36 changes: 18 additions & 18 deletions sanic_ext/extensions/http/cors.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@

@dataclass(frozen=True)
class CORSSettings:
allow_headers: FrozenSet[str]
allow_methods: FrozenSet[str]
allow_origins: Tuple[re.Pattern, ...]
allow_headers: frozenset[str]
allow_methods: frozenset[str]
allow_origins: tuple[re.Pattern, ...]
always_send: bool
automatic_options: bool
expose_headers: FrozenSet[str]
expose_headers: frozenset[str]
max_age: str
send_wildcard: bool
supports_credentials: bool
Expand Down Expand Up @@ -86,9 +86,9 @@ async def _assign_cors_settings(app, _):
def cors(
*,
origin: Union[str, Default] = _default,
expose_headers: Union[List[str], Default] = _default,
allow_headers: Union[List[str], Default] = _default,
allow_methods: Union[List[str], Default] = _default,
expose_headers: Union[list[str], Default] = _default,
allow_headers: Union[list[str], Default] = _default,
allow_methods: Union[list[str], Default] = _default,
supports_credentials: Union[bool, Default] = _default,
max_age: Union[str, int, timedelta, Default] = _default,
):
Expand Down Expand Up @@ -227,10 +227,10 @@ def _add_credentials_header(request: Request, response: HTTPResponse) -> None:

def _add_allow_header(request: Request, response: HTTPResponse) -> None:
with_credentials = _is_request_with_credentials(request)
request_headers = set(
request_headers = {
h.strip().lower()
for h in request.headers.get(REQUEST_HEADERS_HEADER, "").split(",")
)
}
allow_headers = _get_from_cors_ctx(
request, "_cors_allow_headers", request.app.ctx.cors.allow_headers
)
Expand Down Expand Up @@ -297,16 +297,16 @@ def _add_vary_header(request: Request, response: HTTPResponse) -> None:
response.headers[VARY_HEADER] = "origin"


def _get_allow_origins(app: Sanic) -> Tuple[re.Pattern, ...]:
def _get_allow_origins(app: Sanic) -> tuple[re.Pattern, ...]:
origins = app.config.CORS_ORIGINS
return _parse_allow_origins(origins)


def _parse_allow_origins(
value: Union[str, re.Pattern, List[Union[str, re.Pattern]]],
) -> Tuple[re.Pattern, ...]:
value: Union[str, re.Pattern, list[Union[str, re.Pattern]]],
) -> tuple[re.Pattern, ...]:
origins: Optional[
Union[List[str], List[re.Pattern], List[Union[str, re.Pattern]]]
Union[list[str], list[re.Pattern], list[Union[str, re.Pattern]]]
] = None
if value and isinstance(value, str):
if value == "*":
Expand All @@ -326,7 +326,7 @@ def _parse_allow_origins(
)


def _get_expose_headers(app: Sanic) -> FrozenSet[str]:
def _get_expose_headers(app: Sanic) -> frozenset[str]:
expose_headers = (
(
app.config.CORS_EXPOSE_HEADERS
Expand All @@ -341,11 +341,11 @@ def _get_expose_headers(app: Sanic) -> FrozenSet[str]:
return frozenset(header.lower() for header in expose_headers)


def _get_allow_headers(app: Sanic) -> FrozenSet[str]:
def _get_allow_headers(app: Sanic) -> frozenset[str]:
return _parse_allow_headers(app.config.CORS_ALLOW_HEADERS)


def _parse_allow_headers(value: str) -> FrozenSet[str]:
def _parse_allow_headers(value: str) -> frozenset[str]:
allow_headers = (
(
value
Expand All @@ -372,11 +372,11 @@ def _parse_max_age(value) -> str:
return str(max_age)


def _get_allow_methods(app: Sanic) -> FrozenSet[str]:
def _get_allow_methods(app: Sanic) -> frozenset[str]:
return _parse_allow_methods(app.config.CORS_METHODS)


def _parse_allow_methods(value) -> FrozenSet[str]:
def _parse_allow_methods(value) -> frozenset[str]:
allow_methods = (
(
value
Expand Down
3 changes: 2 additions & 1 deletion sanic_ext/extensions/http/methods.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from functools import partial
from inspect import isawaitable
from operator import itemgetter
from typing import Sequence, Union
from typing import Union
from collections.abc import Sequence

from sanic import Sanic
from sanic.constants import HTTPMethod
Expand Down
22 changes: 11 additions & 11 deletions sanic_ext/extensions/injection/constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def __init__(
self, func: Callable[..., Any], request_arg: Optional[str] = None
):
self.func = func
self.injections: Dict[str, Tuple[Type, Constructor]] = {}
self.constants: Dict[str, Any] = {}
self.injections: dict[str, tuple[type, Constructor]] = {}
self.constants: dict[str, Any] = {}
self.pass_kwargs: bool = False
self.request_arg = request_arg

Expand Down Expand Up @@ -77,7 +77,7 @@ def prepare(
app: Sanic,
injection_registry: InjectionRegistry,
constant_registry: ConstantRegistry,
allowed_types: Set[Type[object]],
allowed_types: set[type[object]],
) -> None:
hints = self._get_hints()
hints.pop("return", None)
Expand Down Expand Up @@ -118,25 +118,25 @@ def prepare(
"html#injecting-services for more details."
)

checked: Set[Type[object]] = set()
current: Set[Type[object]] = set()
checked: set[type[object]] = set()
current: set[type[object]] = set()
self.check_circular(checked, current)

def check_circular(
self,
checked: Set[Type[object]],
current: Set[Type[object]],
checked: set[type[object]],
current: set[type[object]],
) -> None:
dependencies = set(self.injections.values())
for dependency, constructor in dependencies:
self._visit(dependency, constructor, checked, current)

def _visit(
self,
dependency: Type[object],
dependency: type[object],
constructor: Constructor,
checked: Set[Type[object]],
current: Set[Type[object]],
checked: set[type[object]],
current: set[type[object]],
):
if dependency in checked:
return
Expand Down Expand Up @@ -167,7 +167,7 @@ def _get_hints(self):
raise InitError(f"Cannot get type hints for {self.func}")


async def gather_args(injections, request, **kwargs) -> Dict[str, Any]:
async def gather_args(injections, request, **kwargs) -> dict[str, Any]:
return {
name: await do_cast(_type, constructor, request, **kwargs)
for name, (_type, constructor) in injections.items()
Expand Down
10 changes: 5 additions & 5 deletions sanic_ext/extensions/injection/injector.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ def add_injection(

@app.listener("before_server_start", priority=PRIORITY)
async def finalize_injections(app: Sanic, _):
router_converters = set(
router_converters = {
allowed[0] for allowed in app.router.regex_types.values()
)
}
router_types = set()
for converter in router_converters:
if isclass(converter):
Expand Down Expand Up @@ -105,10 +105,10 @@ async def setup_signatures(app, _):
except TypeError:
continue

dependencies: Dict[
str, Tuple[Type, Optional[Callable[..., Any]]]
dependencies: dict[
str, tuple[type, Optional[Callable[..., Any]]]
] = {}
constants: Dict[str, Any] = {}
constants: dict[str, Any] = {}
for param, annotation in hints.items():
if annotation in injection_registry:
dependencies[param] = (
Expand Down
Loading
Loading