]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Adjusted the "importlater" mechanism, which is
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 21 Sep 2011 20:56:14 +0000 (16:56 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 21 Sep 2011 20:56:14 +0000 (16:56 -0400)
     used internally to resolve import cycles,
     such that the usage of __import__ is completed
     when the import of sqlalchemy or sqlalchemy.orm
     is done, thereby avoiding any usage of __import__
     after the application starts new threads,
     fixes [ticket:2279].  Also in 0.6.9.

CHANGES
lib/sqlalchemy/__init__.py
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/sql/__init__.py
lib/sqlalchemy/util/langhelpers.py

diff --git a/CHANGES b/CHANGES
index 4d16c708dd8dab4a9b397398d20cfde8bf8f7286..5b9ed4c96b2b5e409b2380b11776c5d225b3d05f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -5,6 +5,15 @@ CHANGES
 =======
 0.7.3
 =====
+- general
+   - Adjusted the "importlater" mechanism, which is
+     used internally to resolve import cycles,
+     such that the usage of __import__ is completed
+     when the import of sqlalchemy or sqlalchemy.orm
+     is done, thereby avoiding any usage of __import__
+     after the application starts new threads,
+     fixes [ticket:2279].  Also in 0.6.9.
+
 - orm
    - Added after_soft_rollback() Session event.  This
      event fires unconditionally whenever rollback()
index c15cc6b693de2accf109401466c3b9596444d9ab..0b9b7a00e9f11440ae956ef989b42c78c0cf98b0 100644 (file)
@@ -120,3 +120,6 @@ __all__ = sorted(name for name, obj in locals().items()
 __version__ = '0.7.3'
 
 del inspect, sys
+
+from sqlalchemy import util as _sa_util
+_sa_util.importlater.resolve_all()
\ No newline at end of file
index f6b02eaa83a0b0b790b343b750c43496691d7f1f..b7f7884f24a3f01ee629bfe1971d7b81b1de966d 100644 (file)
@@ -1458,3 +1458,6 @@ def undefer_group(name):
 
     """
     return strategies.UndeferGroupOption(name)
+
+from sqlalchemy import util as _sa_util
+_sa_util.importlater.resolve_all()
\ No newline at end of file
index 893d6ea2a717428457cf828c93f2a9cbe381c6ff..334d6d3786fb241fa39c76d13155221abe610ea7 100644 (file)
@@ -21,7 +21,7 @@ from itertools import chain
 from sqlalchemy import exc as sa_exc
 from sqlalchemy import util
 from sqlalchemy.sql import operators
-deque = util.importlater('collections').deque
+deque = __import__('collections').deque
 
 mapperutil = util.importlater('sqlalchemy.orm', 'util')
 
index c591e6802ec0fb9aab488731a4aa32addd944e56..1b82847814be02ef2aef2d71df19fb5d6dda447c 100644 (file)
@@ -64,3 +64,4 @@ from sqlalchemy.sql.visitors import ClauseVisitor
 
 __tmp = locals().keys()
 __all__ = sorted([i for i in __tmp if not i.startswith('__')])
+
index 4dd9a52706bc4ab8c8a6809abc381b7347dac6c1..cf8b2acac816aa176d7cb383373e65f6c85082a6 100644 (file)
@@ -527,37 +527,67 @@ class importlater(object):
         from mypackage.somemodule import somesubmod
 
     except evaluted upon attribute access to "somesubmod".
+    
+    importlater() currently requires that resolve_all() be
+    called, typically at the bottom of a package's __init__.py.
+    This is so that __import__ still called only at 
+    module import time, and not potentially within
+    a non-main thread later on.
 
     """
+
+    _unresolved = set()
+
     def __init__(self, path, addtl=None):
         self._il_path = path
         self._il_addtl = addtl
+        importlater._unresolved.add(self)
+
+    @classmethod
+    def resolve_all(cls):
+        for m in list(importlater._unresolved):
+            m._resolve()
+
+    @property
+    def _full_path(self):
+        if self._il_addtl:
+            return self._il_path + "." + self._il_addtl
+        else:
+            return self._il_path
 
     @memoized_property
     def module(self):
+        if self in importlater._unresolved:
+            raise ImportError(
+                    "importlater.resolve_all() hasn't been called")
+
+        m = self._initial_import
         if self._il_addtl:
-            m = __import__(self._il_path, globals(), locals(),
-                                [self._il_addtl])
-            try:
-                return getattr(m, self._il_addtl)
-            except AttributeError:
-                raise ImportError(
-                        "Module %s has no attribute '%s'" %
-                        (self._il_path, self._il_addtl)
-                    )
+            m = getattr(m, self._il_addtl)
         else:
-            m = __import__(self._il_path)
             for token in self._il_path.split(".")[1:]:
                 m = getattr(m, token)
-            return m
+        return m
+
+    def _resolve(self):
+        importlater._unresolved.discard(self)
+        if self._il_addtl:
+            self._initial_import = __import__(
+                                self._il_path, globals(), locals(), 
+                                [self._il_addtl])
+        else:
+            self._initial_import = __import__(self._il_path)
 
     def __getattr__(self, key):
+        if key == 'module':
+            raise ImportError("Could not resolve module %s" 
+                                % self._full_path)
         try:
             attr = getattr(self.module, key)
         except AttributeError:
             raise AttributeError(
                         "Module %s has no attribute '%s'" %
-                        (self._il_path, key)
+                        (self._full_path, key)
                     )
         self.__dict__[key] = attr
         return attr