From 5f9e5c1b0d5680f793ba7646d52ffab9e2c3623f Mon Sep 17 00:00:00 2001 From: Nick Pope Date: Tue, 21 Nov 2023 19:29:21 +0000 Subject: [PATCH] Refs #34822, Refs #34986 -- Fixed migrations serializer support for functools.lru_cache(). It turns out that `functools._lru_cache_wrapper` is only a class when CPython's _functools C module provides it, otherwise it is a function. PyPy also provides it as a function. --- django/db/migrations/serializer.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py index 69e10fd41b4..4f61a69cd47 100644 --- a/django/db/migrations/serializer.py +++ b/django/db/migrations/serializer.py @@ -18,6 +18,15 @@ from django.db.migrations.utils import COMPILED_REGEX_TYPE, RegexObject from django.utils.functional import LazyObject, Promise from django.utils.version import PY311, get_docs_version +FUNCTION_TYPES = (types.FunctionType, types.BuiltinFunctionType, types.MethodType) + +if isinstance(functools._lru_cache_wrapper, type): + # When using CPython's _functools C module, LRU cache function decorators + # present as a class and not a function, so add that class to the list of + # function types. In the pure Python implementation and PyPy they present + # as normal functions which are already handled. + FUNCTION_TYPES += (functools._lru_cache_wrapper,) + class BaseSerializer: def __init__(self, value): @@ -346,12 +355,7 @@ class Serializer: (bool, int, types.NoneType, bytes, str, range): BaseSimpleSerializer, decimal.Decimal: DecimalSerializer, (functools.partial, functools.partialmethod): FunctoolsPartialSerializer, - ( - types.FunctionType, - types.BuiltinFunctionType, - types.MethodType, - functools._lru_cache_wrapper, - ): FunctionTypeSerializer, + FUNCTION_TYPES: FunctionTypeSerializer, collections.abc.Iterable: IterableSerializer, (COMPILED_REGEX_TYPE, RegexObject): RegexSerializer, uuid.UUID: UUIDSerializer,