Skip to content

Django channels stubs #13939

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

huynguyengl99
Copy link

No description provided.

This comment has been minimized.

1 similar comment

This comment has been minimized.

@huynguyengl99 huynguyengl99 force-pushed the feature/channels-stubs branch from 040b12e to 2edbaf3 Compare May 4, 2025 17:16

This comment has been minimized.

This comment has been minimized.

@huynguyengl99
Copy link
Author

Hi @sobolevn,
I’ve created stubs to add type hint support for django-channels. Sorry for the tag, but if you have some time, could you please take a look and share any feedback or suggestions? I’d really appreciate your input!

Copy link
Contributor

github-actions bot commented May 4, 2025

Diff from mypy_primer, showing the effect of this PR on open source code:

strawberry (https://github.com/strawberry-graphql/strawberry)
- strawberry/channels/handlers/base.py:14: error: Cannot find implementation or library stub for module named "channels.consumer"  [import-not-found]
- strawberry/channels/handlers/base.py:15: error: Cannot find implementation or library stub for module named "channels.generic.websocket"  [import-not-found]
+ note: "__init_subclass__" of "object" defined here
+ strawberry/channels/handlers/base.py:57: error: Incompatible types in assignment (expression has type "ChannelsLayer | None", base class "AsyncConsumer" defined the type as "BaseChannelLayer")  [assignment]
+ strawberry/channels/handlers/base.py:66: error: Argument 1 of "dispatch" is incompatible with supertype "AsyncConsumer"; supertype defines the argument type as "dict[str, Any]"  [override]
+ strawberry/channels/handlers/base.py:66: note: This violates the Liskov substitution principle
+ strawberry/channels/handlers/base.py:66: note: See https://mypy.readthedocs.io/en/stable/common_issues.html#incompatible-overrides
+ strawberry/channels/handlers/base.py:77: error: Argument 1 to "dispatch" of "AsyncConsumer" has incompatible type "ChannelsMessage"; expected "dict[str, Any]"  [arg-type]
+ strawberry/channels/handlers/base.py:209: error: Definition of "channel_layer" in base class "ChannelsConsumer" is incompatible with definition in base class "AsyncWebsocketConsumer"  [misc]
- strawberry/channels/testing.py:13: error: Cannot find implementation or library stub for module named "channels.testing.websocket"  [import-not-found]
+ strawberry/channels/testing.py:101: error: Incompatible types in assignment (expression has type "dict[str, Any]", variable has type "ConnectionAckMessage")  [assignment]
+ strawberry/channels/testing.py:109: error: Incompatible types in assignment (expression has type "dict[str, Any]", variable has type "ConnectionAckMessage")  [assignment]
+ strawberry/channels/testing.py:146: error: Incompatible types in assignment (expression has type "dict[str, Any]", variable has type "ConnectionInitMessage | ConnectionAckMessage | PingMessage | PongMessage | SubscribeMessage | NextMessage | ErrorMessage | CompleteMessage")  [assignment]
+ strawberry/channels/handlers/ws_handler.py:69: error: Definition of "channel_layer" in base class "ChannelsConsumer" is incompatible with definition in base class "AsyncWebsocketConsumer"  [misc]
+ strawberry/channels/handlers/ws_handler.py:133: error: Argument 1 to "run" of "AsyncBaseHTTPView" has incompatible type "GraphQLWSConsumer[Context, RootValue]"; expected "GraphQLWSConsumer[None, None]"  [arg-type]
- strawberry/channels/handlers/http_handler.py:22: error: Cannot find implementation or library stub for module named "channels.db"  [import-not-found]
- strawberry/channels/handlers/http_handler.py:23: error: Cannot find implementation or library stub for module named "channels.generic.http"  [import-not-found]
+ strawberry/channels/handlers/http_handler.py:200: error: "BaseGraphQLHTTPConsumer" has no attribute "run"  [attr-defined]
+ strawberry/channels/handlers/http_handler.py:207: error: Argument "headers" to "send_headers" of "AsyncHttpConsumer" has incompatible type "dict[bytes, bytes]"; expected "Iterable[tuple[bytes, bytes]] | None"  [arg-type]
+ strawberry/channels/handlers/http_handler.py:360: error: Return type "Coroutine[Any, Any, ChannelsResponse | MultipartChannelsResponse]" of "run" incompatible with return type "ChannelsResponse" in supertype "SyncBaseHTTPView"  [override]
- strawberry/channels/router.py:14: error: Cannot find implementation or library stub for module named "channels.routing"  [import-not-found]

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

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

I have some concerns about adding django-channels to typeshed. I would like to discuss them in detail here:

  1. Since django-stubs does not support pyright and other type checkers - what will be the result of adding these types here, where pyright and pytype are also included in the CI?
  2. What about different django versions? Does django-channels have any difference between them? We (django-stubs) only support the latest django version
  3. Does django-channels need any extra features? Would it benefit from a custom mypy plugin?

@Tatsh
Copy link
Contributor

Tatsh commented May 4, 2025

There is a very good example of usage of Channels here.

I have some concerns about adding django-channels to typeshed. I would like to discuss them in detail here:

  1. Since django-stubs does not support pyright and other type checkers - what will be the result of adding these types here, where pyright and pytype are also included in the CI?

From the way I've been using Channels, it will not pull in anything that will not work properly with Pyright such as an app's models.

  1. What about different django versions? Does django-channels have any difference between them? We (django-stubs) only support the latest django version

They only check for Django>=4.2.

  1. Does django-channels need any extra features? Would it benefit from a custom mypy plugin?

I do not believe so.

It is a somewhat active project so I think the typing should go in the project itself rather than here.

Copy link
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

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

(not a full review)

@@ -0,0 +1,7 @@
version = "4.*"
upstream_repository = "https://github.com/django/channels"
requires = ["django-stubs", "asgiref"]
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
requires = ["django-stubs", "asgiref"]
requires = ["django-stubs>=5.2,<5.3", "asgiref"]

Copy link
Author

Choose a reason for hiding this comment

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

Should I specify it as >=5.1 instead? It looks like Django Channels supports Django 4.2+, so I guess we can use a broader range for Django stubs to cover more versions (since Django stub 5.1 has partial support for Django 4.2). I haven’t tested it on older Django versions yet, but I guess the interface should be the same for those as well.

requires = ["django-stubs", "asgiref"]

[tool.stubtest]
skip = true # due to the need of django mypy plugin config, it should be skipped.
Copy link
Member

Choose a reason for hiding this comment

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

please, add a # TODO: comment here

from channels.utils import _ChannelApplication

# HTTP test-specific response type
class _HTTPTestResponse(TypedDict, total=False):
Copy link
Member

Choose a reason for hiding this comment

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

I propose adding this to new type-check only features:

Suggested change
class _HTTPTestResponse(TypedDict, total=False):
@type_check_only
class _HTTPTestResponse(TypedDict, total=False):

from django.test.testcases import TransactionTestCase
from django.test.utils import modify_settings

DaphneProcess: TypeAlias = Any
Copy link
Member

Choose a reason for hiding this comment

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

please, clarify why it is any

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.

3 participants