[Django] #35984: functools.singledispatchmethod on Django models don't work

11 views
Skip to first unread message

Django

unread,
Dec 8, 2024, 6:08:58 PM12/8/24
to django-...@googlegroups.com
#35984: functools.singledispatchmethod on Django models don't work
-----------------------+-----------------------------------------
Reporter: vodik | Type: Uncategorized
Status: new | Component: Uncategorized
Version: 5.1 | Severity: Normal
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-----------------------+-----------------------------------------
I'm on Django 4.2.17 and Python 3.13.1

The following code works on Python 3.12 and I believe
https://github.com/python/cpython/issues/85160 is the cause

When traversing a relationship and then calling a `singledispatchmethod`
method registered on a model, the reference to `self` seems to get cached
and locked to the first created model.

{{{#!python
class Test(models.Model):
...

class Test2(models.Model):
relationship = models.ForeignKey("Test", on_delete=models.CASCADE)

@singledispatchmethod
def bug(self, x):
print(">", id(self))

@bug.register
def _(self, x: int):
print(">", id(self))
}}}
and then it's pretty easy to trigger:
{{{#!python
for t in test.test2_set.all():
print("id:", id(t)) # always changes
t.bug(4) # only ever prints a single id
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35984>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 8, 2024, 6:09:18 PM12/8/24
to django-...@googlegroups.com
#35984: functools.singledispatchmethod on Django models don't work
-------------------------------+--------------------------------------
Reporter: vodik | Owner: (none)
Type: Uncategorized | Status: new
Component: Uncategorized | Version: 4.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by vodik):

* version: 5.1 => 4.2

--
Ticket URL: <https://code.djangoproject.com/ticket/35984#comment:1>

Django

unread,
Dec 8, 2024, 6:58:55 PM12/8/24
to django-...@googlegroups.com
#35984: functools.singledispatchmethod on Django models don't work
-------------------------------------+-------------------------------------
Reporter: Simon Gomizelj | Owner: (none)
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: needsinfo
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham):

* component: Uncategorized => Database layer (models, ORM)
* resolution: => needsinfo
* status: new => closed
* type: Uncategorized => Bug

Comment:

Why create a bug report here when you believe cpython is at fault? Feel
free to reopen with more explanation if you believe Django is at fault and
can explain what action we should take.
--
Ticket URL: <https://code.djangoproject.com/ticket/35984#comment:2>

Django

unread,
Dec 8, 2024, 7:11:26 PM12/8/24
to django-...@googlegroups.com
#35984: functools.singledispatchmethod on Django models don't work
-------------------------------------+-------------------------------------
Reporter: Simon Gomizelj | Owner: (none)
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: needsinfo
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Simon Gomizelj):

Because honestly I'm not sure. I can't seem to replicate this behaviour
outside of Django. Maybe Django is doing something non-standard. Either
way, I have filed a cpython issue as well. We'll see where that goes.
--
Ticket URL: <https://code.djangoproject.com/ticket/35984#comment:3>

Django

unread,
Dec 8, 2024, 7:28:23 PM12/8/24
to django-...@googlegroups.com
#35984: functools.singledispatchmethod on Django models don't work
-------------------------------------+-------------------------------------
Reporter: Simon Gomizelj | Owner: (none)
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: needsinfo
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Simon Gomizelj):

I know what the issue is. There's a weak key map under the hood:

{{{#!python
class singledispatchmethod:
# snip

def __get__(self, obj, cls=None):
if self._method_cache is not None:
try:
_method = self._method_cache[obj]
except TypeError:
self._method_cache = None
except KeyError:
pass
else:
return _method
}}}

Since Django models `__hash__` is driven by the pk, this is fundamentally
incompatible with this optimization.
--
Ticket URL: <https://code.djangoproject.com/ticket/35984#comment:4>

Django

unread,
Dec 8, 2024, 7:37:18 PM12/8/24
to django-...@googlegroups.com
#35984: functools.singledispatchmethod on Django models don't work
-------------------------------------+-------------------------------------
Reporter: Simon Gomizelj | Owner: (none)
Type: Bug | Status: closed
Component: Database layer | Version: 4.2
(models, ORM) |
Severity: Normal | Resolution: needsinfo
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Simon Gomizelj):

Apologies - absolutely a cpython bug. Pulling at this thread I figured out
how to replicate it with just the Python stdlib.
--
Ticket URL: <https://code.djangoproject.com/ticket/35984#comment:5>
Reply all
Reply to author
Forward
0 new messages