Skip to content

Relax strictness on Middleware type#3059

Merged
Kludex merged 2 commits intomainfrom
more-permissive-version-of-app
Nov 1, 2025
Merged

Relax strictness on Middleware type#3059
Kludex merged 2 commits intomainfrom
more-permissive-version-of-app

Conversation

@Kludex
Copy link
Copy Markdown
Owner

@Kludex Kludex commented Nov 1, 2025

Copilot AI review requested due to automatic review settings November 1, 2025 14:01
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the starlette/middleware/__init__.py file to remove the dependency on starlette.types.ASGIApp and replace it with a local, more permissive type alias _ASGIApp. This change aims to prevent type errors when using middleware with type checking.

Key Changes:

  • Introduced local type aliases (_Scope, _Receive, _Send, _ASGIApp) using Any for more permissive typing
  • Removed the import of ASGIApp from starlette.types
  • Updated _MiddlewareFactory protocol to use the new _ASGIApp type
  • Reformatted the Middleware.__init__ method to a single line

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

_Receive = Callable[[], Awaitable[Any]]
_Send = Callable[[Any], Awaitable[None]]
_ASGIApp = Callable[[_Scope, _Receive, _Send], Awaitable[None]]
"""A more permissive version of ASGIApp that doesn't cause type errors."""
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring for _ASGIApp should clarify when and why this permissive version should be used instead of the standard ASGIApp from starlette.types. Consider expanding it to: 'A more permissive version of ASGIApp used in middleware protocols to avoid type errors when middleware implementations use more specific ASGI types.'

Suggested change
"""A more permissive version of ASGIApp that doesn't cause type errors."""
"""
A more permissive version of ASGIApp used in middleware protocols to avoid type errors
when middleware implementations use more specific ASGI types. This type alias should be
used instead of the standard ASGIApp from starlette.types in cases where middleware
needs to accept a broader range of ASGI applications without strict type constraints.
"""

Copilot uses AI. Check for mistakes.

class _MiddlewareFactory(Protocol[P]):
def __call__(self, app: ASGIApp, /, *args: P.args, **kwargs: P.kwargs) -> ASGIApp: ... # pragma: no cover
def __call__(self, app: _ASGIApp, /, *args: P.args, **kwargs: P.kwargs) -> _ASGIApp: ... # pragma: no cover
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement has no effect.

Copilot uses AI. Check for mistakes.
@Kludex Kludex requested a review from Copilot November 1, 2025 14:04
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 15 to +17

_Scope = Any
_Receive = Callable[[], Awaitable[Any]]
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These internal type aliases lack documentation explaining their purpose. Consider adding a comment explaining why Any is used for _Scope instead of the more specific MutableMapping[str, Any] from starlette.types.Scope, and why _Receive returns Any instead of Message. This would help maintainers understand the intentional loosening of types.

Suggested change
_Scope = Any
_Receive = Callable[[], Awaitable[Any]]
# Internal type alias for ASGI scope.
# We use `Any` here instead of `MutableMapping[str, Any]` (from `starlette.types.Scope`)
# to allow for compatibility with different ASGI implementations and to avoid type errors
# when interacting with libraries that may not strictly adhere to the more specific type.
_Scope = Any
# Internal type alias for ASGI receive callable.
# The return type is `Any` instead of `Message` to permit broader compatibility with
# various ASGI implementations, some of which may not use the exact `Message` type.
_Receive = Callable[[], Awaitable[Any]]
# Internal type alias for ASGI send callable.
# The argument is typed as `Any` instead of `Message` for the same reason as above:
# to allow for flexibility and compatibility with different ASGI implementations.

Copilot uses AI. Check for mistakes.

class _MiddlewareFactory(Protocol[P]):
def __call__(self, app: ASGIApp, /, *args: P.args, **kwargs: P.kwargs) -> ASGIApp: ... # pragma: no cover
def __call__(self, app: _ASGIApp, /, *args: P.args, **kwargs: P.kwargs) -> _ASGIApp: ... # pragma: no cover
Copy link

Copilot AI Nov 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement has no effect.

Copilot uses AI. Check for mistakes.
@Kludex Kludex merged commit c443396 into main Nov 1, 2025
13 checks passed
@Kludex Kludex deleted the more-permissive-version-of-app branch November 1, 2025 14:13
nixroxursox pushed a commit to nixroxursox/starlette that referenced this pull request Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

incompatible type and expected "type[_MiddlewareClass[[]]]" [arg-type]

2 participants