diff --git a/sanic_ext/bootstrap.py b/sanic_ext/bootstrap.py index 6e20d16..cc3f3d8 100644 --- a/sanic_ext/bootstrap.py +++ b/sanic_ext/bootstrap.py @@ -3,7 +3,8 @@ 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__ @@ -42,7 +43,7 @@ class Extend: - _pre_registry: List[Union[Type[Extension], Extension]] = [] + _pre_registry: list[Union[type[Extension], Extension]] = [] if TEMPLATING_ENABLED: environment: Environment @@ -52,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: """ @@ -81,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() @@ -128,7 +129,7 @@ def _display(self): def injection( self, - type: Type, + type: type, constructor: Optional[Callable[..., Any]] = None, ) -> None: warn( @@ -140,7 +141,7 @@ def injection( def add_dependency( self, - type: Type, + type: type, constructor: Optional[Callable[..., Any]] = None, request_arg: Optional[str] = None, ) -> None: @@ -215,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 diff --git a/sanic_ext/config.py b/sanic_ext/config.py index ba4a5cc..550076e 100644 --- a/sanic_ext/config.py +++ b/sanic_ext/config.py @@ -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 @@ -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, @@ -44,7 +45,7 @@ def __init__( injection_load_custom_constants: bool = False, logging: bool = False, logging_queue_max_size: int = 4096, - loggers: List[str] = [ + loggers: list[str] = [ "sanic.access", "sanic.error", "sanic.root", @@ -72,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", diff --git a/sanic_ext/extensions/base.py b/sanic_ext/extensions/base.py index e5bf922..a825f8d 100644 --- a/sanic_ext/extensions/base.py +++ b/sanic_ext/extensions/base.py @@ -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 @@ -65,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: diff --git a/sanic_ext/extensions/http/cors.py b/sanic_ext/extensions/http/cors.py index 3346945..b60427e 100644 --- a/sanic_ext/extensions/http/cors.py +++ b/sanic_ext/extensions/http/cors.py @@ -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 @@ -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, ): @@ -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 ) @@ -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 == "*": @@ -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 @@ -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 @@ -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 diff --git a/sanic_ext/extensions/http/methods.py b/sanic_ext/extensions/http/methods.py index 8976e49..cc03013 100644 --- a/sanic_ext/extensions/http/methods.py +++ b/sanic_ext/extensions/http/methods.py @@ -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 diff --git a/sanic_ext/extensions/injection/constructor.py b/sanic_ext/extensions/injection/constructor.py index a996717..dcbc970 100644 --- a/sanic_ext/extensions/injection/constructor.py +++ b/sanic_ext/extensions/injection/constructor.py @@ -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 @@ -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) @@ -118,14 +118,14 @@ 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: @@ -133,10 +133,10 @@ def check_circular( 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 @@ -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() diff --git a/sanic_ext/extensions/injection/injector.py b/sanic_ext/extensions/injection/injector.py index 224bb95..ed6c9e4 100644 --- a/sanic_ext/extensions/injection/injector.py +++ b/sanic_ext/extensions/injection/injector.py @@ -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): @@ -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] = ( diff --git a/sanic_ext/extensions/injection/registry.py b/sanic_ext/extensions/injection/registry.py index ec6029c..3f0888a 100644 --- a/sanic_ext/extensions/injection/registry.py +++ b/sanic_ext/extensions/injection/registry.py @@ -10,7 +10,7 @@ class InjectionRegistry: def __init__(self): - self._registry: Dict[Type, Optional[Callable[..., Any]]] = {} + self._registry: dict[type, Optional[Callable[..., Any]]] = {} def __getitem__(self, key): return self._registry[key] @@ -26,7 +26,7 @@ def get(self, key, default=None): def register( self, - _type: Type, + _type: type, constructor: Optional[Callable[..., Any]], request_arg: Optional[str] = None, ) -> None: @@ -50,11 +50,11 @@ def length(self): class SignatureRegistry: def __init__(self): - self._registry: Dict[ + self._registry: dict[ str, - Tuple[ - Dict[str, Tuple[Type, Optional[Callable[..., Any]]]], - Dict[str, Any], + tuple[ + dict[str, tuple[type, Optional[Callable[..., Any]]]], + dict[str, Any], ], ] = {} @@ -70,8 +70,8 @@ def get(self, key, default=None): def register( self, route_name: str, - dependencies: Dict[str, Tuple[Type, Optional[Callable[..., Any]]]], - constants: Optional[Dict[str, Any]] = None, + dependencies: dict[str, tuple[type, Optional[Callable[..., Any]]]], + constants: Optional[dict[str, Any]] = None, ) -> None: self._registry[route_name] = (dependencies, constants or {}) @@ -79,7 +79,7 @@ def register( class ConstantRegistry: def __init__(self, config: Config): self._config = config - self._registry: Set[str] = set() + self._registry: set[str] = set() def __str__(self) -> str: return str(self._registry) diff --git a/sanic_ext/extensions/logging/extractor.py b/sanic_ext/extensions/logging/extractor.py index 9de958a..a25ec82 100644 --- a/sanic_ext/extensions/logging/extractor.py +++ b/sanic_ext/extensions/logging/extractor.py @@ -25,18 +25,18 @@ class FormatterConfig(TypedDict): class LoggingConfig(TypedDict): version: int disable_existing_loggers: bool - formatters: Dict[str, FormatterConfig] - handlers: Dict[str, HandlerConfig] - loggers: Dict[str, LoggerConfig] + formatters: dict[str, FormatterConfig] + handlers: dict[str, HandlerConfig] + loggers: dict[str, LoggerConfig] class LoggingConfigExtractor: def __init__(self): self.version = 1 self.disable_existing_loggers = False - self.formatters: Dict[str, FormatterConfig] = {} - self.handlers: Dict[str, HandlerConfig] = {} - self.loggers: Dict[str, LoggerConfig] = {} + self.formatters: dict[str, FormatterConfig] = {} + self.handlers: dict[str, HandlerConfig] = {} + self.loggers: dict[str, LoggerConfig] = {} def add_logger(self, logger: logging.Logger): self._extract_logger_config(logger) @@ -97,7 +97,7 @@ def _extract_formatter_config(self, formatter: logging.Formatter): } self.formatters[formatter_name] = config - def _clean(self, d: Dict[str, Any]) -> Dict[str, Any]: + def _clean(self, d: dict[str, Any]) -> dict[str, Any]: return { k.replace("class_", "class"): self._clean(v) if isinstance(v, dict) diff --git a/sanic_ext/extensions/logging/logger.py b/sanic_ext/extensions/logging/logger.py index 6cc1b0b..6f8cd7a 100644 --- a/sanic_ext/extensions/logging/logger.py +++ b/sanic_ext/extensions/logging/logger.py @@ -69,7 +69,7 @@ async def remove_server_logging(app: Sanic): class Logger: - LOGGERS: List[str] = [] + LOGGERS: list[str] = [] def __init__(self): self.run = True @@ -108,7 +108,7 @@ def stop(self, *_): self.run = False @classmethod - def update_cls_loggers(cls, logger_names: List[str]): + def update_cls_loggers(cls, logger_names: list[str]): cls.LOGGERS = logger_names @classmethod diff --git a/sanic_ext/extensions/openapi/autodoc.py b/sanic_ext/extensions/openapi/autodoc.py index cf7fe3a..68a7c2f 100644 --- a/sanic_ext/extensions/openapi/autodoc.py +++ b/sanic_ext/extensions/openapi/autodoc.py @@ -74,7 +74,7 @@ def _parse_yaml(self, doc: str) -> dict: return yaml.safe_load(doc) except Exception as e: warnings.warn( - "error parsing openAPI yaml, ignoring it. ({})".format(e) + f"error parsing openAPI yaml, ignoring it. ({e})" ) return {} diff --git a/sanic_ext/extensions/openapi/blueprint.py b/sanic_ext/extensions/openapi/blueprint.py index 89f8609..f20a5f0 100644 --- a/sanic_ext/extensions/openapi/blueprint.py +++ b/sanic_ext/extensions/openapi/blueprint.py @@ -53,7 +53,7 @@ def blueprint_factory(config: Config): custom_css = getattr(config, f"OAS_UI_{ui}_CUSTOM_CSS".upper()) html_path = path if path else f"{dir_path}/{ui}.html" - with open(html_path, "r") as f: + with open(html_path) as f: page = f.read() def index( @@ -185,10 +185,8 @@ def build_spec(app, loop): for _parameter in route_parameters: if any( - ( param.fields["name"] == _parameter.name for param in operation.parameters - ) ): continue diff --git a/sanic_ext/extensions/openapi/builders.py b/sanic_ext/extensions/openapi/builders.py index dae7d02..0680921 100644 --- a/sanic_ext/extensions/openapi/builders.py +++ b/sanic_ext/extensions/openapi/builders.py @@ -1,7 +1,8 @@ from __future__ import annotations from collections import defaultdict -from typing import TYPE_CHECKING, Optional, Sequence, Union, cast +from typing import TYPE_CHECKING, Optional, Union, cast +from collections.abc import Sequence from sanic_ext.extensions.openapi.constants import ( SecuritySchemeAuthorization, diff --git a/sanic_ext/extensions/openapi/definitions.py b/sanic_ext/extensions/openapi/definitions.py index 0b93fa4..cdf37d5 100644 --- a/sanic_ext/extensions/openapi/definitions.py +++ b/sanic_ext/extensions/openapi/definitions.py @@ -34,7 +34,7 @@ class Reference(Schema): def __init__(self, value): super().__init__(**{"$ref": value}) - def guard(self, fields: Dict[str, Any]): + def guard(self, fields: dict[str, Any]): return fields @@ -86,7 +86,7 @@ class MediaType(Definition): schema: Schema example: Any - def __init__(self, schema: Union[Schema, Dict[str, Any]], **kwargs): + def __init__(self, schema: Union[Schema, dict[str, Any]], **kwargs): if isinstance(schema, dict) and contains_annotations(schema): schema = Schema.make(schema) super().__init__(schema=schema, **kwargs) @@ -117,7 +117,7 @@ def all(content: Any): class Response(Definition): - content: Union[Any, Dict[str, Union[Any, MediaType]]] + content: Union[Any, dict[str, Union[Any, MediaType]]] description: Optional[str] status: Union[Literal["default"], int] @@ -126,7 +126,7 @@ class Response(Definition): def __init__( self, - content: Optional[Union[Any, Dict[str, Union[Any, MediaType]]]] = None, + content: Optional[Union[Any, dict[str, Union[Any, MediaType]]]] = None, status: Union[Literal["default"], int] = "default", description: Optional[str] = None, **kwargs, @@ -151,13 +151,13 @@ def make(content, description: Optional[str] = None, **kwargs): class RequestBody(Definition): description: Optional[str] required: Optional[bool] - content: Union[Any, Dict[str, Union[Any, MediaType]]] + content: Union[Any, dict[str, Union[Any, MediaType]]] __nullable__ = None def __init__( self, - content: Union[Any, Dict[str, Union[Any, MediaType]]], + content: Union[Any, dict[str, Union[Any, MediaType]]], required: Optional[bool] = None, description: Optional[str] = None, **kwargs, @@ -209,7 +209,7 @@ def make(url: str, description: Optional[str] = None): class Parameter(Definition): name: str - schema: Union[Type, Schema] + schema: Union[type, Schema] location: str description: Optional[str] required: Optional[bool] @@ -221,7 +221,7 @@ class Parameter(Definition): def __init__( self, name: str, - schema: Union[Type, Schema] = str, + schema: Union[type, Schema] = str, location: str = "query", description: Optional[str] = None, required: Optional[bool] = None, @@ -258,18 +258,18 @@ def make(name: str, schema: type, location: str, **kwargs): class Operation(Definition): - tags: List[str] + tags: list[str] summary: str description: str operationId: str requestBody: RequestBody externalDocs: ExternalDocumentation - parameters: List[Parameter] - responses: Dict[str, Response] - security: Dict[str, List[str]] - callbacks: List[str] # TODO + parameters: list[Parameter] + responses: dict[str, Response] + security: dict[str, list[str]] + callbacks: list[str] # TODO deprecated: bool - servers: List[Dict[str, str]] + servers: list[dict[str, str]] class PathItem(Definition): @@ -289,7 +289,7 @@ class Flow(Definition): authorizationUrl: str tokenUrl: str refreshUrl: str - scopes: Dict[str, str] + scopes: dict[str, str] class Flows(Definition): @@ -301,7 +301,7 @@ class Flows(Definition): class SecurityRequirement(Definition): name: str - value: List[str] + value: list[str] class SecurityScheme(Definition): @@ -329,15 +329,15 @@ def fields(self): return values @staticmethod - def make(_type: str, cls: Type, **kwargs): - params: Dict[str, Any] = getattr(cls, "__dict__", {}) + def make(_type: str, cls: type, **kwargs): + params: dict[str, Any] = getattr(cls, "__dict__", {}) return SecurityScheme(_type, **params, **kwargs) class ServerVariable(Definition): default: str description: str - enum: List[str] + enum: list[str] def __init__(self, default: str, **kwargs): super().__init__(default=default, **kwargs) @@ -346,7 +346,7 @@ def __init__(self, default: str, **kwargs): class Server(Definition): url: str description: str - variables: Dict[str, ServerVariable] + variables: dict[str, ServerVariable] __nullable__ = None @@ -354,7 +354,7 @@ def __init__( self, url: str, description: Optional[str] = None, - variables: Optional[Dict[str, Any]] = None, + variables: Optional[dict[str, Any]] = None, ): super().__init__( url=url, description=description, variables=variables or {} @@ -374,15 +374,15 @@ class Components(Definition): # This class is not being used in sanic-openapi right now, but the # definition is kept here to keep in close accordance with the openapi # spec, in case it is desired to be added later. - schemas: Dict[str, Schema] - responses: Dict[str, Response] - parameters: Dict[str, Parameter] - examples: Dict[str, Example] - requestBodies: Dict[str, RequestBody] - headers: Dict[str, Header] - securitySchemes: Dict[str, SecurityScheme] - links: Dict[str, Schema] # TODO - callbacks: Dict[str, Schema] # TODO + schemas: dict[str, Schema] + responses: dict[str, Response] + parameters: dict[str, Parameter] + examples: dict[str, Example] + requestBodies: dict[str, RequestBody] + headers: dict[str, Header] + securitySchemes: dict[str, SecurityScheme] + links: dict[str, Schema] # TODO + callbacks: dict[str, Schema] # TODO def Component( @@ -446,13 +446,13 @@ def Component( class OpenAPI(Definition): openapi: str info: Info - servers: List[Server] - paths: Dict[str, PathItem] + servers: list[Server] + paths: dict[str, PathItem] components: Components - security: Dict[str, SecurityScheme] - tags: List[Tag] + security: dict[str, SecurityScheme] + tags: list[Tag] externalDocs: ExternalDocumentation - def __init__(self, info: Info, paths: Dict[str, PathItem], **kwargs): + def __init__(self, info: Info, paths: dict[str, PathItem], **kwargs): use = {k: v for k, v in kwargs.items() if v is not None} super().__init__(openapi="3.0.3", info=info, paths=paths, **use) diff --git a/sanic_ext/extensions/openapi/openapi.py b/sanic_ext/extensions/openapi/openapi.py index 8d26cec..cbca7a8 100644 --- a/sanic_ext/extensions/openapi/openapi.py +++ b/sanic_ext/extensions/openapi/openapi.py @@ -13,12 +13,12 @@ List, Literal, Optional, - Sequence, Type, TypeVar, Union, overload, ) +from collections.abc import Sequence from sanic import Blueprint from sanic.exceptions import InvalidUsage, SanicException @@ -262,7 +262,7 @@ def parameter( @overload def parameter( name: str, - schema: Optional[Union[Type, Schema]] = None, + schema: Optional[Union[type, Schema]] = None, location: Optional[str] = None, parameter: None = None, **kwargs, @@ -271,7 +271,7 @@ def parameter( def parameter( name: Optional[str] = None, - schema: Optional[Union[Type, Schema]] = None, + schema: Optional[Union[type, Schema]] = None, location: Optional[str] = None, parameter: Optional[definitions.Parameter] = None, **kwargs, @@ -373,20 +373,20 @@ def definition( ] ] = None, deprecated: bool = False, - body: Optional[Union[Dict[str, Any], definitions.RequestBody, Any]] = None, + body: Optional[Union[dict[str, Any], definitions.RequestBody, Any]] = None, parameter: Optional[ Union[ - Union[Dict[str, Any], definitions.Parameter, str], - List[Union[Dict[str, Any], definitions.Parameter, str]], + Union[dict[str, Any], definitions.Parameter, str], + list[Union[dict[str, Any], definitions.Parameter, str]], ] ] = None, response: Optional[ Union[ - Union[Dict[str, Any], definitions.Response, Any], - List[Union[Dict[str, Any], definitions.Response]], + Union[dict[str, Any], definitions.Response, Any], + list[Union[dict[str, Any], definitions.Response]], ] ] = None, - secured: Optional[Dict[str, Any]] = None, + secured: Optional[dict[str, Any]] = None, validate: bool = False, body_argument: str = "body", ) -> Callable[[T], T]: diff --git a/sanic_ext/extensions/openapi/types.py b/sanic_ext/extensions/openapi/types.py index 008d57d..39da4e6 100644 --- a/sanic_ext/extensions/openapi/types.py +++ b/sanic_ext/extensions/openapi/types.py @@ -63,11 +63,11 @@ class MsgspecAdapter: class Definition: - __nullable__: Optional[List[str]] = [] - __ignore__: Optional[List[str]] = [] + __nullable__: Optional[list[str]] = [] + __ignore__: Optional[list[str]] = [] def __init__(self, **kwargs): - self._fields: Dict[str, Any] = self.guard(kwargs) + self._fields: dict[str, Any] = self.guard(kwargs) @property def fields(self): @@ -115,11 +115,11 @@ class Schema(Definition): required: bool default: None example: None - oneOf: List[Definition] - anyOf: List[Definition] - allOf: List[Definition] + oneOf: list[Definition] + anyOf: list[Definition] + allOf: list[Definition] - additionalProperties: Dict[str, str] + additionalProperties: dict[str, str] multipleOf: int maximum: int exclusiveMaximum: bool @@ -128,7 +128,7 @@ class Schema(Definition): maxLength: int minLength: int pattern: str - enum: Union[List[Any], Enum] + enum: Union[list[Any], Enum] @staticmethod def make(value, **kwargs): @@ -310,12 +310,12 @@ def make(cls, value: Any, **kwargs): class Object(Schema): - properties: Dict[str, Schema] + properties: dict[str, Schema] maxProperties: int minProperties: int def __init__( - self, properties: Optional[Dict[str, Schema]] = None, **kwargs + self, properties: Optional[dict[str, Schema]] = None, **kwargs ): if properties: kwargs["properties"] = properties @@ -323,7 +323,7 @@ def __init__( @classmethod def make(cls, value: Any, **kwargs): - extra: Dict[str, Any] = {} + extra: dict[str, Any] = {} # Extract from field metadata if msgspec, pydantic, attrs, or dataclass if isclass(value): @@ -403,7 +403,7 @@ def _serialize(value) -> Any: return value -def _properties(value: object) -> Dict: +def _properties(value: object) -> dict: try: fields = { x: val diff --git a/sanic_ext/extensions/templating/engine.py b/sanic_ext/extensions/templating/engine.py index 7a93080..69ac844 100644 --- a/sanic_ext/extensions/templating/engine.py +++ b/sanic_ext/extensions/templating/engine.py @@ -28,7 +28,7 @@ def template( self, file_name: str, status: int = 200, - headers: Optional[Union[Header, Dict[str, str]]] = None, + headers: Optional[Union[Header, dict[str, str]]] = None, content_type: str = "text/html; charset=utf-8", **kwargs, ): diff --git a/sanic_ext/extensions/templating/extension.py b/sanic_ext/extensions/templating/extension.py index f27befe..2b4ec92 100644 --- a/sanic_ext/extensions/templating/extension.py +++ b/sanic_ext/extensions/templating/extension.py @@ -4,7 +4,8 @@ from collections import abc from pathlib import Path -from typing import TYPE_CHECKING, Sequence, Union +from typing import TYPE_CHECKING, Union +from collections.abc import Sequence from jinja2 import ( Environment, diff --git a/sanic_ext/extensions/templating/render.py b/sanic_ext/extensions/templating/render.py index ce67066..b327d9d 100644 --- a/sanic_ext/extensions/templating/render.py +++ b/sanic_ext/extensions/templating/render.py @@ -31,9 +31,9 @@ class LazyResponse(TemplateResponse): def __init__( self, - context: Dict[str, Any], + context: dict[str, Any], status: int = 0, - headers: Optional[Union[Header, Dict[str, str]]] = None, + headers: Optional[Union[Header, dict[str, str]]] = None, content_type: Optional[str] = None, ): super().__init__( @@ -45,11 +45,11 @@ def __init__( async def render( template_name: str = "", status: int = 200, - headers: Optional[Dict[str, str]] = None, + headers: Optional[dict[str, str]] = None, content_type: str = "text/html; charset=utf-8", app: Optional[Sanic] = None, environment: Optional[Environment] = None, - context: Optional[Dict[str, Any]] = None, + context: Optional[dict[str, Any]] = None, *, template_source: str = "", ) -> TemplateResponse: diff --git a/sanic_ext/extras/validation/check.py b/sanic_ext/extras/validation/check.py index fb3f9c8..4a465e7 100644 --- a/sanic_ext/extras/validation/check.py +++ b/sanic_ext/extras/validation/check.py @@ -4,7 +4,6 @@ from typing import ( Any, Literal, - Mapping, NamedTuple, Optional, Tuple, @@ -12,6 +11,7 @@ get_args, get_origin, ) +from collections.abc import Mapping from sanic_ext.utils.typing import ( UnionType, @@ -21,7 +21,7 @@ ) -MISSING: Tuple[Any, ...] = (_HAS_DEFAULT_FACTORY,) +MISSING: tuple[Any, ...] = (_HAS_DEFAULT_FACTORY,) try: import attrs # noqa @@ -51,7 +51,7 @@ class Hint(NamedTuple): typed: bool nullable: bool origin: Optional[Any] - allowed: Tuple[Hint, ...] # type: ignore + allowed: tuple[Hint, ...] # type: ignore allow_missing: bool def validate( diff --git a/sanic_ext/extras/validation/clean.py b/sanic_ext/extras/validation/clean.py index e4b39b7..4bcc650 100644 --- a/sanic_ext/extras/validation/clean.py +++ b/sanic_ext/extras/validation/clean.py @@ -1,7 +1,7 @@ from typing import Any, Dict, Type, get_origin, get_type_hints -def clean_data(model: Type[object], data: Dict[str, Any]) -> Dict[str, Any]: +def clean_data(model: type[object], data: dict[str, Any]) -> dict[str, Any]: hints = get_type_hints(model) return {key: _coerce(hints[key], value) for key, value in data.items()} diff --git a/sanic_ext/extras/validation/decorator.py b/sanic_ext/extras/validation/decorator.py index 59e346d..302d99d 100644 --- a/sanic_ext/extras/validation/decorator.py +++ b/sanic_ext/extras/validation/decorator.py @@ -14,9 +14,9 @@ def validate( - json: Optional[Union[Callable[[Request], bool], Type[object]]] = None, - form: Optional[Union[Callable[[Request], bool], Type[object]]] = None, - query: Optional[Union[Callable[[Request], bool], Type[object]]] = None, + json: Optional[Union[Callable[[Request], bool], type[object]]] = None, + form: Optional[Union[Callable[[Request], bool], type[object]]] = None, + query: Optional[Union[Callable[[Request], bool], type[object]]] = None, body_argument: str = "body", query_argument: str = "query", ) -> Callable[[T], T]: diff --git a/sanic_ext/extras/validation/schema.py b/sanic_ext/extras/validation/schema.py index fbc2445..b9a823d 100644 --- a/sanic_ext/extras/validation/schema.py +++ b/sanic_ext/extras/validation/schema.py @@ -70,9 +70,9 @@ def make_schema(agg, item): def parse_hints( - hints, fields: Dict[str, Union[Field, Attribute]] -) -> Dict[str, Hint]: - output: Dict[str, Hint] = { + hints, fields: dict[str, Union[Field, Attribute]] +) -> dict[str, Hint]: + output: dict[str, Hint] = { name: parse_hint(hint, fields.get(name)) for name, hint in hints.items() } @@ -85,7 +85,7 @@ def parse_hint(hint, field: Optional[Union[Field, Attribute]] = None): nullable = False typed = False model = False - allowed: Tuple[Any, ...] = tuple() + allowed: tuple[Any, ...] = tuple() allow_missing = False if field and ( diff --git a/sanic_ext/extras/validation/validators.py b/sanic_ext/extras/validation/validators.py index d04b449..94f8641 100644 --- a/sanic_ext/extras/validation/validators.py +++ b/sanic_ext/extras/validation/validators.py @@ -9,7 +9,7 @@ try: from pydantic import ValidationError as PydanticValidationError - VALIDATION_ERROR: Tuple[Type[Exception], ...] = ( + VALIDATION_ERROR: tuple[type[Exception], ...] = ( TypeError, PydanticValidationError, ) @@ -18,9 +18,9 @@ def validate_body( - validator: Callable[[Type[Any], Dict[str, Any]], Any], - model: Type[Any], - body: Dict[str, Any], + validator: Callable[[type[Any], dict[str, Any]], Any], + model: type[Any], + body: dict[str, Any], ) -> Any: try: return validator(model, body) diff --git a/sanic_ext/utils/typing.py b/sanic_ext/utils/typing.py index 36d0710..0107994 100644 --- a/sanic_ext/utils/typing.py +++ b/sanic_ext/utils/typing.py @@ -62,9 +62,9 @@ def is_msgspec(model): def flat_values( item: typing.Union[ - typing.Dict[str, typing.Any], typing.Iterable[typing.Any] + dict[str, typing.Any], typing.Iterable[typing.Any] ], -) -> typing.Set[typing.Any]: +) -> set[typing.Any]: values = set() if isinstance(item, dict): item = item.values() @@ -76,6 +76,6 @@ def flat_values( return values -def contains_annotations(d: typing.Dict[str, typing.Any]) -> bool: +def contains_annotations(d: dict[str, typing.Any]) -> bool: values = flat_values(d) return any(isclass(q) or is_generic(q) for q in values) diff --git a/sanic_ext/utils/version.py b/sanic_ext/utils/version.py index 1821bab..46522b9 100644 --- a/sanic_ext/utils/version.py +++ b/sanic_ext/utils/version.py @@ -39,7 +39,7 @@ ) -def get_version(version) -> Tuple[int, ...]: +def get_version(version) -> tuple[int, ...]: match = PATTERN.search(version) if not match: raise ValueError(f"Invalid version: {version}") diff --git a/tests/extensions/openapi/test_decorators.py b/tests/extensions/openapi/test_decorators.py index 1b56b55..ca2dd70 100644 --- a/tests/extensions/openapi/test_decorators.py +++ b/tests/extensions/openapi/test_decorators.py @@ -35,8 +35,8 @@ class BigFoo: nullable_single: Optional[bool] nullable_multi: Optional[Union[str, int]] bar: Bar - adict: Dict[str, Any] - bdict: Dict[str, bool] + adict: dict[str, Any] + bdict: dict[str, bool] anything: Any choice: Choice diff --git a/tests/extensions/openapi/test_model_fields.py b/tests/extensions/openapi/test_model_fields.py index c04656d..c043b8e 100644 --- a/tests/extensions/openapi/test_model_fields.py +++ b/tests/extensions/openapi/test_model_fields.py @@ -13,13 +13,12 @@ from .utils import get_spec -if sys.version_info >= (3, 9): - from typing import Annotated +from typing import Annotated @dataclass class FooDataclass: - links: List[UUID] + links: list[UUID] priority: int = field( metadata={"openapi": {"exclusiveMinimum": 1, "exclusiveMaximum": 10}} ) @@ -28,7 +27,7 @@ class FooDataclass: @attrs.define class FooAttrs: - links: List[UUID] + links: list[UUID] priority: int = attrs.field( metadata={"openapi": {"exclusiveMinimum": 1, "exclusiveMaximum": 10}} ) @@ -38,27 +37,26 @@ class FooAttrs: class FooPydanticBaseModel(BaseModel): - links: List[UUID] + links: list[UUID] priority: int = Field(gt=1, lt=10) ident: str = Field("XXXX", example="ABC123") @pydataclass class FooPydanticDataclass: - links: List[UUID] + links: list[UUID] priority: int = Field(gt=1, lt=10) ident: str = Field("XXXX", example="ABC123") -if sys.version_info >= (3, 9): - class FooStruct(Struct): - links: List[UUID] - priority: Annotated[ - int, - Meta(extra={"openapi": {"exclusiveMinimum": 1, "exclusiveMaximum": 10}}), - ] - ident: Annotated[str, Meta(extra={"openapi": {"example": "ABC123"}})] = "XXXX" +class FooStruct(Struct): + links: list[UUID] + priority: Annotated[ + int, + Meta(extra={"openapi": {"exclusiveMinimum": 1, "exclusiveMaximum": 10}}), + ] + ident: Annotated[str, Meta(extra={"openapi": {"example": "ABC123"}})] = "XXXX" models = [ @@ -68,8 +66,7 @@ class FooStruct(Struct): FooPydanticDataclass, ] -if sys.version_info >= (3, 9): - models.append(FooStruct) +models.append(FooStruct) @pytest.mark.parametrize("Foo", models) diff --git a/tests/extensions/openapi/test_model_spec.py b/tests/extensions/openapi/test_model_spec.py index f337b41..faa936e 100644 --- a/tests/extensions/openapi/test_model_spec.py +++ b/tests/extensions/openapi/test_model_spec.py @@ -15,7 +15,7 @@ @dataclass class AlertDataclass: - hit: Dict[str, int] + hit: dict[str, int] last_updated: datetime @@ -26,7 +26,7 @@ class AlertResponseDataclass: class AlertPydanticBaseModel(BaseModel): - hit: Dict[str, int] + hit: dict[str, int] last_updated: datetime @@ -36,7 +36,7 @@ class AlertResponsePydanticBaseModel(BaseModel): class AlertMsgspecBaseModel(Struct): - hit: Dict[str, int] + hit: dict[str, int] last_updated: datetime @@ -47,7 +47,7 @@ class AlertResponseMsgspecBaseModel(Struct): @pydataclass class AlertPydanticDataclass: - hit: Dict[str, int] + hit: dict[str, int] last_updated: datetime @@ -59,7 +59,7 @@ class AlertResponsePydanticDataclass: @attrs.define class AlertAttrs: - hit: Dict[str, int] + hit: dict[str, int] last_updated: datetime diff --git a/tests/extensions/openapi/test_schema.py b/tests/extensions/openapi/test_schema.py index 5ce01bf..4227459 100644 --- a/tests/extensions/openapi/test_schema.py +++ b/tests/extensions/openapi/test_schema.py @@ -9,7 +9,7 @@ @pytest.mark.skipif(version_info < (3, 9), reason="Not needed on 3.8") def test_schema_list(): class Foo: - list1: List[int] + list1: list[int] list2: list[int] @property diff --git a/tests/extensions/openapi/test_typing.py b/tests/extensions/openapi/test_typing.py index 50e6fb7..8852614 100644 --- a/tests/extensions/openapi/test_typing.py +++ b/tests/extensions/openapi/test_typing.py @@ -33,13 +33,12 @@ def test_dict_values_nested(): params = [ ({"foo": str}, True), - ({"foo": List[str]}, True), + ({"foo": list[str]}, True), ({"foo": Optional[str]}, True), ({"foo": Foo}, True), ({"foo": "str"}, False), ] -if sys.version_info >= (3, 9): - params.append(({"foo": list[str]}, True)) +params.append(({"foo": list[str]}, True)) if sys.version_info >= (3, 10): params.append(({"foo": str | None}, True)) diff --git a/tests/extensions/openapi/utils.py b/tests/extensions/openapi/utils.py index 52429e9..5375e1a 100644 --- a/tests/extensions/openapi/utils.py +++ b/tests/extensions/openapi/utils.py @@ -3,12 +3,12 @@ from sanic import Sanic -def get_spec(app: Sanic) -> Dict[str, Any]: +def get_spec(app: Sanic) -> dict[str, Any]: test_client = app.test_client _, response = test_client.get("/docs/openapi.json") return response.json -def get_path(app: Sanic, path: str, method: str = "get") -> Dict[str, Any]: +def get_path(app: Sanic, path: str, method: str = "get") -> dict[str, Any]: spec = get_spec(app) return spec["paths"][path][method.lower()] diff --git a/tests/extensions/test_startup.py b/tests/extensions/test_startup.py index 1972bfb..3effc59 100644 --- a/tests/extensions/test_startup.py +++ b/tests/extensions/test_startup.py @@ -49,8 +49,8 @@ class BarExtension(Extension): def startup(self, _) -> None: mock() - foo: Union[Type[Extension], Extension] = FooExtension - bar: Union[Type[Extension], Extension] = BarExtension + foo: Union[type[Extension], Extension] = FooExtension + bar: Union[type[Extension], Extension] = BarExtension if instance: foo = foo() # type: ignore bar = bar() # type: ignore diff --git a/tests/extra/__models__.py b/tests/extra/__models__.py index a9cb822..8def6c0 100644 --- a/tests/extra/__models__.py +++ b/tests/extra/__models__.py @@ -60,27 +60,27 @@ class ModelOptionalUnionIntStr: @dataclass class ModelListStr: - foo: List[str] + foo: list[str] @dataclass class ModelListModel: - foo: List[ModelStr] + foo: list[ModelStr] @dataclass class ModelOptionalList: - foo: Optional[List[str]] + foo: Optional[list[str]] @dataclass class ModelListUnion: - foo: List[Union[int, float]] + foo: list[Union[int, float]] @dataclass class ModelOptionalListUnion: - foo: Optional[List[Union[int, float]]] + foo: Optional[list[Union[int, float]]] @dataclass @@ -95,27 +95,27 @@ class ModelOptionalModel: @dataclass class ModelDictStr: - foo: Dict[str, str] + foo: dict[str, str] @dataclass class ModelDictModel: - foo: Dict[str, ModelStr] + foo: dict[str, ModelStr] @dataclass class ModelOptionalDict: - foo: Optional[Dict[str, str]] + foo: Optional[dict[str, str]] @dataclass class ModelDictUnion: - foo: Dict[str, Union[int, float]] + foo: dict[str, Union[int, float]] @dataclass class ModelOptionalDictUnion: - foo: Optional[Dict[str, Union[int, float]]] + foo: Optional[dict[str, Union[int, float]]] @dataclass @@ -140,7 +140,7 @@ class ModelOptionalMultipleLiteral: @dataclass class ModelListStrWithDefaultFactory: - foo: List[str] = field(default_factory=list) + foo: list[str] = field(default_factory=list) if sys.version_info > (3, 10): diff --git a/tests/extra/test_parse_hint.py b/tests/extra/test_parse_hint.py index f14f989..f213675 100644 --- a/tests/extra/test_parse_hint.py +++ b/tests/extra/test_parse_hint.py @@ -8,7 +8,7 @@ @pytest.mark.skipif(version_info < (3, 9), reason="Not needed on 3.8") def test_parse_generic_list(): - hint_1 = parse_hint(List[int]) + hint_1 = parse_hint(list[int]) hint_2 = parse_hint(list[int]) assert hint_1.origin == hint_2.origin @@ -17,7 +17,7 @@ def test_parse_generic_list(): @pytest.mark.skipif(version_info < (3, 9), reason="Not needed on 3.8") def test_parse_generic_dict(): - hint_1 = parse_hint(Dict[str, Any]) + hint_1 = parse_hint(dict[str, Any]) hint_2 = parse_hint(dict[str, Any]) assert hint_1.origin == hint_2.origin diff --git a/tests/extra/test_validation_attrs.py b/tests/extra/test_validation_attrs.py index 0c44c2c..85071fc 100644 --- a/tests/extra/test_validation_attrs.py +++ b/tests/extra/test_validation_attrs.py @@ -13,7 +13,7 @@ def test_validate_json(app): @attrs.define class Pet: name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(json=Pet) @@ -51,7 +51,7 @@ def test_validate_form(app): @attrs.define class Pet: name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(form=Pet) diff --git a/tests/extra/test_validation_dataclass.py b/tests/extra/test_validation_dataclass.py index b8b004a..6e3a7bb 100644 --- a/tests/extra/test_validation_dataclass.py +++ b/tests/extra/test_validation_dataclass.py @@ -24,14 +24,14 @@ class Pet: class Person: name: str age: int - pets: Optional[List[Pet]] + pets: Optional[list[Pet]] schema = make_schema({}, Person) assert "Person" in schema assert schema["Person"]["hints"]["name"] == parse_hint(str) assert schema["Person"]["hints"]["age"] == parse_hint(int) - assert schema["Person"]["hints"]["pets"] == parse_hint(Optional[List[Pet]]) + assert schema["Person"]["hints"]["pets"] == parse_hint(Optional[list[Pet]]) assert "Pet" in schema assert schema["Pet"]["hints"]["name"] == parse_hint(str) @@ -46,7 +46,7 @@ class Pet: class Person: name: str age: int - pets: List[Pet] + pets: list[Pet] data = {"name": "Charlie Brown", "age": 8, "pets": [{"name": "Snoopy"}]} @@ -78,7 +78,7 @@ class Pet: class Person: name: str age: int - pets: List[Pet] + pets: list[Pet] schema = make_schema({}, Person) with pytest.raises(TypeError): @@ -295,7 +295,7 @@ def test_validate_json(app): @dataclass class Pet: name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(json=Pet) @@ -333,7 +333,7 @@ def test_validate_form(app): @dataclass class Pet: name: str - alter_ego: List[str] + alter_ego: list[str] description: Optional[str] = None @app.post("/function") diff --git a/tests/extra/test_validation_msgspec.py b/tests/extra/test_validation_msgspec.py index 076fa4d..8dbb446 100644 --- a/tests/extra/test_validation_msgspec.py +++ b/tests/extra/test_validation_msgspec.py @@ -22,14 +22,14 @@ class Pet(Struct): class Person(Struct): name: str age: int - pets: Optional[List[Pet]] + pets: Optional[list[Pet]] schema = make_schema({}, Person) assert "Person" in schema assert schema["Person"]["hints"]["name"] == parse_hint(str) assert schema["Person"]["hints"]["age"] == parse_hint(int) - assert schema["Person"]["hints"]["pets"] == parse_hint(Optional[List[Pet]]) + assert schema["Person"]["hints"]["pets"] == parse_hint(Optional[list[Pet]]) assert "Pet" in schema assert schema["Pet"]["hints"]["name"] == parse_hint(str) @@ -42,7 +42,7 @@ class Pet(Struct): class Person(Struct): name: str age: int - pets: List[Pet] + pets: list[Pet] data = {"name": "Charlie Brown", "age": 8, "pets": [{"name": "Snoopy"}]} @@ -72,7 +72,7 @@ class Pet(Struct): class Person(Struct): name: str age: int - pets: List[Pet] + pets: list[Pet] schema = make_schema({}, Person) with pytest.raises(TypeError): @@ -288,7 +288,7 @@ def test_modeling_union_type_ModelUnionTypeStrInt(): def test_validate_json(app): class Pet(Struct): name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(json=Pet) @@ -325,7 +325,7 @@ async def post(self, _, body: Pet): def test_validate_form(app): class Pet(Struct): name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(form=Pet) diff --git a/tests/extra/test_validation_pydantic.py b/tests/extra/test_validation_pydantic.py index 149d701..54f3196 100644 --- a/tests/extra/test_validation_pydantic.py +++ b/tests/extra/test_validation_pydantic.py @@ -15,7 +15,7 @@ def test_validate_json(app): @dataclass class Pet: name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(json=Pet) @@ -53,7 +53,7 @@ def test_validate_form(app): @dataclass class Pet: name: str - alter_ego: List[str] + alter_ego: list[str] @app.post("/function") @validate(form=Pet)