~shabbyrobe/wsgitypes

9eb430b6bf3729a637b6dbbc7078f55cd44ac1f9 — shabbyrobe 3 years ago 32cc5fc + cbd9a18
Merge branch 'master' of github.com:shabbyrobe/wsgitypes
1 files changed, 24 insertions(+), 13 deletions(-)

M README.rst
M README.rst => README.rst +24 -13
@@ 1,9 1,10 @@
Experimental WSGI Types for Python
==================================
WSGI Types for Python
=====================

This is an attempt to bring some type safety to WSGI applications using Python's new
typing features (TypedDicts, Protocols). It seems to work OK but it'll be full of gaps,
holes, bugs, missteps, etc. I would not recommend depending on it.
typing features (TypedDicts, Protocols). It seems to work OK but may still be full of gaps,
holes, bugs, missteps, etc. It helped bring a lot of extra safety to a couple of places
that really needed it though, and seemed to remain quite stable for a couple of months.

This is implemented as a Python module, rather than MyPy stubs, as it represents a
protocol things can satisfy rather than a set of types for something concrete.


@@ 15,12 16,14 @@ Define a callable application as a class:

.. code-block:: py

    class MyApplication(wsgitypes.Application[MyEnviron]):
    import wsgitypes
    
    class MyApplication(wsgitypes.Application):
        def __call__(
            self, 
            environ: Environ,
            environ: wsgitypes.Environ,
            start_response: wsgitypes.StartResponse,
        ) -> wsgitypes.ResponseBody:
        ) -> wsgitypes.Response:
            my_header = environ.get("REQUEST_METHOD", "")
            return []



@@ 29,7 32,11 @@ Environ should be type-safe:
.. code-block:: py

    class MyApplication(wsgitypes.Application):
        def __call__(self, environ: Environ, start_response: wsgitypes.StartResponse) -> wsgitypes.ResponseBody:
        def __call__(
            self,
            environ: wsgitypes.Environ,
            start_response: wsgitypes.StartResponse,
        ) -> wsgitypes.Response:
            environ["wsgi.input"] # Good
            environ["wsgi.unpot"] # BORK! MyPy will catch this.
            return []


@@ 43,12 50,16 @@ like so:
        HTTP_X_MY_HEADER: t.Optional[str]
    
    class MyApplication(wsgitypes.Application):
        def __call__(self, environ: wsgitypes.Environ, start_response: wsgitypes.StartResponse) -> wsgitypes.Response:
        def __call__(
            self,
            environ: MyEnviron,
            start_response: wsgitypes.StartResponse,
        ) -> wsgitypes.Response:
            environ = typing.cast(MyEnviron, environ)
            environ.get("HTTP_X_MY_HEADER")
            environ.get("HTTP_X_MY_HEADER") # Good
            return []

Note that you need to use ``typing.cast`` to convert the incoming environ to your derived
version. An attempt was made to use a type param for Environ, but it wasn't viable:
https://github.com/python/mypy/issues/7654
Note that you need to use ``typing.cast`` to convert the incoming `Environ` to your
derived version. An attempt was made to use a type param for Environ, but it wasn't
viable (even with GVR helping!): https://github.com/python/mypy/issues/7654