Skip to content

for werkzeug.exceptions.HTTPException.get_response, type signature and documentation disagreeΒ #3056

Closed

Description

@glyph
from werkzeug.exceptions import HTTPException

e: HTTPException
reveal_type(e.get_response())
src/t.py:4:13: note: Revealed type is "werkzeug.sansio.response.Response"
Success: no issues found in 1 source file

This is surprising because the type import of "Response" and the reference to "Response" seem to be indicating the sansio Response, however, I think that Sphinx is resolving the name reference in some global namespace that gets clobbered, which then results in the actual rendered documentation referring to werkzeug.wrappers.Response.

The actual implementation does return a werkzeug.wrappers.Response and we have code in Klein that expects this to be the case, so I think that this was perhaps a case of jumbled intent?

In any case these should be made to agree.

Environment:

  • Python version: 3.13.5
  • Werkzeug version: 3.1.3 / 504a8c4

Activity

  1. changed the title [-]for `werkzeug.exceptions.HTTPException`, type signature and documentation disagree[/-] [+]for `werkzeug.exceptions.HTTPException.get_response`, type signature and documentation disagree[/+] on Jul 10, 2025
  2. davidism commented on Jul 10, 2025

    @davidism
    Member

    This is one of those places where it's very hard to shoehorn in ASGI stuff where it was authored for WSGI only, while still making type checkers happy internally and externally. For WSGI applications, this should return werkzeug.response.Response, for ASGI this should return sansio.Response. Quart relies on that, so it needs the broader annotation so that its own type checking doesn't fail. There's no way to tell the type system "this is a WSGI application", so the annotation ends up being less accurate. I don't see a way to change this, but if you have a suggestion I'd be happy to review it.

  3. glyph commented on Jul 11, 2025

    @glyph
    Author

    This is one of those places where it's very hard to shoehorn in ASGI stuff where it was authored for WSGI only, while still making type checkers happy internally and externally. For WSGI applications, this should return werkzeug.response.Response, for ASGI this should return sansio.Response. Quart relies on that, so it needs the broader annotation so that its own type checking doesn't fail. There's no way to tell the type system "this is a WSGI application", so the annotation ends up being less accurate. I don't see a way to change this, but if you have a suggestion I'd be happy to review it.

    First, a simple fix would be that, if this is the case, then sure, just make the documentation say it. Right now it points at the wrong class, apparently by accident. If client code needs to do an isinstance check that's fine.

    Second, if you want to get more sophisticated, If you make the attribute read-only, you could make SynchronousHTTPException a subclass of HTTPException that repurposes the attribute to be a werkzeug.wrappers.response.Response, and then WSGI applications could just catch SynchronousHTTPException, secure in the knowledge that they're not ASGI and thus will never see that exception type raised.

  4. glyph commented on Jul 11, 2025

    @glyph
    Author

    For a spooky, third option, you could use typing.Generics to tell which kind of application you're talking to but I suspect that would involve a huge and annoying cascade of TypeVars across a few hundred call sites, all to communicate this not-that-interesting detail

  5. davidism commented on Nov 27, 2025

    @davidism
    Member

    I've used some overloads and better import aliases to make reveal_type and the docs more accurate.

    Long term I do want to use generics, but I've tried a couple times in Flask and Werkzeug already. It is a huge knot to slowly untangle, and I didn't have the time.

  6. glyph commented on Nov 28, 2025

    @glyph
    Author

    I've used some overloads and better import aliases to make reveal_type and the docs more accurate.

    Thanks!

    Long term I do want to use generics, but I've tried a couple times in Flask and Werkzeug already. It is a huge knot to slowly untangle, and I didn't have the time.

    Would you be open to accepting a contribution if someone else (no promises, but, maybe me) felt like attempting to untangle it?

  7. locked as resolved and limited conversation to collaborators on Dec 13, 2025
  8. davidism commented on Jan 8, 2026

    @davidism
    Member

    Hey sorry for responding so late, but I would absolutely be open to someone who really knows typing (maybe you) working on this. We currently try to satisfy mypy --strict for internal typing and pyright --verifytypes to ensure the annotations that affect users are complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions