]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Use preloaded for sql.util import in exc
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 7 Oct 2020 01:46:03 +0000 (21:46 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 7 Oct 2020 02:25:23 +0000 (22:25 -0400)
Repaired a function-level import that was not using SQLAlchemy's standard
late-import system within the sqlalchemy.exc module.

Moved preloaded to sqlalchemy.util.preloaded so that it
does not depend on langhelpers which depends on exc.

Fixes: #5632
Change-Id: I61b7ce9cd461071ce543714739f67aa5aeb47fd6

doc/build/changelog/unreleased_13/5632.rst [new file with mode: 0644]
lib/sqlalchemy/exc.py
lib/sqlalchemy/util/__init__.py
lib/sqlalchemy/util/_preloaded.py [new file with mode: 0644]
lib/sqlalchemy/util/langhelpers.py
test/base/test_utils.py

diff --git a/doc/build/changelog/unreleased_13/5632.rst b/doc/build/changelog/unreleased_13/5632.rst
new file mode 100644 (file)
index 0000000..fb90694
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, engine
+    :tickets: 5632
+
+    Repaired a function-level import that was not using SQLAlchemy's standard
+    late-import system within the sqlalchemy.exc module.
+
index 7e4a3f53eb8e75455ffc140817bc16d38828d1b7..7ba2e369b603c93c6d48a7730f4f7b69322560d5 100644 (file)
@@ -13,6 +13,7 @@ raised as a result of DBAPI exceptions are all subclasses of
 
 """
 
+from .util import _preloaded
 from .util import compat
 
 _version_token = None
@@ -416,8 +417,9 @@ class StatementError(SQLAlchemyError):
             ),
         )
 
+    @_preloaded.preload_module("sqlalchemy.sql.util")
     def _sql_message(self, as_unicode):
-        from sqlalchemy.sql import util
+        util = _preloaded.preloaded.sql_util
 
         details = [self._message(as_unicode=as_unicode)]
         if self.statement:
index 7ce0ce12bb5a74239cfb8597e610efa0a8e41446..8ef2f010321879f0cce341cc04c63a6f2171f096 100644 (file)
@@ -44,6 +44,8 @@ from ._collections import UniqueAppender  # noqa
 from ._collections import update_copy  # noqa
 from ._collections import WeakPopulateDict  # noqa
 from ._collections import WeakSequence  # noqa
+from ._preloaded import preload_module  # noqa
+from ._preloaded import preloaded  # noqa
 from .compat import ABC  # noqa
 from .compat import arm  # noqa
 from .compat import b  # noqa
@@ -149,8 +151,6 @@ from .langhelpers import NoneType  # noqa
 from .langhelpers import only_once  # noqa
 from .langhelpers import PluginLoader  # noqa
 from .langhelpers import portable_instancemethod  # noqa
-from .langhelpers import preload_module  # noqa
-from .langhelpers import preloaded  # noqa
 from .langhelpers import quoted_token_parser  # noqa
 from .langhelpers import safe_reraise  # noqa
 from .langhelpers import set_creation_order  # noqa
diff --git a/lib/sqlalchemy/util/_preloaded.py b/lib/sqlalchemy/util/_preloaded.py
new file mode 100644 (file)
index 0000000..1a833a9
--- /dev/null
@@ -0,0 +1,62 @@
+# util/_preloaded.py
+# Copyright (C) 2005-2020 the SQLAlchemy authors and contributors
+# <see AUTHORS file>
+#
+# This module is part of SQLAlchemy and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+"""supplies the "preloaded" registry to resolve circular module imports at
+runtime.
+
+"""
+
+import sys
+
+from . import compat
+
+
+class _ModuleRegistry:
+    """Registry of modules to load in a package init file.
+
+    To avoid potential thread safety issues for imports that are deferred
+    in a function, like https://bugs.python.org/issue38884, these modules
+    are added to the system module cache by importing them after the packages
+    has finished initialization.
+
+    A global instance is provided under the name :attr:`.preloaded`. Use
+    the function :func:`.preload_module` to register modules to load and
+    :meth:`.import_prefix` to load all the modules that start with the
+    given path.
+
+    While the modules are loaded in the global module cache, it's advisable
+    to access them using :attr:`.preloaded` to ensure that it was actually
+    registered. Each registered module is added to the instance ``__dict__``
+    in the form `<package>_<module>`, omitting ``sqlalchemy`` from the package
+    name. Example: ``sqlalchemy.sql.util`` becomes ``preloaded.sql_util``.
+    """
+
+    def __init__(self, prefix="sqlalchemy"):
+        self.module_registry = set()
+
+    def preload_module(self, *deps):
+        """Adds the specified modules to the list to load.
+
+        This method can be used both as a normal function and as a decorator.
+        No change is performed to the decorated object.
+        """
+        self.module_registry.update(deps)
+        return lambda fn: fn
+
+    def import_prefix(self, path):
+        """Resolve all the modules in the registry that start with the
+        specified path.
+        """
+        for module in self.module_registry:
+            key = module.split("sqlalchemy.")[-1].replace(".", "_")
+            if module.startswith(path) and key not in self.__dict__:
+                compat.import_(module, globals(), locals())
+                self.__dict__[key] = sys.modules[module]
+
+
+preloaded = _ModuleRegistry()
+preload_module = preloaded.preload_module
index 85a065e999fe0bc5dca8818443b2cc67b38864b8..e546f196d511ef2ff10333e705d2931b33e693e1 100644 (file)
@@ -1044,53 +1044,6 @@ class MemoizedSlots(object):
             return self._fallback_getattr(key)
 
 
-class _ModuleRegistry:
-    """Registry of modules to load in a package init file.
-
-    To avoid potential thread safety issues for imports that are deferred
-    in a function, like https://bugs.python.org/issue38884, these modules
-    are added to the system module cache by importing them after the packages
-    has finished initialization.
-
-    A global instance is provided under the name :attr:`.preloaded`. Use
-    the function :func:`.preload_module` to register modules to load and
-    :meth:`.import_prefix` to load all the modules that start with the
-    given path.
-
-    While the modules are loaded in the global module cache, it's advisable
-    to access them using :attr:`.preloaded` to ensure that it was actually
-    registered. Each registered module is added to the instance ``__dict__``
-    in the form `<package>_<module>`, omitting ``sqlalchemy`` from the package
-    name. Example: ``sqlalchemy.sql.util`` becomes ``preloaded.sql_util``.
-    """
-
-    def __init__(self, prefix="sqlalchemy"):
-        self.module_registry = set()
-
-    def preload_module(self, *deps):
-        """Adds the specified modules to the list to load.
-
-        This method can be used both as a normal function and as a decorator.
-        No change is performed to the decorated object.
-        """
-        self.module_registry.update(deps)
-        return lambda fn: fn
-
-    def import_prefix(self, path):
-        """Resolve all the modules in the registry that start with the
-        specified path.
-        """
-        for module in self.module_registry:
-            key = module.split("sqlalchemy.")[-1].replace(".", "_")
-            if module.startswith(path) and key not in self.__dict__:
-                compat.import_(module, globals(), locals())
-                self.__dict__[key] = sys.modules[module]
-
-
-preloaded = _ModuleRegistry()
-preload_module = preloaded.preload_module
-
-
 # from paste.deploy.converters
 def asbool(obj):
     if isinstance(obj, compat.string_types):
index d765a46131ad239aa85bea8d5b249f235d36c1e4..fa347243e7555127c47f417fa6158e32b1280a31 100644 (file)
@@ -24,6 +24,7 @@ from sqlalchemy.testing import mock
 from sqlalchemy.testing import ne_
 from sqlalchemy.testing.util import gc_collect
 from sqlalchemy.testing.util import picklers
+from sqlalchemy.util import _preloaded
 from sqlalchemy.util import classproperty
 from sqlalchemy.util import compat
 from sqlalchemy.util import get_callable_argspec
@@ -3210,7 +3211,7 @@ class TestModuleRegistry(fixtures.TestBase):
         for m in ("xml.dom", "wsgiref.simple_server"):
             to_restore.append((m, sys.modules.pop(m, None)))
         try:
-            mr = langhelpers._ModuleRegistry()
+            mr = _preloaded._ModuleRegistry()
 
             ret = mr.preload_module(
                 "xml.dom", "wsgiref.simple_server", "sqlalchemy.sql.util"