The following code works on Python 3.12 and I believe #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.
Since dictionaries use __hash__/__eq__ for determining if a key is present, we can have collisions. Django hashs models based on the primary key. Here's a way to reproduce the same bug with just the stdlib:
fromfunctoolsimportsingledispatchmethodfromdataclassesimportdataclass@dataclass(frozen=True) # or (unsafe_hash=True)classTest:
pk: int@singledispatchmethoddefbroken(self, x):
raiseNotImplemenetedError@broken.registerdef_(self, x: int):
returnid(self)
t1=Test(1)
print(id(t1))
t2=Test(1)
print(id(t2))
assertid(t1) ==t1.broken(2) # both t1 and t2 will share the same dispatcherassertid(t2) ==t2.broken(2) # fails!
Activity
vodik commented on Dec 9, 2024
I see what the issue is now: https://github.com/AlexWaygood/cpython/blob/3d8d4ba5f5367f2d87488b00afd55f75401c2b7d/Lib/functools.py#L950
Since dictionaries use __hash__/__eq__ for determining if a key is present, we can have collisions. Django hashs models based on the primary key. Here's a way to reproduce the same bug with just the stdlib:
vodik commented on Dec 9, 2024
I have a fix, I think. Working on a PR.
pythongh-127750: Improve singledispatchmethod caching
pythongh-127750: Improve singledispatchmethod caching
pythongh-127750: Improve singledispatchmethod caching
vodik commented on Dec 9, 2024
I'm pretty sure the code in question is also leaking memory. See comment here.
eendebakpt commented on Dec 9, 2024
@vodik There is indeed a behavior change between 3.12 and 3.13, so perhaps that needs to be fixed. Another example showing the issue is:
8 remaining items
gh-127750: Restore inspect and pydoc support of singledispatchmethod (G…
[3.13] pythongh-127750: Restore inspect and pydoc support of singledi…
[3.13] pythongh-127750: Backport some tests for singledispatchmethod (p…
[3.13] gh-127750: Backport some tests for singledispatchmethod (GH-13…
[3.13] pythongh-127750: Backport some tests for singledispatchmethod (p…
[3.12] gh-127750: Backport some tests for singledispatchmethod (GH-13…
gh-127750: Improve repr of functools.singledispatchmethod (GH-130220)
gh-127750: Fix annotations in singledispatchmethod signature tests (G…
pythongh-127750: Fix annotations in singledispatchmethod signature te…
pythongh-127750: Fix annotations in singledispatchmethod signature te…
[3.13] gh-127750: Fix annotations in singledispatchmethod signature t…
[3.14] gh-127750: Fix annotations in singledispatchmethod signature t…
pythongh-127750: Fix annotations in singledispatchmethod signature te…
pythongh-127750: Fix annotations in singledispatchmethod signature te…