Since the recent version of daphne (2.3.0) added support for ASGI3, I no longer can't use channels (2.2.0).
https://github.com/django/daphne/blob/master/daphne/cli.py#L30
Here it would likely to call channel's router ( ProtocolTypeRouter) with additional two parameters (send, receive) which by now (https://github.com/django/channels/blob/2486738765064525cd8ee39294c44600140476ac/channels/routing.py#L56) is not supported.
Can we have support for ASGI3?
As for now, I just created subclass of ProtocolTypeRouter like below to support ASGI3.
from channels.routing import ProtocolTypeRouter
class CustomSocketioProtocolTypeRouter(ProtocolTypeRouter):
"""
Overrided base class's __call__ method to support python socketio 4.2.0 and daphne 2.3.0
"""
def __call__(self, scope, *args):
if scope["type"] in self.application_mapping:
handlerobj = self.application_mapping[scope["type"]](scope)
if args:
return handlerobj(*args)
return handlerobj
raise ValueError(
"No application configured for scope type %r" % scope["type"]
)
application = CustomSocketioProtocolTypeRouter({
# (http->django views is added by default)
})
This is related to #1316.
Can we have support for ASGI3?
Short answer, yes.
I'm working on an update for Daphne now, and then will be coming back to update Channels.
Any help in the form of PRs towards that would be awesome!
As for now, I just created subclass of
ProtocolTypeRouterlike below to support ASGI3.from channels.routing import ProtocolTypeRouter class CustomSocketioProtocolTypeRouter(ProtocolTypeRouter): """ Overrided base class's __call__ method to support python socketio 4.2.0 and daphne 2.3.0 """ def __call__(self, scope, *args): if scope["type"] in self.application_mapping: handlerobj = self.application_mapping[scope["type"]](scope) if args: return handlerobj(*args) return handlerobj raise ValueError( "No application configured for scope type %r" % scope["type"] ) application = CustomSocketioProtocolTypeRouter({ # (http->django views is added by default) })Hi, could you share how you solved it? I can't get it to work.
N.B. you should be able to wrap Channels ASGI 2 apps with asgiref.compatibility.guarantee_single_callable - https://github.com/django/asgiref/blob/master/asgiref/compatibility.py#L39 - to convert it to ASGI 3.
piggybacking on this @adamchainz i tried your solution and wrapped my application in asgi.py using compatibility.guarantee_single_callable(get_asgi_application()) but when i run my app i'm still getting the TypeError: __call__() missing 2 required positional arguments: 'receive' and 'send' implying it's still ASGI3
I think you’re wrapping the wrong app @mburke05 .
hm, i've tried wrapping:
application = compatibility.guarantee_single_callable(
ProtocolTypeRouter({
# (http->django views is added by default)
})
) in routing.py
assuming that's what you mean, but i'm getting the same result. (Django=3.0.2,channels=2.4.0)
just for posterity the full error:
HTTP GET / 500 [0.00, 172.20.0.1:50300]
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/daphne/http_protocol.py", line 163, in process
self.application_queue = yield maybeDeferred(
TypeError: new_application() missing 2 required positional arguments: 'receive' and 'send'
edit: fwiw i fixed this it looks like with a fresh install (i think it may have been a result of twisted not behaving with windows 10 but unsure), but i'll leave it in case the app wrapping question gets answered for someone in the future)
@carltongibson I'd love to help out with this. Any advice for where to start?
Hi @jaydenwindle. Take a look here: https://asgi.readthedocs.io/en/latest/specs/main.html#applications — This explains the change from the double to single callable.
For now we can just wrap our channels apps, as @adamchainz says. First step might be to add a note to that effect to the docs.
But longer term, and this is #1316 too is to migrate everything across to single callable.
It's a bit of a job, because all the consumers will need adjusting, which is why it's still here.
It's in the _Nice Project_ scale for someone (maybe you 🙂).
Maybe we could adjust the various Routers to the new style first, using asgiref.compatibility to embed consumers. Then the consumers and so on.
If you want to take this on, I'd be very happy to support you: we would need to work out a roadmap and document where we were for people adapting, but it should be possible to do it incrementally. And it does need doing.
@jaydenwindle There aren't that many classes. Maybe it makes sense to bump them all at once and do a major version release with a migration guide. That's a bigger chunk of work all at once though...
@carltongibson Sounds good! I'd love to take this on.
I think it makes sense to release the ASGI 3 changes all at once. I'll raise a couple of PRs for this so it's easier to review. Using asgiref.compatibility should make it easy enough to refactor the different groups (routers, consumers, etc) without too many conflicts. Then we can merge them into a feature branch and do a major version release.
Do we want to add in deprecation warnings for users that are still using the legacy-style double callables?
Do we want to add in deprecation warnings for users that are still using the legacy-style double callables?
Not sure yet. Argh! 🙂 — Start and I'll try it out and see what I need to do to migrate. The difficulty is going to be when we've subclassed the generic consumers. I'm guessing the upgrade steps will be enough of a warning.
@carltongibson Haha alright, sounds good 🙂
As for now, I just created subclass of
ProtocolTypeRouterlike below to support ASGI3.from channels.routing import ProtocolTypeRouter class CustomSocketioProtocolTypeRouter(ProtocolTypeRouter): """ Overrided base class's __call__ method to support python socketio 4.2.0 and daphne 2.3.0 """ def __call__(self, scope, *args): if scope["type"] in self.application_mapping: handlerobj = self.application_mapping[scope["type"]](scope) if args: return handlerobj(*args) return handlerobj raise ValueError( "No application configured for scope type %r" % scope["type"] ) application = CustomSocketioProtocolTypeRouter({ # (http->django views is added by default) })
This worked for me when i had this issue today. I'm following the tutorial on read the docs.
Most helpful comment
N.B. you should be able to wrap Channels ASGI 2 apps with
asgiref.compatibility.guarantee_single_callable- https://github.com/django/asgiref/blob/master/asgiref/compatibility.py#L39 - to convert it to ASGI 3.