Skip to content
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

After upgrading to Django 4.2 LTS, I receive AttributeError on each page load. Using DDT 4.0.0 #1769

Closed
kunambi opened this issue May 6, 2023 · 23 comments · Fixed by #1770
Closed

Comments

@kunambi
Copy link

kunambi commented May 6, 2023

E0506 14:25:32.246 django.request:241 Internal Server Error: /dashboard/
Traceback (most recent call last):
  File "C:\Users\Owner\.virtualenvs\premind-6P0nJig8\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\Owner\.virtualenvs\premind-6P0nJig8\lib\site-packages\sentry_sdk\integrations\django\middleware.py", line 176, in __call__
    return f(*args, **kwargs)
  File "C:\Users\Owner\.virtualenvs\premind-6P0nJig8\lib\site-packages\debug_toolbar\middleware.py", line 64, in __call__
    panel.disable_instrumentation()
  File "C:\Users\Owner\.virtualenvs\premind-6P0nJig8\lib\site-packages\debug_toolbar\panels\cache.py", line 217, in disable_instrumentation
    self._unmonkey_patch_cache(cache)
  File "C:\Users\Owner\.virtualenvs\premind-6P0nJig8\lib\site-packages\debug_toolbar\panels\cache.py", line 171, in _unmonkey_patch_cache
    if original_method.__func__ == getattr(cache.__class__, name):
AttributeError: 'function' object has no attribute '__func__'

Commenting debug_toolbar.panels.cache.CachePanel allows DDT to continue to work.

# settings.py
MIDDLEWARE = [
    "django.middleware.gzip.GZipMiddleware",
]

if DEBUG_TOOLBAR:
    INSTALLED_APPS += ["debug_toolbar"]
    MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"]
    DEBUG_TOOLBAR_PANELS = [
        "debug_toolbar.panels.history.HistoryPanel",
        "debug_toolbar.panels.versions.VersionsPanel",
        "debug_toolbar.panels.timer.TimerPanel",
        "debug_toolbar.panels.settings.SettingsPanel",
        "debug_toolbar.panels.headers.HeadersPanel",
        "debug_toolbar.panels.request.RequestPanel",
        "debug_toolbar.panels.sql.SQLPanel",
        # 'debug_toolbar.panels.staticfiles.StaticFilesPanel',  # breaks if minio is enabled
        "debug_toolbar.panels.templates.TemplatesPanel",
        # "debug_toolbar.panels.cache.CachePanel",  # commenting this line allows DDT to continue to work
        "debug_toolbar.panels.signals.SignalsPanel",
        "debug_toolbar.panels.logging.LoggingPanel",
        "debug_toolbar.panels.redirects.RedirectsPanel",
        "debug_toolbar.panels.profiling.ProfilingPanel",
    ]

Please let me know if you need any more information in order to solve this issue

@tim-schilling
Copy link
Contributor

tim-schilling commented May 6, 2023 via email

@kunambi
Copy link
Author

kunambi commented May 6, 2023

I haven't done any additional patching, just trying to use DDT as usual.

My cache settings:

if env("CACHE_URL", default=None) is not None:
    CACHES = {
        "default": env.cache(),
    }
    if env("SESSION_CACHE_URL", default=None) is not None:
        CACHES["session"] = env.cache("SESSION_CACHE_URL")
        SESSION_ENGINE = "django.contrib.sessions.backends.cache"
        SESSION_CACHE_ALIAS = "session"

My environment file:

CACHE_URL=rediscache://localhost:6379/2
SESSION_CACHE_URL=rediscache://localhost:6379/3

@dimaulupov
Copy link

dimaulupov commented May 6, 2023

I have the same problem. It is weird that I somehow can't reproduce it locally.
Here is the stack trace:

AttributeError: 'function' object has no attribute '__func__'
  File "django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "debug_toolbar/middleware.py", line 64, in __call__
    panel.disable_instrumentation()
  File "debug_toolbar/panels/cache.py", line 217, in disable_instrumentation
    self._unmonkey_patch_cache(cache)
  File "debug_toolbar/panels/cache.py", line 171, in _unmonkey_patch_cache
    if original_method.__func__ == getattr(cache.__class__, name):

and sentry says this about locals on the last line:

cache: <django.core.cache.backends.redis.RedisCache object at 0x7f6395470e10>
name: 'get'
original_method: <function RedisCache.get at 0x7f63954cb2e0>

and cache settings as follows:

    "default": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
....
   }

@tim-schilling
Copy link
Contributor

tim-schilling commented May 6, 2023 via email

@tim-schilling
Copy link
Contributor

Can you give us more information about how this is running? Is it local via runserver? Is it using gunicorn, etc?

@kunambi
Copy link
Author

kunambi commented May 7, 2023

Are you sure your local instance matches the other environment? Are you using redis locally?

I'm running redis through a docker container

services:
  redis:
    image: redis:6
    ports:
      - "6379:6379"

The Django app is run through runserver

@matthiask
Copy link
Member

The cache call recording has changed a lot in django-debug-toolbar 3.5; could you check if this version also fails? That may be useful.

(I cannot reproduce the failure either.)

@matthiask
Copy link
Member

Addendum: I cannot reproduce it locally. I haven't tried running the toolbar in a production environment (my opinion and stance is that it is a bad idea)

@dimaulupov
Copy link

It is a weird thing. After many attempts - only hints on how to reproduce it.
So far I've managed only to somehow change stack trace! So maybe it is a different issue now.
Image that is running on two different container-based hosting platforms fails on both of them, but downloaded locally this same image works fine.
No need for redis. It is happening with LocMem cache as well.

As a workaround I've disabled cache panel. Now it works okay.
But if Cache panel is to be manually enabled - starting from second page reload (🤔) it starts failing.

  • It does not happen on version 3.4.0 and happens on 3.8.1 and 4.0.0.
  • It happens when it runs through uwsgi (2.0.21) inside image built based on python:3.11.3
  • Django 4.1.9
  • RedisCache, DatabaseCache and LocMem all have same behaviour.

Stack trace with LocMem:

AttributeError: 'function' object has no attribute '_djdt_wrapped'
  File "django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "debug_toolbar/middleware.py", line 64, in __call__
    panel.disable_instrumentation()
  File "debug_toolbar/panels/cache.py", line 217, in disable_instrumentation
    self._unmonkey_patch_cache(cache)
  File "debug_toolbar/panels/cache.py", line 170, in _unmonkey_patch_cache
    original_method = getattr(cache, name)._djdt_wrapped


Sentry's context:
cache: <django.core.cache.backends.locmem.LocMemCache object at 0x7f786ec059d0>
name: 'add'

Sorry about messy pip freeze, but maybe it will be helpful.

pip freeze
amqp==5.1.1
ansi2html==1.8.0
arabic-reshaper==3.0.0
asgiref==3.6.0
asn1crypto==1.5.1
astroid==2.15.4
asttokens==2.2.1
async-timeout==4.0.2
attrs==23.1.0
aws-encryption-sdk==3.1.1
backcall==0.2.0
bcrypt==4.0.1
beautifulsoup4==4.12.2
billiard==3.6.4.0
black==23.3.0
boto3==1.26.129
botocore==1.29.129
celery==5.2.7
certifi==2023.5.7
cffi==1.15.1
charset-normalizer==3.1.0
click==8.1.3
click-didyoumean==0.3.0
click-plugins==1.1.1
click-repl==0.2.0
cryptography==39.0.2
cssselect2==0.7.0
decorator==5.1.1
defusedxml==0.7.1
dill==0.3.6
Django==4.1.9
django-ace==1.19.0
django-allauth==0.54.0
django-amazon-ses==4.0.1
django-debug-toolbar==4.0.0
django-dirtyfields==1.9.2
django-pgactivity==1.1.1
django-pglock==1.1.0
django-pgtrigger==4.6.0
django-redis==5.2.0
dj-database-url==2.0.0
djhtml==3.0.6
dnspython==2.3.0
executing==1.2.0
fabric==2.7.1
factory-boy==3.2.1
Faker==18.6.2
filelock==3.12.0
freezegun==1.2.2
html5lib==1.1
idna==3.4
invoke==1.7.3
ipython==8.13.2
isort==5.12.0
jedi==0.18.2
jmespath==1.0.1
josepy==1.13.0
jsonpickle==3.0.1
kombu==5.2.4
lazy-object-proxy==1.9.0
lxml==4.9.2
matplotlib-inline==0.1.6
mccabe==0.7.0
mypy-extensions==1.0.0
netaddr==0.8.0
oauthlib==3.2.2
oscrypto==1.3.0
packaging==23.1
paramiko==2.12.0
parso==0.8.3
pathlib2==2.3.7.post1
pathspec==0.11.1
pexpect==4.8.0
pickleshare==0.7.5
Pillow==9.5.0
platformdirs==3.5.0
profilehooks==1.12.0
prometheus-client==0.16.0
prompt-toolkit==3.0.38
psutil==5.9.5
psycopg2==2.9.6
ptyprocess==0.7.0
pure-eval==0.2.2
pycparser==2.21
pycurl==7.44.1
Pygments==2.15.1
pyHanko==0.18.1
pyhanko-certvalidator==0.22.0
PyJWT==2.6.0
pylint==2.17.4
pylint-django==2.5.3
pylint-plugin-utils==0.7
PyNaCl==1.5.0
pyOpenSSL==23.1.1
pypdf==3.8.1
pypng==0.20220715.0
pyRFC3339==1.1
python3-openid==3.2.0
python-bidi==0.4.2
python-dateutil==2.8.2
python-digitalocean==1.17.0
pytz==2023.3
pytz-deprecation-shim==0.1.0.post0
PyYAML==6.0
qrcode==7.4.2
redis==4.5.4
reportlab==3.6.13
requests==2.30.0
requests-file==1.5.1
requests-oauthlib==1.3.1
s3transfer==0.6.1
sentry-sdk==1.22.1
simplejson==3.19.1
six==1.16.0
soupsieve==2.4.1
sqlparse==0.4.4
stack-data==0.6.2
stripe==5.4.0
structlog==22.3.0
svglib==1.5.1
tinycss2==1.2.1
tldextract==3.4.1
tomlkit==0.11.8
traitlets==5.9.0
typing_extensions==4.5.0
tzdata==2023.3
tzlocal==4.3
uritools==4.0.1
urllib3==1.26.15
uWSGI==2.0.21
vine==5.0.0
wcwidth==0.2.6
webencodings==0.5.1
wrapt==1.15.0
xhtml2pdf==0.2.11

Cache settings:

CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
        "KEY_PREFIX": "prefix",
        "VERSION": 1,
        "TIMEOUT": 24 * 60 * 60,
        "OPTIONS": {
            "MAX_ENTRIES": 5000,
            "CULL_FREQUENCY": 5,
        },
    },
}

@WhyNotHugo
Copy link
Member

I'm also seeing this after upgrading from django 4.1 to 4.2:

Environment:


Request Method: GET
Request URL: https://www.ideasenfoto.localhost:8000/admin/

Django Version: 4.2.1
Python Version: 3.11.2
Installed Applications:
['idf.core',
 'django.contrib.auth',
 'idf.auth',
 'idf.backoffice',
 'idf.admin',
 'idf.shipping',
 'idf.reports',
 'nested_admin',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'django.contrib.contenttypes',
 'polymorphic',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'django.contrib.gis',
 'ckeditor',
 'idf.coupons',
 'storages',
 'debug_toolbar',
 'django_afip',
 'django.contrib.postgres',
 'django_inlinecss',
 'rest_framework',
 'idf.sync',
 'idf.imaging',
 'idf.api',
 'idf.tenants',
 'manifest',
 'mptt',
 'payments',
 'anymail',
 'idf.emails']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/django/middleware.py", line 176, in __call__
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/debug_toolbar/middleware.py", line 64, in __call__
    panel.disable_instrumentation()
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/debug_toolbar/panels/cache.py", line 217, in disable_instrumentation
    self._unmonkey_patch_cache(cache)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/debug_toolbar/panels/cache.py", line 171, in _unmonkey_patch_cache
    if original_method.__func__ == getattr(cache.__class__, name):
       ^^^^^^^^^^^^^^^^^^^^^^^^

Exception Type: AttributeError at /admin/
Exception Value: 'function' object has no attribute '__func__'

I see sentry in the stacktrace there. AFAIK, sentry does some money-patching too, so there might be a conflict there.

My settings.py includes:

init_sentry(
    attach_stacktrace=True,
    before_send=before_send,
    integrations=[
        AwsLambdaIntegration(timeout_warning=True),
        CeleryIntegration(),
        DjangoIntegration(),
        LoggingIntegration(event_level=logging.WARNING),
    ],
    release=version,
    in_app_exclude=["logging"],
    ignore_errors=["idf.core.views.TestException"],
    traces_sample_rate=0,
    environment=TENANT_SLUG,
)

If I comment out this block, my site works again. It seems that the conflict arises when debug toolbar AND sentry are both present.

@matthiask
Copy link
Member

Ah yes, of course. A class instance with a __call__ method is callable but doesn't have a __func__ attribute. I bet that's what is happening. Excellent debugging!

(I wonder if we really should do that much work in disable_instrumentation or if we should just not record anything if the panel is inactive.)

@living180
Copy link
Contributor

Since I was the author of those changes I'll try to take a look.

@matthiask
Copy link
Member

Hi all. Can anyone test the current main version in an environment where they got crashes with django-debug-toolbar 4.0? I'd love if anyone could confirm that the latest changes fix the breakage before releasing another version which is broken for some people.

@kunambi
Copy link
Author

kunambi commented May 15, 2023

Hi @matthiask

Yes, I'll happily test it. Can you please share exactly what I should type in order to install the package accordingly?

TYIA

@matthiask
Copy link
Member

@kunambi I'd hope that pip install -U https://github.com/jazzband/django-debug-toolbar/archive/refs/heads/main.zip does the right thing and installs the current main version into your active virtualenv. Thanks!

@kunambi
Copy link
Author

kunambi commented May 15, 2023

After installing DDT according to your suggestion, and re-enabling the CachePanel, I see this error on page load:

Traceback (most recent call last):
  File "C:\Users\Owner\.virtualenvs\6P0nJig8\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\Owner\.virtualenvs\6P0nJig8\lib\site-packages\sentry_sdk\integrations\django\middleware.py", line 176, in __call__
    return f(*args, **kwargs)
  File "C:\Users\Owner\.virtualenvs\6P0nJig8\lib\site-packages\debug_toolbar\middleware.py", line 64, in __call__
    panel.disable_instrumentation()
  File "C:\Users\Owner\.virtualenvs\6P0nJig8\lib\site-packages\debug_toolbar\panels\cache.py", line 217, in disable_instrumentation
    self._unmonkey_patch_cache(cache)
  File "C:\Users\Owner\.virtualenvs\6P0nJig8\lib\site-packages\debug_toolbar\panels\cache.py", line 171, in _unmonkey_patch_cache
    if original_method.__func__ == getattr(cache.__class__, name):

Exception Type: AttributeError at /dashboard/
Exception Value: 'function' object has no attribute '__func__'

@tim-schilling
Copy link
Contributor

@kunambi you haven't installed the version from main. In the stack trace it's pointing to line 171 of panels/cache.py which on main is not if original_method.__func__ == getattr(cache.__class__, name): (see https://github.com/jazzband/django-debug-toolbar/blob/main/debug_toolbar/panels/cache.py#L171)

Maybe try uninstalling the toolbar first, then installing as per Matthias' instructions.

@kunambi
Copy link
Author

kunambi commented May 15, 2023

Uninstalling and then reinstalling with the ZIP-file from main, allows the CachePanels to work nicely!

image

@WhyNotHugo
Copy link
Member

main remains broken for me:

Environment:


Request Method: GET
Request URL: https://www.ideasenfoto.localhost:8000/

Django Version: 4.1.9
Python Version: 3.11.2
Installed Applications:
['idf.core',
 'django.contrib.auth',
 'idf.auth',
 'idf.backoffice',
 'idf.admin',
 'idf.shipping',
 'idf.reports',
 'nested_admin',
 'django.contrib.admin',
 'django.contrib.admindocs',
 'django.contrib.contenttypes',
 'polymorphic',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'django.contrib.gis',
 'ckeditor',
 'idf.coupons',
 'storages',
 'debug_toolbar',
 'django_afip',
 'django.contrib.postgres',
 'django_inlinecss',
 'rest_framework',
 'idf.sync',
 'idf.imaging',
 'idf.api',
 'idf.tenants',
 'manifest',
 'mptt',
 'payments',
 'anymail',
 'idf.emails']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.locale.LocaleMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 56, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.11/site-packages/sentry_sdk/integrations/django/middleware.py", line 176, in __call__
    return f(*args, **kwargs)
  File "/usr/local/lib/python3.11/site-packages/debug_toolbar/middleware.py", line 64, in __call__
    panel.disable_instrumentation()
  File "/usr/local/lib/python3.11/site-packages/debug_toolbar/panels/cache.py", line 217, in disable_instrumentation
    self._unmonkey_patch_cache(cache)
  File "/usr/local/lib/python3.11/site-packages/debug_toolbar/panels/cache.py", line 171, in _unmonkey_patch_cache
    if original_method.__func__ == getattr(cache.__class__, name):

Exception Type: AttributeError at /
Exception Value: 'function' object has no attribute '__func__'

Installed just now via pip install -U https://github.com/jazzband/django-debug-toolbar/archive/refs/heads/main.zip, which is now 1960ca3

@WhyNotHugo
Copy link
Member

WhyNotHugo commented May 15, 2023

Shall we re-open?

@living180
Copy link
Contributor

Just like #1769 (comment), that still looks like the non-updated code. Can you try uninstalling the toolbar and then installing from main.zip again?

@matthiask
Copy link
Member

Yeah, if __func__ still appears in the backtrace it's the old code.

Thanks @kunambi for confirming that the fix seems to work!

@WhyNotHugo
Copy link
Member

Yup, uninstalling and re-installing works.

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 a pull request may close this issue.

6 participants