django / channels

Developer-friendly asynchrony for Django

Home Page:https://channels.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Djangos get_response method seems to return a None and channels crashes because of it

Kaju-Bubanja opened this issue · comments

  • Ubuntu 22.04, Firefox 106.0.3, python 3.6(yes, we know it's old, we are migrating starting next year, but as far as I read the docs it's still supported)
  • A pip freeze output showing your package versions
aiocontextvars==0.2.2
aioredis==1.3.1
alabaster==0.7.12
amqp==5.1.1
arrow==1.2.3
asgiref==3.4.1
async-timeout==4.0.2
attrs==22.1.0
autobahn==21.2.1
Automat==20.2.0
Babel==2.10.3
billiard==3.6.4.0
cached-property==1.5.2
celery==5.1.2
certifi==2022.6.15.1
cffi==1.15.1
channels==3.0.4
channels-redis==2.4.2
charset-normalizer==2.0.12
click==7.1.2
click-didyoumean==0.3.0
click-plugins==1.1.1
click-repl==0.2.0
colorama==0.4.5
ConfigArgParse==1.5.3
constantly==15.1.0
construct==2.10.56
contextvars==2.4
cryptography==38.0.1
cycler==0.11.0
daphne==3.0.2
dataclasses==0.8
decorator==5.1.1
Deprecated==1.2.13
Django==3.2.15
django-grappelli==3.0.3
django-mathfilters==1.0.0
django-wkhtmltopdf==3.4.0
docutils==0.18.1
Dozer==0.8
em==0.4.0
ephem==4.1.3
Flask==2.0.3
Flask-Executor==1.0.0
FormEncode==2.0.1
geographiclib==1.52
geopy==2.2.0
gphoto2==2.3.4
gps3==0.33.3
hiredis==2.0.0
hyperlink==21.0.0
idna==3.3
imagesize==1.4.1
immutables==0.18
importlib-metadata==4.8.3
importlib-resources==5.4.0
imutils==0.5.4
incremental==21.3.0
iniconfig==1.1.1
itsdangerous==2.0.1
Jinja2==3.0.3
kiwisolver==1.3.1
kombu==5.1.0
lark==1.1.2
loguru==0.6.0
Mako==1.1.6
MarkupSafe==2.0.1
massedit==0.69.1
matplotlib==3.3.4
memory-profiler==0.60.0
mido==1.2.10
mpmath==1.2.1
msgpack==0.6.2
msgpack-python==0.5.6
mysqlclient==2.1.1
natsort==8.2.0
netifaces==0.11.0
numpy==1.19.5
opencv-python==4.5.4.60
osa==0.2
packaging==21.3
paho-mqtt==1.6.1
pandas==1.1.5
pendulum==2.1.2
piexif==1.1.3
Pillow==8.4.0
pkg_resources==0.0.0
pluggy==1.0.0
prompt-toolkit==3.0.31
protobuf==3.19.4
psutil==5.9.2
py==1.11.0
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.21
PyDispatcher==2.0.6
Pygments==2.13.0
Pympler==1.0.1
pynmea2==1.18.0
pyOpenSSL==22.0.0
pyparsing==3.0.7
pyserial==3.5
pytest==7.0.1
python-dateutil==2.8.2
python-gammu==2.6
python-rtmidi==1.4.9
pytz==2022.2.1
pytzdata==2020.1
pyudev==0.23.2
PyYAML==6.0
pyzmq==23.2.1
redis==4.3.4
redis-dump-load==1.1
requests==2.27.1
schedule==1.1.0
scipy==1.5.4
seaborn==0.11.2
service-identity==21.1.0
six==1.16.0
snowballstemmer==2.2.0
Sphinx==5.1.1
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
SQLObject==3.9.1
sqlparse==0.4.2
sympy==1.9
tomli==1.2.3
tqdm==4.63.2
transitions==0.9.0
Twisted==22.4.0
txaio==22.2.1
typing_extensions==4.1.1
uptime==3.0.1
urllib3==1.26.12
validators==0.20.0
vine==5.0.0
Wand==0.6.10
wcwidth==0.2.5
WebOb==1.8.7
Werkzeug==2.0.3
wrapt==1.14.1
zipp==3.6.0
zmq==0.0.0
zope.interface==5.4.0

  • Channels http.py handle method errors with following stacktrace
2022-11-09 16:38:14.502 ERROR daphne.server:server.py:293 Exception inside application: 'NoneType' object has no attribute 'items'
Traceback (most recent call last):
  File "/home/username/app/lib/python3.6/site-packages/channels/staticfiles.py", line 41, in __call__
    dict(scope, static_base_url=self.base_url), receive, send
  File "/home/username/app/lib/python3.6/site-packages/channels/staticfiles.py", line 56, in __call__
    return await super().__call__(scope, receive, send)
  File "/home/username/app/lib/python3.6/site-packages/channels/http.py", line 198, in __call__
    await self.handle(scope, async_to_sync(send), body_stream)
  File "/home/username/app/lib/python3.6/site-packages/asgiref/sync.py", line 444, in __call__
    ret = await asyncio.wait_for(future, timeout=None)
  File "/usr/lib/python3.6/asyncio/tasks.py", line 339, in wait_for
    return (yield from fut)
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/home/username/app/lib/python3.6/site-packages/asgiref/sync.py", line 486, in thread_handler
    return func(*args, **kwargs)
  File "/home/username/app/lib/python3.6/site-packages/channels/http.py", line 255, in handle
    for response_message in self.encode_response(response):
  File "/home/username/app/lib/python3.6/site-packages/channels/http.py", line 311, in encode_response
    for header, value in response.items():
AttributeError: 'NoneType' object has no attribute 'items'

Djangos get_response method seems to return a None. Not sure if this is a channels bug and it should be able to handle None as a response or this is a Django bug and self.get_response(request) should never return None

  • How you're running Channels (runserver? daphne/runworker? Nginx/Apache in front?)
    sudo /home/username/app/bin/python manage.py runserver 0.0.0.0:80 --insecure no nginx or apache

The application definition is:

from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from channels.security.websocket import AllowedHostsOriginValidator
from django.urls import re_path

application = ProtocolTypeRouter({
    # (http->django views is added by default)
    'websocket': AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                re_path(r"^app_name/ws", AppConsumer.as_asgi()),
            ])
        )
    )
})

and the consumer is defined as:

from django.db import close_old_connections
from channels.generic.websocket import AsyncJsonWebsocketConsumer

class AppConsumer(AsyncJsonWebsocketConsumer):
    async def connect(self):
        await self.accept()
        await self.channel_layer.group_add("app_ws", self.channel_name)

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard("app_ws", self.channel_name)

    async def app_message(self, event):
        await self.send_json(event)

    async def receive_json(self, content, **kwargs):
        if 'request' in content:
            close_old_connections()
            await self.send_json({"text": get_text(), "channel": content['request']})

Sorry, there's not enough to say anything here. A minimal reproduce would be helpful.