Skip to content

Commit 0ddc63b

Browse files
authored
gh-86178: Add wsgiref.types (GH-32335)
1 parent 1adc837 commit 0ddc63b

File tree

5 files changed

+123
-7
lines changed

5 files changed

+123
-7
lines changed

Doc/library/wsgiref.rst

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ an existing framework.
2323
be used to add WSGI support to a web server or framework. It provides utilities
2424
for manipulating WSGI environment variables and response headers, base classes
2525
for implementing WSGI servers, a demo HTTP server that serves WSGI applications,
26+
types for static type checking,
2627
and a validation tool that checks WSGI servers and applications for conformance
2728
to the WSGI specification (:pep:`3333`).
2829

@@ -43,7 +44,9 @@ This module provides a variety of utility functions for working with WSGI
4344
environments. A WSGI environment is a dictionary containing HTTP request
4445
variables as described in :pep:`3333`. All of the functions taking an *environ*
4546
parameter expect a WSGI-compliant dictionary to be supplied; please see
46-
:pep:`3333` for a detailed specification.
47+
:pep:`3333` for a detailed specification and
48+
:data:`~wsgiref.types.WSGIEnvironment` for a type alias that can be used
49+
in type annotations.
4750

4851

4952
.. function:: guess_scheme(environ)
@@ -150,7 +153,9 @@ also provides these miscellaneous utilities:
150153

151154
.. class:: FileWrapper(filelike, blksize=8192)
152155

153-
A wrapper to convert a file-like object to an :term:`iterator`. The resulting objects
156+
A concrete implementation of the :class:`wsgiref.types.FileWrapper`
157+
protocol used to convert a file-like object to an :term:`iterator`.
158+
The resulting objects
154159
are :term:`iterable`\ s. As the object is iterated over, the
155160
optional *blksize* parameter will be repeatedly passed to the *filelike*
156161
object's :meth:`read` method to obtain bytestrings to yield. When :meth:`read`
@@ -349,7 +354,8 @@ request. (E.g., using the :func:`shift_path_info` function from
349354

350355
.. method:: WSGIRequestHandler.get_environ()
351356

352-
Returns a dictionary containing the WSGI environment for a request. The default
357+
Return a :data:`~wsgiref.types.WSGIEnvironment` dictionary for a
358+
request. The default
353359
implementation copies the contents of the :class:`WSGIServer` object's
354360
:attr:`base_environ` dictionary attribute and then adds various headers derived
355361
from the HTTP request. Each call to this method should return a new dictionary
@@ -558,13 +564,15 @@ input, output, and error streams.
558564

559565
.. method:: BaseHandler.get_stdin()
560566

561-
Return an input stream object suitable for use as the ``wsgi.input`` of the
567+
Return an object compatible with :class:`~wsgiref.types.InputStream`
568+
suitable for use as the ``wsgi.input`` of the
562569
request currently being processed.
563570

564571

565572
.. method:: BaseHandler.get_stderr()
566573

567-
Return an output stream object suitable for use as the ``wsgi.errors`` of the
574+
Return an object compatible with :class:`~wsgiref.types.ErrorStream`
575+
suitable for use as the ``wsgi.errors`` of the
568576
request currently being processed.
569577

570578

@@ -703,8 +711,9 @@ input, output, and error streams.
703711

704712
.. attribute:: BaseHandler.wsgi_file_wrapper
705713

706-
A ``wsgi.file_wrapper`` factory, or ``None``. The default value of this
707-
attribute is the :class:`wsgiref.util.FileWrapper` class.
714+
A ``wsgi.file_wrapper`` factory, compatible with
715+
:class:`wsgiref.types.FileWrapper`, or ``None``. The default value
716+
of this attribute is the :class:`wsgiref.util.FileWrapper` class.
708717

709718

710719
.. method:: BaseHandler.sendfile()
@@ -754,6 +763,51 @@ input, output, and error streams.
754763
.. versionadded:: 3.2
755764

756765

766+
:mod:`wsgiref.types` -- WSGI types for static type checking
767+
-----------------------------------------------------------
768+
769+
.. module:: wsgiref.types
770+
:synopsis: WSGI types for static type checking
771+
772+
773+
This module provides various types for static type checking as described
774+
in :pep:`3333`.
775+
776+
.. versionadded:: 3.11
777+
778+
779+
.. class:: StartResponse()
780+
781+
A :class:`typing.Protocol` describing `start_response()
782+
<https://peps.python.org/pep-3333/#the-start-response-callable>`_
783+
callables (:pep:`3333`).
784+
785+
.. data:: WSGIEnvironment
786+
787+
A type alias describing a WSGI environment dictionary.
788+
789+
.. data:: WSGIApplication
790+
791+
A type alias describing a WSGI application callable.
792+
793+
.. class:: InputStream()
794+
795+
A :class:`typing.Protocol` describing a `WSGI Input Stream
796+
<https://peps.python.org/pep-3333/#input-and-error-streams>`_.
797+
798+
.. class:: ErrorStream()
799+
800+
A :class:`typing.Protocol` describing a `WSGI Error Stream
801+
<https://peps.python.org/pep-3333/#input-and-error-streams>`_.
802+
803+
.. class:: FileWrapper()
804+
805+
A :class:`typing.Protocol` describing a `file wrapper
806+
<https://peps.python.org/pep-3333/#optional-platform-specific-file-handling>`_.
807+
See :class:`wsgiref.util.FileWrapper` for a concrete implementation of this
808+
protocol.
809+
810+
757811
Examples
758812
--------
759813

Doc/whatsnew/3.11.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,10 @@ New Modules
233233
* A new module, :mod:`tomllib`, was added for parsing TOML.
234234
(Contributed by Taneli Hukkinen in :issue:`40059`.)
235235

236+
* :mod:`wsgiref.types`, containing WSGI-specific types for static type
237+
checking, was added.
238+
(Contributed by Sebastian Rittau in :issue:`42012`.)
239+
236240

237241
Improved Modules
238242
================

Lib/wsgiref/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
* validate -- validation wrapper that sits between an app and a server
1414
to detect errors in either
1515
16+
* types -- collection of WSGI-related types for static type checking
17+
1618
To-Do:
1719
1820
* cgi_gateway -- Run WSGI apps under CGI (pending a deployment standard)

Lib/wsgiref/types.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""WSGI-related types for static type checking"""
2+
3+
from collections.abc import Callable, Iterable
4+
from types import TracebackType
5+
from typing import Any, Protocol, TypeAlias
6+
7+
__all__ = [
8+
"StartResponse",
9+
"WSGIEnvironment",
10+
"WSGIApplication",
11+
"InputStream",
12+
"ErrorStream",
13+
"FileWrapper",
14+
]
15+
16+
_ExcInfo = tuple[type[BaseException], BaseException, TracebackType]
17+
_OptExcInfo = _ExcInfo | tuple[None, None, None]
18+
19+
class StartResponse(Protocol):
20+
"""start_response() callable as defined in PEP 3333"""
21+
def __call__(
22+
self,
23+
status: str,
24+
headers: list[tuple[str, str]],
25+
exc_info: _OptExcInfo | None = ...,
26+
/,
27+
) -> Callable[[bytes], object]: ...
28+
29+
WSGIEnvironment: TypeAlias = dict[str, Any]
30+
WSGIApplication: TypeAlias = Callable[[WSGIEnvironment, StartResponse],
31+
Iterable[bytes]]
32+
33+
class InputStream(Protocol):
34+
"""WSGI input stream as defined in PEP 3333"""
35+
def read(self, size: int = ..., /) -> bytes: ...
36+
def readline(self, size: int = ..., /) -> bytes: ...
37+
def readlines(self, hint: int = ..., /) -> list[bytes]: ...
38+
def __iter__(self) -> Iterable[bytes]: ...
39+
40+
class ErrorStream(Protocol):
41+
"""WSGI error stream as defined in PEP 3333"""
42+
def flush(self) -> object: ...
43+
def write(self, s: str, /) -> object: ...
44+
def writelines(self, seq: list[str], /) -> object: ...
45+
46+
class _Readable(Protocol):
47+
def read(self, size: int = ..., /) -> bytes: ...
48+
# Optional: def close(self) -> object: ...
49+
50+
class FileWrapper(Protocol):
51+
"""WSGI file wrapper as defined in PEP 3333"""
52+
def __call__(
53+
self, file: _Readable, block_size: int = ..., /,
54+
) -> Iterable[bytes]: ...
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :mod:`wsgiref.types`, containing WSGI-specific types for static type
2+
checking.

0 commit comments

Comments
 (0)