]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
repair mapper sort
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 20 Jan 2022 14:31:42 +0000 (09:31 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 20 Jan 2022 19:46:09 +0000 (14:46 -0500)
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.

For interim 3.11 support, adds the git main build of greenlet
for Python 3.11

Fixes: #7591
Change-Id: I24a62f2322ad7dac5d8e4a00853f8a9408877c9c

doc/build/changelog/unreleased_14/7591.rst [new file with mode: 0644]
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/util/typing.py
setup.cfg
tox.ini

diff --git a/doc/build/changelog/unreleased_14/7591.rst b/doc/build/changelog/unreleased_14/7591.rst
new file mode 100644 (file)
index 0000000..4ecf983
--- /dev/null
@@ -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.
+
index aa642e65eedf7e78b4a020ca4c24a7820c0c5cf6..cf47ee72990fe1c9c3687e6cec913664b20052be 100644 (file)
@@ -3389,14 +3389,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,
index e2d42db6e0a3c30b87b7971cfcc2087cffee2e61..5767d258b0a27ad55de57dc3be1bb2384223bfa3 100644 (file)
@@ -6,6 +6,8 @@ from typing import Type
 from typing import TypeVar
 from typing import Union
 
+from typing_extensions import NotRequired  # noqa
+
 from . import compat
 
 _T = TypeVar("_T", bound=Any)
@@ -26,11 +28,6 @@ else:
     from typing_extensions import Concatenate  # noqa
     from typing_extensions import ParamSpec  # noqa
 
-if compat.py311:
-    from typing import NotRequired  # noqa
-else:
-    from typing_extensions import NotRequired  # noqa
-
 
 _T = TypeVar("_T")
 
index c88cd96d5cc68a639d7b0f9059d5ea3824e4a9c4..e841348cec13378528e63943650785ccc87fc06a 100644 (file)
--- a/setup.cfg
+++ b/setup.cfg
@@ -37,7 +37,7 @@ package_dir =
 install_requires =
     importlib-metadata;python_version<"3.8"
     greenlet != 0.4.17;(platform_machine=='aarch64' or (platform_machine=='ppc64le' or (platform_machine=='x86_64' or (platform_machine=='amd64' or (platform_machine=='AMD64' or (platform_machine=='win32' or platform_machine=='WIN32'))))))
-    typing-extensions >= 4;python_version<"3.11"
+    typing-extensions >= 4
 
 [options.extras_require]
 asyncio =
diff --git a/tox.ini b/tox.ini
index def210826091c1766ec5f486e208530632ef6325..89bac9cc26e5820d815bf34afb5126353ea13243 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -19,6 +19,9 @@ deps=
      pytest>=7.0.0rc1,<8
      pytest-xdist
 
+     # note cython not working for 3.11 at all right now
+     git+https://github.com/python-greenlet/greenlet.git#egg=greenlet; python_version >= '3.11'
+
      sqlite: .[aiosqlite]
      sqlite_file: .[aiosqlite]
      sqlite_file: .[sqlcipher]; python_version < '3.10'