From 4a5e41a2d1d550f341394d06fe392c879fa8faff Mon Sep 17 00:00:00 2001 From: Yilei Yang Date: Thu, 21 Dec 2023 02:47:03 -0500 Subject: [PATCH] Use a copy of `self.contents` in this list comprehension. Improved a fix first implemented for :ticket:`3208` released in version 0.9.8, where the registry of classes used internally by declarative could be subject to a race condition in the case where individual mapped classes are being garbage collected at the same time while new mapped classes are being constructed, as can happen in some test suite configurations or dynamic class creation environments. In addition to the weakref check already added, the list of items being iterated is also copied first to avoid "list changed while iterating" errors. Pull request courtesy Yilei Yang. Fixes: #10782 Closes: #10783 Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10783 Pull-request-sha: 354e97b640430120d0c193a4efe487f293d4768b Change-Id: I04ccc92472bf1004dad0fb785e16b180f58f101d (cherry picked from commit 0fe5d3ca51884b85b4059ed05b53f02172325e70) --- doc/build/changelog/unreleased_14/10782.rst | 15 +++++++++++++++ lib/sqlalchemy/orm/clsregistry.py | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 doc/build/changelog/unreleased_14/10782.rst diff --git a/doc/build/changelog/unreleased_14/10782.rst b/doc/build/changelog/unreleased_14/10782.rst new file mode 100644 index 0000000000..d7b219a365 --- /dev/null +++ b/doc/build/changelog/unreleased_14/10782.rst @@ -0,0 +1,15 @@ +.. change:: + :tags: bug, orm + :tickets: 10782 + :versions: 2.0.24, 1.4.51 + + Improved a fix first implemented for :ticket:`3208` released in version + 0.9.8, where the registry of classes used internally by declarative could + be subject to a race condition in the case where individual mapped classes + are being garbage collected at the same time while new mapped classes are + being constructed, as can happen in some test suite configurations or + dynamic class creation environments. In addition to the weakref check + already added, the list of items being iterated is also copied first to + avoid "list changed while iterating" errors. Pull request courtesy Yilei + Yang. + diff --git a/lib/sqlalchemy/orm/clsregistry.py b/lib/sqlalchemy/orm/clsregistry.py index fda5d11102..36a42f3e35 100644 --- a/lib/sqlalchemy/orm/clsregistry.py +++ b/lib/sqlalchemy/orm/clsregistry.py @@ -164,11 +164,11 @@ class _MultipleClassMarker(object): def add_item(self, item): # protect against class registration race condition against # asynchronous garbage collection calling _remove_item, - # [ticket:3208] + # [ticket:3208] and [ticket:10782] modules = set( [ cls.__module__ - for cls in [ref() for ref in self.contents] + for cls in [ref() for ref in list(self.contents)] if cls is not None ] ) -- 2.47.2