summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/util/langhelpers.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2011-09-21 16:56:14 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2011-09-21 16:56:14 -0400
commit2aa80d40d2c9a00bb87a145bba1f01c327b6000b (patch)
treeb27660b881d695c3cba82b93d2020c566c4fa6c0 /lib/sqlalchemy/util/langhelpers.py
parent36e2b2d8750ca5bcf0345733973f5ed097d2949a (diff)
downloadsqlalchemy-2aa80d40d2c9a00bb87a145bba1f01c327b6000b.tar.gz
- 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.
Diffstat (limited to 'lib/sqlalchemy/util/langhelpers.py')
-rw-r--r--lib/sqlalchemy/util/langhelpers.py54
1 files changed, 42 insertions, 12 deletions
diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py
index 4dd9a5270..cf8b2acac 100644
--- a/lib/sqlalchemy/util/langhelpers.py
+++ b/lib/sqlalchemy/util/langhelpers.py
@@ -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