From: Mike Bayer Date: Thu, 20 Jan 2022 14:31:42 +0000 (-0500) Subject: repair mapper sort X-Git-Tag: rel_1_4_31~4^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3ee2a731b4a3e4177293104e47c4cf1fc7b9a11;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git repair mapper sort Fixed issue in :meth:`_orm.Session.bulk_save_mappings` where the sorting that takes place when the ``preserve_order`` parameter is set to False would sort partially on ``Mapper`` objects, which is rejected in Python 3.11. Also uses typing_extensions for NotRequired as this symbol does not seem to be in Python 3.11.0a4 yet. (2.0 only) Fixes: #7591 Change-Id: I24a62f2322ad7dac5d8e4a00853f8a9408877c9c (cherry picked from commit 8d3d934c16a91adcdc7f374c01761b18fbba74d9) --- diff --git a/doc/build/changelog/unreleased_14/7591.rst b/doc/build/changelog/unreleased_14/7591.rst new file mode 100644 index 0000000000..4ecf983d11 --- /dev/null +++ b/doc/build/changelog/unreleased_14/7591.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, orm + :tickets: 7591 + + Fixed issue in :meth:`_orm.Session.bulk_save_mappings` where the sorting + that takes place when the ``preserve_order`` parameter is set to False + would sort partially on ``Mapper`` objects, which is rejected in Python + 3.11. + diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 49e8060d08..d5a80953d6 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -3602,14 +3602,24 @@ class Session(_SessionClassMethods): """ - def key(state): - return (state.mapper, state.key is not None) - obj_states = (attributes.instance_state(obj) for obj in objects) + if not preserve_order: - obj_states = sorted(obj_states, key=key) + # the purpose of this sort is just so that common mappers + # and persistence states are grouped together, so that groupby + # will return a single group for a particular type of mapper. + # it's not trying to be deterministic beyond that. + obj_states = sorted( + obj_states, + key=lambda state: (id(state.mapper), state.key is not None), + ) - for (mapper, isupdate), states in itertools.groupby(obj_states, key): + def grouping_key(state): + return (state.mapper, state.key is not None) + + for (mapper, isupdate), states in itertools.groupby( + obj_states, grouping_key + ): self._bulk_save_mappings( mapper, states,