mirror of
https://github.com/davidhalter/typeshed.git
synced 2025-12-10 05:51:52 +08:00
WebOb: Complete the stubs and activate stricter pyright config (#11460)
This commit is contained in:
@@ -78,7 +78,6 @@
|
||||
"stubs/tqdm",
|
||||
"stubs/ttkthemes",
|
||||
"stubs/vobject",
|
||||
"stubs/WebOb",
|
||||
"stubs/workalendar",
|
||||
],
|
||||
"typeCheckingMode": "strict",
|
||||
|
||||
@@ -137,6 +137,17 @@ webob.request.AdhocAttrMixin.__setattr__
|
||||
# make sense to annotate them and pretend they're part of the API.
|
||||
webob.request.BaseRequest.__init__
|
||||
|
||||
# We needed to add a dummy *_: _P.args in order to support ParamSpec
|
||||
webob.dec.wsgify.middleware
|
||||
webob.dec._MiddlewareFactory.__call__
|
||||
|
||||
# We renamed some of the arguments in positional only overloads for greater
|
||||
# clarity about what the arguments mean, stubtest should probably be a bit
|
||||
# more lenient here, since this is only unsafe if that overload accepts
|
||||
# arbitrary named arguments, that could overlap with the argument in that
|
||||
# specific position
|
||||
webob.dec.wsgify.__call__
|
||||
|
||||
# Error: is not present at runtime
|
||||
# =============================
|
||||
# This attribute is there to help mypy type narrow NoVars based on its static
|
||||
|
||||
121
stubs/WebOb/@tests/test_cases/check_wsgify.py
Normal file
121
stubs/WebOb/@tests/test_cases/check_wsgify.py
Normal file
@@ -0,0 +1,121 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from _typeshed.wsgi import StartResponse, WSGIApplication, WSGIEnvironment
|
||||
from collections.abc import Iterable # noqa: F401
|
||||
from typing_extensions import assert_type
|
||||
|
||||
from webob.dec import _AnyResponse, wsgify
|
||||
from webob.request import Request
|
||||
|
||||
|
||||
class App:
|
||||
@wsgify
|
||||
def __call__(self, request: Request) -> str:
|
||||
return "hello"
|
||||
|
||||
|
||||
env: WSGIEnvironment = {}
|
||||
start_response: StartResponse = lambda x, y, z=None: lambda b: None
|
||||
application: WSGIApplication = lambda e, s: [b""]
|
||||
request: Request = Request(env)
|
||||
|
||||
x = App()
|
||||
# since we wsgified our __call__ we should now be a valid WSGIApplication
|
||||
application = x
|
||||
assert_type(x(env, start_response), "Iterable[bytes]")
|
||||
# currently we lose the exact response type, but that should be fine in
|
||||
# most use-cases, since middlewares operate on an application level, not
|
||||
# on these raw intermediary functions
|
||||
assert_type(x(request), _AnyResponse)
|
||||
|
||||
# accessing the method from the class should work as you expect it to
|
||||
assert_type(App.__call__(x, env, start_response), "Iterable[bytes]")
|
||||
assert_type(App.__call__(x, request), _AnyResponse)
|
||||
|
||||
|
||||
# but we can also wrap it with a middleware that expects to deal with requests
|
||||
class Middleware:
|
||||
@wsgify.middleware
|
||||
def restrict_ip(self, req: Request, app: WSGIApplication, ips: list[str]) -> WSGIApplication:
|
||||
return app
|
||||
|
||||
__call__ = restrict_ip(x, ips=["127.0.0.1"])
|
||||
|
||||
|
||||
# and we still end up with a valid WSGIApplication
|
||||
m = Middleware()
|
||||
application = m
|
||||
assert_type(m(env, start_response), "Iterable[bytes]")
|
||||
assert_type(m(request), _AnyResponse)
|
||||
|
||||
|
||||
# the same should work with plain functions
|
||||
@wsgify
|
||||
def app(request: Request) -> str:
|
||||
return "hello"
|
||||
|
||||
|
||||
application = app
|
||||
assert_type(app, "wsgify[Request, []]")
|
||||
assert_type(app(env, start_response), "Iterable[bytes]")
|
||||
assert_type(app(request), _AnyResponse)
|
||||
# FIXME: For some reason pyright complains here with
|
||||
# mismatch: expected "wsgify[Request, ()]" but received "wsgify[Request, ()]"
|
||||
# can you spot the difference?
|
||||
# assert_type(app(application), "wsgify[Request, []]")
|
||||
application = app(application)
|
||||
|
||||
|
||||
@wsgify.middleware
|
||||
def restrict_ip(req: Request, app: WSGIApplication, ips: list[str]) -> WSGIApplication:
|
||||
return app
|
||||
|
||||
|
||||
@restrict_ip(ips=["127.0.0.1"])
|
||||
@wsgify
|
||||
def m_app(request: Request) -> str:
|
||||
return "hello"
|
||||
|
||||
|
||||
application = m_app
|
||||
# FIXME: same weird pyright error where it complains about the types
|
||||
# being the same
|
||||
# assert_type(m_app, "wsgify[Request, [WSGIApplication]]")
|
||||
assert_type(m_app(env, start_response), "Iterable[bytes]")
|
||||
assert_type(m_app(request), _AnyResponse)
|
||||
# FIXME: and also here
|
||||
# assert_type(m_app(application), "wsgify[Request, [WSGIApplication]]")
|
||||
application = m_app(application)
|
||||
|
||||
|
||||
# custom request
|
||||
class MyRequest(Request):
|
||||
pass
|
||||
|
||||
|
||||
@wsgify(RequestClass=MyRequest)
|
||||
def my_request_app(request: MyRequest) -> None:
|
||||
pass
|
||||
|
||||
|
||||
application = my_request_app
|
||||
assert_type(my_request_app, "wsgify[MyRequest, []]")
|
||||
|
||||
|
||||
# we are allowed to accept a less specific request class
|
||||
@wsgify(RequestClass=MyRequest)
|
||||
def valid_request_app(request: Request) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# but the opposite is not allowed
|
||||
@wsgify # type:ignore
|
||||
def invalid_request_app(request: MyRequest) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# we can't really make passing extra arguments directly work
|
||||
# otherwise we have to give up most of our type safety for
|
||||
# something that should only be used through wsgify.middleware
|
||||
wsgify(args=(1,)) # type:ignore
|
||||
wsgify(kwargs={"ips": ["127.0.0.1"]}) # type:ignore
|
||||
@@ -6,23 +6,23 @@ class Range:
|
||||
start: int | None
|
||||
end: int | None
|
||||
@overload
|
||||
def __init__(self, start: None, end: None): ...
|
||||
def __init__(self, start: None, end: None) -> None: ...
|
||||
@overload
|
||||
def __init__(self, start: int, end: int | None): ...
|
||||
def __init__(self, start: int, end: int | None) -> None: ...
|
||||
def range_for_length(self, length: int | None) -> tuple[int, int] | None: ...
|
||||
def content_range(self, length: int | None) -> ContentRange | None: ...
|
||||
def __iter__(self) -> Iterator[int | None]: ...
|
||||
@classmethod
|
||||
def parse(cls, header: str | None) -> Self: ...
|
||||
def parse(cls, header: str | None) -> Self | None: ...
|
||||
|
||||
class ContentRange:
|
||||
start: int | None
|
||||
stop: int | None
|
||||
length: int | None
|
||||
@overload
|
||||
def __init__(self, start: None, stop: None, length: int | None): ...
|
||||
def __init__(self, start: None, stop: None, length: int | None) -> None: ...
|
||||
@overload
|
||||
def __init__(self, start: int, stop: int, length: int | None): ...
|
||||
def __init__(self, start: int, stop: int, length: int | None) -> None: ...
|
||||
def __iter__(self) -> Iterator[int | None]: ...
|
||||
@classmethod
|
||||
def parse(cls, value: str | None) -> Self: ...
|
||||
def parse(cls, value: str | None) -> Self | None: ...
|
||||
|
||||
@@ -18,7 +18,7 @@ class UpdateDict(dict[_KT, _VT]):
|
||||
class exists_property:
|
||||
prop: str
|
||||
type: str | None
|
||||
def __init__(self, prop: str, type: str | None = None): ...
|
||||
def __init__(self, prop: str, type: str | None = None) -> None: ...
|
||||
@overload
|
||||
def __get__(self, obj: None, type: _Type | None = None) -> Self: ...
|
||||
@overload
|
||||
@@ -32,9 +32,9 @@ class value_property(Generic[_T, _NoneLiteral]):
|
||||
none: _NoneLiteral
|
||||
type: str | None
|
||||
@overload
|
||||
def __init__(self, prop: str, default: None = None, none: None = None, type: str | None = None): ...
|
||||
def __init__(self, prop: str, default: None = None, none: None = None, type: str | None = None) -> None: ...
|
||||
@overload
|
||||
def __init__(self, prop: str, default: _T, none: _NoneLiteral, type: str | None = None): ...
|
||||
def __init__(self, prop: str, default: _T, none: _NoneLiteral, type: str | None = None) -> None: ...
|
||||
@overload
|
||||
def __get__(self, obj: None, type: _Type | None = None) -> Self: ...
|
||||
@overload
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from _typeshed.wsgi import StartResponse, WSGIEnvironment
|
||||
from collections.abc import Iterable
|
||||
from http.client import HTTPMessage
|
||||
from http.client import HTTPConnection, HTTPMessage, HTTPSConnection
|
||||
from typing import ClassVar
|
||||
|
||||
class SendRequest:
|
||||
def __init__(self, HTTPConnection=..., HTTPSConnection=...) -> None: ...
|
||||
def __init__(self, HTTPConnection: type[HTTPConnection] = ..., HTTPSConnection: type[HTTPSConnection] = ...) -> None: ...
|
||||
def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> Iterable[bytes]: ...
|
||||
filtered_headers: ClassVar[tuple[str, ...]]
|
||||
def parse_headers(self, message: HTTPMessage) -> list[tuple[str, str]]: ...
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from datetime import date, datetime, timedelta, tzinfo
|
||||
from time import _TimeTuple, struct_time
|
||||
|
||||
class _UTC(tzinfo):
|
||||
def dst(self, dt: datetime | None) -> timedelta: ...
|
||||
@@ -17,7 +18,7 @@ second: timedelta
|
||||
month: timedelta
|
||||
year: timedelta
|
||||
|
||||
def parse_date(value: str | bytes) -> datetime | None: ...
|
||||
def serialize_date(dt) -> str: ...
|
||||
def parse_date_delta(value: str | bytes) -> datetime | None: ...
|
||||
def serialize_date_delta(value) -> str: ...
|
||||
def parse_date(value: str | bytes | None) -> datetime | None: ...
|
||||
def serialize_date(dt: datetime | date | timedelta | _TimeTuple | struct_time | float | str | bytes) -> str: ...
|
||||
def parse_date_delta(value: str | bytes | None) -> datetime | None: ...
|
||||
def serialize_date_delta(value: datetime | date | timedelta | _TimeTuple | struct_time | float | str | bytes) -> str: ...
|
||||
|
||||
@@ -1,49 +1,196 @@
|
||||
from _typeshed import Incomplete
|
||||
from _typeshed.wsgi import WSGIApplication
|
||||
from typing import ClassVar, overload
|
||||
from typing_extensions import Self
|
||||
from _typeshed.wsgi import StartResponse, WSGIApplication, WSGIEnvironment
|
||||
from collections.abc import Callable, Iterable, Mapping
|
||||
from typing import Any, Generic, TypeVar, overload
|
||||
from typing_extensions import Concatenate, Never, ParamSpec, Self, TypeAlias
|
||||
|
||||
from webob.request import Request
|
||||
from webob.response import Response
|
||||
|
||||
class wsgify:
|
||||
RequestClass: ClassVar[type[Request]]
|
||||
func: Incomplete
|
||||
args: Incomplete
|
||||
kwargs: Incomplete
|
||||
middleware_wraps: Incomplete
|
||||
_AnyResponse: TypeAlias = Response | WSGIApplication | str | None
|
||||
_S = TypeVar("_S")
|
||||
_AppT = TypeVar("_AppT", bound=WSGIApplication)
|
||||
_AppT_contra = TypeVar("_AppT_contra", bound=WSGIApplication, contravariant=True)
|
||||
_RequestT = TypeVar("_RequestT", bound=Request)
|
||||
_RequestT_contra = TypeVar("_RequestT_contra", bound=Request, contravariant=True)
|
||||
_P = ParamSpec("_P")
|
||||
_P2 = ParamSpec("_P2")
|
||||
|
||||
_RequestHandlerCallable: TypeAlias = Callable[Concatenate[_RequestT_contra, _P], _AnyResponse]
|
||||
_RequestHandlerMethod: TypeAlias = Callable[Concatenate[Any, _RequestT_contra, _P], _AnyResponse]
|
||||
_MiddlewareCallable: TypeAlias = Callable[Concatenate[_RequestT_contra, _AppT_contra, _P], _AnyResponse]
|
||||
_MiddlewareMethod: TypeAlias = Callable[Concatenate[Any, _RequestT_contra, _AppT_contra, _P], _AnyResponse]
|
||||
_RequestHandler: TypeAlias = _RequestHandlerCallable[_RequestT_contra, _P] | _RequestHandlerMethod[_RequestT_contra, _P]
|
||||
_Middleware: TypeAlias = (
|
||||
_MiddlewareCallable[_RequestT_contra, _AppT_contra, _P] | _MiddlewareMethod[_RequestT_contra, _AppT_contra, _P]
|
||||
)
|
||||
|
||||
class wsgify(Generic[_RequestT_contra, _P]):
|
||||
RequestClass: type[Request]
|
||||
func: _RequestHandler[_RequestT_contra, _P] | None
|
||||
args: tuple[Any, ...]
|
||||
kwargs: dict[str, Any]
|
||||
middleware_wraps: WSGIApplication | None
|
||||
# NOTE: We disallow passing args/kwargs using this direct API, because
|
||||
# we can't really make it work as a decorator this way, these
|
||||
# arguments should only really be used indrectly through the
|
||||
# middleware decorator, where we can be more type safe
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
func: Incomplete | None = None,
|
||||
RequestClass: Incomplete | None = None,
|
||||
args=...,
|
||||
kwargs: Incomplete | None = None,
|
||||
middleware_wraps: Incomplete | None = None,
|
||||
self: wsgify[Request, []],
|
||||
func: _RequestHandler[Request, []] | None = None,
|
||||
RequestClass: None = None,
|
||||
args: tuple[()] = (),
|
||||
kwargs: None = None,
|
||||
middleware_wraps: None = None,
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __get__(self, obj: None, type: type | None = None) -> Self: ...
|
||||
def __init__(
|
||||
self: wsgify[_RequestT_contra, []],
|
||||
func: _RequestHandler[_RequestT_contra, []] | None,
|
||||
RequestClass: type[_RequestT_contra],
|
||||
args: tuple[()] = (),
|
||||
kwargs: None = None,
|
||||
middleware_wraps: None = None,
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __get__(self, obj: object, type: type | None = None) -> WSGIApplication: ...
|
||||
def __call__(self, req, *args, **kw): ...
|
||||
def get(self, url, **kw): ...
|
||||
def post(self, url, POST: Incomplete | None = None, **kw): ...
|
||||
def request(self, url, **kw): ...
|
||||
def call_func(self, req, *args, **kwargs): ...
|
||||
def clone(self, func: Incomplete | None = None, **kw): ...
|
||||
def __init__(
|
||||
self: wsgify[_RequestT_contra, []],
|
||||
func: _RequestHandler[_RequestT_contra, []] | None = None,
|
||||
*,
|
||||
RequestClass: type[_RequestT_contra],
|
||||
args: tuple[()] = (),
|
||||
kwargs: None = None,
|
||||
middleware_wraps: None = None,
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self: wsgify[Request, [_AppT_contra]],
|
||||
func: _Middleware[Request, _AppT_contra, []] | None = None,
|
||||
RequestClass: None = None,
|
||||
args: tuple[()] = (),
|
||||
kwargs: None = None,
|
||||
*,
|
||||
middleware_wraps: _AppT_contra,
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self: wsgify[_RequestT_contra, [_AppT_contra]],
|
||||
func: _Middleware[_RequestT_contra, _AppT_contra, []] | None,
|
||||
RequestClass: type[_RequestT_contra],
|
||||
args: tuple[()] = (),
|
||||
kwargs: None = None,
|
||||
*,
|
||||
middleware_wraps: _AppT_contra,
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self: wsgify[_RequestT_contra, [_AppT_contra]],
|
||||
func: _Middleware[_RequestT_contra, _AppT_contra, []] | None = None,
|
||||
*,
|
||||
RequestClass: type[_RequestT_contra],
|
||||
args: tuple[()] = (),
|
||||
kwargs: None = None,
|
||||
middleware_wraps: _AppT_contra,
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __get__(self, obj: None, type: type[_S]) -> _unbound_wsgify[_RequestT_contra, _P, _S]: ...
|
||||
@overload
|
||||
def __get__(self, obj: object, type: type | None = None) -> Self: ...
|
||||
@overload
|
||||
def __call__(self, env: WSGIEnvironment, /, start_response: StartResponse) -> Iterable[bytes]: ...
|
||||
@overload
|
||||
def __call__(self, func: _RequestHandler[_RequestT_contra, _P], /) -> Self: ...
|
||||
@overload
|
||||
def __call__(self, req: _RequestT_contra) -> _AnyResponse: ...
|
||||
@overload
|
||||
def __call__(self, req: _RequestT_contra, *args: _P.args, **kw: _P.kwargs) -> _AnyResponse: ...
|
||||
def get(self, url: str, **kw: Any) -> _AnyResponse: ...
|
||||
def post(
|
||||
self, url: str, POST: str | bytes | Mapping[Any, Any] | Mapping[Any, list[Any] | tuple[Any, ...]] | None = None, **kw: Any
|
||||
) -> _AnyResponse: ...
|
||||
def request(self, url: str, **kw: Any) -> _AnyResponse: ...
|
||||
def call_func(self, req: _RequestT_contra, *args: _P.args, **kwargs: _P.kwargs) -> _AnyResponse: ...
|
||||
# technically this could bind different type vars, but we disallow it for safety
|
||||
def clone(self, func: _RequestHandler[_RequestT_contra, _P] | None = None, **kw: Never) -> Self: ...
|
||||
@property
|
||||
def undecorated(self): ...
|
||||
def undecorated(self) -> _RequestHandler[_RequestT_contra, _P] | None: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def middleware(cls, middle_func: Incomplete | None = None, app: Incomplete | None = None, **kw): ...
|
||||
def middleware(
|
||||
cls, middle_func: None = None, app: None | _AppT = None, *_: _P.args, **kw: _P.kwargs
|
||||
) -> _UnboundMiddleware[Any, _AppT, _P]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def middleware(
|
||||
cls, middle_func: _MiddlewareCallable[_RequestT, _AppT, _P2], app: None = None
|
||||
) -> _MiddlewareFactory[_RequestT, _AppT, _P2]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def middleware(
|
||||
cls, middle_func: _MiddlewareMethod[_RequestT, _AppT, _P2], app: None = None
|
||||
) -> _MiddlewareFactory[_RequestT, _AppT, _P2]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def middleware(
|
||||
cls, middle_func: _MiddlewareMethod[_RequestT, _AppT, _P2], app: None = None, *_: _P2.args, **kw: _P2.kwargs
|
||||
) -> _MiddlewareFactory[_RequestT, _AppT, _P2]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def middleware(
|
||||
cls, middle_func: _MiddlewareMethod[_RequestT, _AppT, _P2], app: _AppT
|
||||
) -> type[wsgify[_RequestT, Concatenate[_AppT, _P2]]]: ...
|
||||
@overload
|
||||
@classmethod
|
||||
def middleware(
|
||||
cls, middle_func: _MiddlewareMethod[_RequestT, _AppT, _P2], app: _AppT, *_: _P2.args, **kw: _P2.kwargs
|
||||
) -> type[wsgify[_RequestT, Concatenate[_AppT, _P2]]]: ...
|
||||
|
||||
class _UnboundMiddleware:
|
||||
wrapper_class: Incomplete
|
||||
app: Incomplete
|
||||
kw: Incomplete
|
||||
def __init__(self, wrapper_class, app, kw) -> None: ...
|
||||
def __call__(self, func, app: Incomplete | None = None): ...
|
||||
class _unbound_wsgify(wsgify[_RequestT_contra, _P], Generic[_RequestT_contra, _P, _S]):
|
||||
@overload # type: ignore[override]
|
||||
def __call__(self, __self: _S, env: WSGIEnvironment, /, start_response: StartResponse) -> Iterable[bytes]: ...
|
||||
@overload
|
||||
def __call__(self, __self: _S, func: _RequestHandler[_RequestT_contra, _P], /) -> Self: ...
|
||||
@overload
|
||||
def __call__(self, __self: _S, req: _RequestT_contra) -> _AnyResponse: ...
|
||||
@overload
|
||||
def __call__(self, __self: _S, req: _RequestT_contra, *args: _P.args, **kw: _P.kwargs) -> _AnyResponse: ...
|
||||
|
||||
class _MiddlewareFactory:
|
||||
wrapper_class: Incomplete
|
||||
middleware: Incomplete
|
||||
kw: Incomplete
|
||||
def __init__(self, wrapper_class, middleware, kw) -> None: ...
|
||||
def __call__(self, app: Incomplete | None = None, **config): ...
|
||||
class _UnboundMiddleware(Generic[_RequestT_contra, _AppT_contra, _P]):
|
||||
wrapper_class: type[wsgify[_RequestT_contra, Concatenate[_AppT_contra, _P]]]
|
||||
app: _AppT_contra | None
|
||||
kw: dict[str, Any]
|
||||
def __init__(
|
||||
self,
|
||||
wrapper_class: type[wsgify[_RequestT_contra, Concatenate[_AppT_contra, _P]]],
|
||||
app: _AppT_contra | None,
|
||||
kw: dict[str, Any],
|
||||
) -> None: ...
|
||||
@overload
|
||||
def __call__(self, func: None, app: _AppT_contra | None = None) -> Self: ...
|
||||
@overload
|
||||
def __call__(
|
||||
self, func: _Middleware[_RequestT_contra, _AppT_contra, _P], app: None = None
|
||||
) -> wsgify[_RequestT_contra, Concatenate[_AppT_contra, _P]]: ...
|
||||
@overload
|
||||
def __call__(
|
||||
self, func: _Middleware[_RequestT_contra, _AppT_contra, _P], app: _AppT_contra
|
||||
) -> wsgify[_RequestT_contra, Concatenate[_AppT_contra, _P]]: ...
|
||||
|
||||
class _MiddlewareFactory(Generic[_RequestT_contra, _AppT_contra, _P]):
|
||||
wrapper_class: type[wsgify[_RequestT_contra, Concatenate[_AppT_contra, _P]]]
|
||||
middleware: _Middleware[_RequestT_contra, _AppT_contra, _P]
|
||||
kw: dict[str, Any]
|
||||
def __init__(
|
||||
self,
|
||||
wrapper_class: type[wsgify[_RequestT_contra, Concatenate[_AppT_contra, _P]]],
|
||||
middleware: _Middleware[_RequestT_contra, _AppT_contra, _P],
|
||||
kw: dict[str, Any],
|
||||
) -> None: ...
|
||||
# NOTE: Technically you are not allowed to pass args, but we give up all kinds
|
||||
# of other safety if we don't use ParamSpec
|
||||
@overload
|
||||
def __call__(
|
||||
self, app: None = None, *_: _P.args, **config: _P.kwargs
|
||||
) -> _MiddlewareFactory[_RequestT_contra, _AppT_contra, []]: ...
|
||||
@overload
|
||||
def __call__(self, app: _AppT_contra, *_: _P.args, **config: _P.kwargs) -> wsgify[_RequestT_contra, [_AppT_contra]]: ...
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
from _typeshed import Incomplete
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Callable, Iterable
|
||||
from datetime import date, datetime, timedelta
|
||||
from time import _TimeTuple, struct_time
|
||||
from typing import Any, Generic, NamedTuple, TypeVar, overload
|
||||
from typing_extensions import TypeAlias
|
||||
|
||||
from webob.byterange import ContentRange, Range
|
||||
from webob.etag import IfRange, IfRangeDate
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_DefaultT = TypeVar("_DefaultT")
|
||||
_GetterReturnType = TypeVar("_GetterReturnType")
|
||||
_SetterValueType = TypeVar("_SetterValueType")
|
||||
_ConvertedGetterReturnType = TypeVar("_ConvertedGetterReturnType")
|
||||
_ConvertedSetterValueType = TypeVar("_ConvertedSetterValueType")
|
||||
_ContentRangeParams: TypeAlias = (
|
||||
ContentRange
|
||||
| list[int]
|
||||
| list[None]
|
||||
| list[int | None]
|
||||
| tuple[int, int]
|
||||
| tuple[None, None]
|
||||
| tuple[int, int, int | None]
|
||||
| tuple[None, None, int | None]
|
||||
| str
|
||||
| None
|
||||
)
|
||||
|
||||
class _AsymmetricProperty(Generic[_GetterReturnType, _SetterValueType]):
|
||||
@overload
|
||||
@@ -17,36 +36,67 @@ class _AsymmetricProperty(Generic[_GetterReturnType, _SetterValueType]):
|
||||
class _AsymmetricPropertyWithDelete(_AsymmetricProperty[_GetterReturnType, _SetterValueType]):
|
||||
def __delete__(self, __obj: Any) -> None: ...
|
||||
|
||||
class _StringProperty(_AsymmetricPropertyWithDelete[str | None, str | None]): ...
|
||||
class _SymmetricProperty(_AsymmetricProperty[_T, _T]): ...
|
||||
class _SymmetricPropertyWithDelete(_AsymmetricPropertyWithDelete[_T, _T]): ...
|
||||
class _StringProperty(_SymmetricPropertyWithDelete[str | None]): ...
|
||||
class _ListProperty(_AsymmetricPropertyWithDelete[tuple[str, ...] | None, Iterable[str] | str | None]): ...
|
||||
class _DateProperty(
|
||||
_AsymmetricPropertyWithDelete[datetime | None, date | datetime | timedelta | _TimeTuple | struct_time | float | str | None]
|
||||
): ...
|
||||
|
||||
def environ_getter(key, default=..., rfc_section: Incomplete | None = None): ...
|
||||
def environ_decoder(key, default=..., rfc_section: Incomplete | None = None, encattr: Incomplete | None = None): ...
|
||||
def upath_property(key): ...
|
||||
def deprecated_property(attr, name, text, version): ...
|
||||
@overload
|
||||
def environ_getter(key: str, default: None, rfc_section: str | None = None) -> _SymmetricPropertyWithDelete[Any | None]: ...
|
||||
@overload
|
||||
def environ_getter(
|
||||
key: str, default: _DefaultT, rfc_section: str | None = None
|
||||
) -> _AsymmetricPropertyWithDelete[Any | _DefaultT, Any | _DefaultT | None]: ...
|
||||
@overload
|
||||
def environ_getter(key: str, *, rfc_section: str | None = None) -> _SymmetricProperty[Any]: ...
|
||||
@overload
|
||||
def environ_decoder(
|
||||
key: str, default: str, rfc_section: str | None = None, encattr: str | None = None
|
||||
) -> _AsymmetricPropertyWithDelete[str, str | None]: ...
|
||||
@overload
|
||||
def environ_decoder(
|
||||
key: str, default: None, rfc_section: str | None = None, encattr: str | None = None
|
||||
) -> _SymmetricPropertyWithDelete[str | None]: ...
|
||||
@overload
|
||||
def environ_decoder(key: str, *, rfc_section: str | None = None, encattr: str | None = None) -> _SymmetricProperty[str]: ...
|
||||
def upath_property(key: str) -> _SymmetricProperty[str]: ...
|
||||
def deprecated_property(attr: _T, name: str, text: str, version: str) -> _T: ...
|
||||
def header_getter(header: str, rfc_section: str) -> _StringProperty: ...
|
||||
def converter(prop, parse, serialize, convert_name: Incomplete | None = None): ...
|
||||
@overload
|
||||
def converter(
|
||||
prop: _AsymmetricPropertyWithDelete[_GetterReturnType, _SetterValueType],
|
||||
parse: Callable[[_GetterReturnType], _ConvertedGetterReturnType],
|
||||
serialize: Callable[[_ConvertedSetterValueType], _SetterValueType],
|
||||
convert_name: str | None = None,
|
||||
) -> _AsymmetricPropertyWithDelete[_ConvertedGetterReturnType, _ConvertedSetterValueType]: ...
|
||||
@overload
|
||||
def converter(
|
||||
prop: _AsymmetricProperty[_GetterReturnType, _SetterValueType],
|
||||
parse: Callable[[_GetterReturnType], _ConvertedGetterReturnType],
|
||||
serialize: Callable[[_ConvertedSetterValueType], _SetterValueType],
|
||||
convert_name: str | None = None,
|
||||
) -> _AsymmetricProperty[_ConvertedGetterReturnType, _ConvertedSetterValueType]: ...
|
||||
def list_header(header: str, rfc_section: str) -> _ListProperty: ...
|
||||
def parse_list(value): ...
|
||||
def serialize_list(value): ...
|
||||
def converter_date(prop): ...
|
||||
def parse_list(value: str | None) -> tuple[str, ...] | None: ...
|
||||
def serialize_list(value: Iterable[str] | str) -> str: ...
|
||||
def converter_date(prop: _StringProperty) -> _DateProperty: ...
|
||||
def date_header(header: str, rfc_section: str) -> _DateProperty: ...
|
||||
def parse_etag_response(value, strong: bool = False): ...
|
||||
def serialize_etag_response(value): ...
|
||||
def serialize_if_range(value): ...
|
||||
def parse_range(value): ...
|
||||
def serialize_range(value): ...
|
||||
def parse_int(value): ...
|
||||
def parse_int_safe(value): ...
|
||||
def parse_etag_response(value: str | None, strong: bool = False) -> str | None: ...
|
||||
def serialize_etag_response(value: str | tuple[str, bool]) -> str: ...
|
||||
def serialize_if_range(value: IfRange | IfRangeDate | datetime | date | str) -> str | None: ...
|
||||
def parse_range(value: str | None) -> Range | None: ...
|
||||
def serialize_range(value: tuple[int, int | None] | list[int | None] | list[int] | str | None) -> str | None: ...
|
||||
def parse_int(value: str | None) -> int | None: ...
|
||||
def parse_int_safe(value: str | None) -> int | None: ...
|
||||
|
||||
serialize_int = str
|
||||
serialize_int: Callable[[int], str]
|
||||
|
||||
def parse_content_range(value): ...
|
||||
def serialize_content_range(value): ...
|
||||
def parse_auth_params(params): ...
|
||||
def parse_content_range(value: str | None) -> ContentRange | None: ...
|
||||
def serialize_content_range(value: _ContentRangeParams) -> str | None: ...
|
||||
def parse_auth_params(params: str) -> dict[str, str]: ...
|
||||
|
||||
known_auth_schemes: dict[str, None]
|
||||
|
||||
@@ -54,5 +104,5 @@ class _authorization(NamedTuple):
|
||||
authtype: str
|
||||
params: dict[str, str] | str
|
||||
|
||||
def parse_auth(val): ...
|
||||
def serialize_auth(val): ...
|
||||
def parse_auth(val: str | None) -> _authorization | None: ...
|
||||
def serialize_auth(val: tuple[str, dict[str, str] | str] | list[Any] | str | None) -> str | None: ...
|
||||
|
||||
@@ -11,9 +11,9 @@ _VT = TypeVar("_VT")
|
||||
|
||||
class MultiDict(MutableMapping[_KT, _VT]):
|
||||
@overload
|
||||
def __init__(self, __m: SupportsItems[_KT, _VT], **kwargs: _VT): ...
|
||||
def __init__(self, __m: SupportsItems[_KT, _VT], **kwargs: _VT) -> None: ...
|
||||
@overload
|
||||
def __init__(self, __m: Iterable[tuple[_KT, _VT]], **kwargs: _VT): ...
|
||||
def __init__(self, __m: Iterable[tuple[_KT, _VT]], **kwargs: _VT) -> None: ...
|
||||
@overload
|
||||
def __init__(self, **kwargs: _VT) -> None: ...
|
||||
@classmethod
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import datetime
|
||||
import io
|
||||
from _typeshed import (
|
||||
ExcInfo,
|
||||
Incomplete,
|
||||
ReadableBuffer,
|
||||
SupportsItems,
|
||||
SupportsKeysAndGetItem,
|
||||
SupportsNoArgReadline,
|
||||
SupportsRead,
|
||||
)
|
||||
from _typeshed import ExcInfo, ReadableBuffer, SupportsItems, SupportsKeysAndGetItem, SupportsNoArgReadline, SupportsRead
|
||||
from _typeshed.wsgi import WSGIApplication, WSGIEnvironment
|
||||
from cgi import FieldStorage
|
||||
from collections.abc import Iterable, Mapping
|
||||
@@ -55,8 +47,11 @@ class BaseRequest:
|
||||
environ: WSGIEnvironment
|
||||
method: _HTTPMethod
|
||||
def __init__(self, environ: WSGIEnvironment, **kw: Any) -> None: ...
|
||||
def encget(self, key: str, default: Any = ..., encattr: str | None = None) -> Any: ...
|
||||
def encset(self, key: str, val: Any, encattr: str | None = None) -> None: ...
|
||||
@overload
|
||||
def encget(self, key: str, default: _T, encattr: str | None = None) -> str | _T: ...
|
||||
@overload
|
||||
def encget(self, key: str, *, encattr: str | None = None) -> str: ...
|
||||
def encset(self, key: str, val: str, encattr: str | None = None) -> None: ...
|
||||
@property
|
||||
def charset(self) -> str | None: ...
|
||||
def decode(self, charset: str | None = None, errors: str = "strict") -> Self: ...
|
||||
@@ -96,7 +91,10 @@ class BaseRequest:
|
||||
@path_info.setter
|
||||
def path_info(self, value: str | None) -> None: ...
|
||||
uscript_name: str # bw compat
|
||||
upath_info = path_info # bw compat
|
||||
@property
|
||||
def upath_info(self) -> str | None: ... # bw compat
|
||||
@upath_info.setter
|
||||
def upath_info(self, value: str | None) -> None: ... # bw compat
|
||||
content_type: str | None
|
||||
headers: _AsymmetricProperty[EnvironHeaders, SupportsItems[str, str] | Iterable[tuple[str, str]]]
|
||||
@property
|
||||
@@ -166,7 +164,7 @@ class BaseRequest:
|
||||
]
|
||||
max_forwards: int | None
|
||||
pragma: str | None
|
||||
range: _AsymmetricPropertyWithDelete[Range, tuple[int, int | None] | list[int | None] | str | None]
|
||||
range: _AsymmetricPropertyWithDelete[Range | None, tuple[int, int | None] | list[int | None] | list[int] | str | None]
|
||||
referer: str | None
|
||||
referrer: str | None
|
||||
user_agent: str | None
|
||||
@@ -198,20 +196,31 @@ class BaseRequest:
|
||||
base_url: str | None = None,
|
||||
headers: Mapping[str, str] | None = None,
|
||||
POST: str | bytes | Mapping[Any, Any] | Mapping[Any, _ListOrTuple[Any]] | None = None,
|
||||
**kw,
|
||||
**kw: Any,
|
||||
) -> Self: ...
|
||||
|
||||
class LegacyRequest(BaseRequest):
|
||||
uscript_name: Incomplete
|
||||
upath_info: Incomplete
|
||||
def encget(self, key, default=..., encattr: Incomplete | None = None): ...
|
||||
@property
|
||||
def uscript_name(self) -> str: ...
|
||||
@uscript_name.setter
|
||||
def uscript_name(self, value: str) -> None: ...
|
||||
@property # type:ignore[override]
|
||||
def upath_info(self) -> str: ...
|
||||
@upath_info.setter
|
||||
def upath_info(self, value: str) -> None: ...
|
||||
def encget(self, key: str, default: Any = ..., encattr: str | None = None) -> Any: ...
|
||||
|
||||
class AdhocAttrMixin:
|
||||
def __setattr__(self, attr: str, value: Any) -> None: ...
|
||||
def __getattr__(self, attr: str) -> Any: ...
|
||||
def __delattr__(self, attr: str) -> None: ...
|
||||
|
||||
class Request(AdhocAttrMixin, BaseRequest): ...
|
||||
class Request(AdhocAttrMixin, BaseRequest):
|
||||
# this is so Request doesn't count as callable, it's not very pretty
|
||||
# but we run into trouble with overlapping overloads in wsgify if we
|
||||
# don't exclude __call__ from arbitrary attribute access
|
||||
__call__: None
|
||||
|
||||
class DisconnectionError(IOError): ...
|
||||
|
||||
def environ_from_url(path: str) -> WSGIEnvironment: ...
|
||||
|
||||
@@ -8,7 +8,14 @@ from typing_extensions import TypeAlias
|
||||
from webob.byterange import ContentRange
|
||||
from webob.cachecontrol import _ResponseCacheControl
|
||||
from webob.cookies import _SameSitePolicy
|
||||
from webob.descriptors import _AsymmetricProperty, _AsymmetricPropertyWithDelete, _authorization, _DateProperty, _ListProperty
|
||||
from webob.descriptors import (
|
||||
_AsymmetricProperty,
|
||||
_AsymmetricPropertyWithDelete,
|
||||
_authorization,
|
||||
_ContentRangeParams,
|
||||
_DateProperty,
|
||||
_ListProperty,
|
||||
)
|
||||
from webob.headers import ResponseHeaders
|
||||
from webob.request import Request
|
||||
|
||||
@@ -46,16 +53,6 @@ class _ResponseCacheControlDict(TypedDict, total=False):
|
||||
stale_if_error: int
|
||||
|
||||
_HTTPHeader: TypeAlias = tuple[str, str]
|
||||
_ContentRangeParams: TypeAlias = (
|
||||
ContentRange
|
||||
| list[int | None]
|
||||
| tuple[int, int]
|
||||
| tuple[None, None]
|
||||
| tuple[int, int, int | None]
|
||||
| tuple[None, None, int | None]
|
||||
| str
|
||||
| None
|
||||
)
|
||||
|
||||
class Response:
|
||||
default_content_type: str
|
||||
@@ -154,7 +151,7 @@ class ResponseBodyFile:
|
||||
mode: Literal["wb"]
|
||||
closed: Literal[False]
|
||||
response: Response
|
||||
def __init__(self, response: Response): ...
|
||||
def __init__(self, response: Response) -> None: ...
|
||||
@property
|
||||
def encoding(self) -> str | None: ...
|
||||
def write(self, text: str | bytes) -> int: ...
|
||||
|
||||
@@ -5,8 +5,8 @@ class _HasHTML(Protocol):
|
||||
def __html__(self) -> str: ...
|
||||
|
||||
def html_escape(s: str | bytes | _HasHTML) -> str: ...
|
||||
def header_docstring(header, rfc_section): ...
|
||||
def warn_deprecation(text, version, stacklevel) -> None: ...
|
||||
def header_docstring(header: str, rfc_section: str) -> str: ...
|
||||
def warn_deprecation(text: str, version: str, stacklevel: int) -> None: ...
|
||||
|
||||
status_reasons: dict[int, str]
|
||||
status_generic_reasons: dict[int, str]
|
||||
|
||||
Reference in New Issue
Block a user