summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/ext/declarative/clsregistry.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2013-12-03 13:46:41 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2013-12-03 13:46:41 -0500
commit36e1aa0afdf7e42f88426da4b2e9ee631d16728c (patch)
tree233b2308824abd1faab762e5df7fbcd815049cad /lib/sqlalchemy/ext/declarative/clsregistry.py
parent21feea9c1d278036cc37add813b72d0dbd4b1754 (diff)
downloadsqlalchemy-36e1aa0afdf7e42f88426da4b2e9ee631d16728c.tar.gz
- The :class:`.DeferredReflection` class has been enhanced to provide
automatic reflection support for the "secondary" table referred to by a :func:`.relationship`. "secondary", when specified either as a string table name, or as a :class:`.Table` object with only a name and :class:`.MetaData` object will also be included in the reflection process when :meth:`.DeferredReflection.prepare` is called. [ticket:2865] - clsregistry._resolver() now uses a stateful _class_resolver() class in order to handle the work of mapping strings to objects. This is to provide for simpler extensibility, namely a ._resolvers collection of ad-hoc name resolution functions; the DeferredReflection class adds its own resolver here in order to handle relationship(secondary) names which generate new Table objects.
Diffstat (limited to 'lib/sqlalchemy/ext/declarative/clsregistry.py')
-rw-r--r--lib/sqlalchemy/ext/declarative/clsregistry.py89
1 files changed, 52 insertions, 37 deletions
diff --git a/lib/sqlalchemy/ext/declarative/clsregistry.py b/lib/sqlalchemy/ext/declarative/clsregistry.py
index 8fef8f1bc..04567b32c 100644
--- a/lib/sqlalchemy/ext/declarative/clsregistry.py
+++ b/lib/sqlalchemy/ext/declarative/clsregistry.py
@@ -225,47 +225,62 @@ def _determine_container(key, value):
return _GetColumns(value)
-def _resolver(cls, prop):
- def resolve_arg(arg):
- import sqlalchemy
- from sqlalchemy.orm import foreign, remote
-
- fallback = sqlalchemy.__dict__.copy()
- fallback.update({'foreign': foreign, 'remote': remote})
-
- def access_cls(key):
- if key in cls._decl_class_registry:
- return _determine_container(key, cls._decl_class_registry[key])
- elif key in cls.metadata.tables:
- return cls.metadata.tables[key]
- elif key in cls.metadata._schemas:
- return _GetTable(key, cls.metadata)
- elif '_sa_module_registry' in cls._decl_class_registry and \
- key in cls._decl_class_registry['_sa_module_registry']:
- registry = cls._decl_class_registry['_sa_module_registry']
- return registry.resolve_attr(key)
+class _class_resolver(object):
+ def __init__(self, cls, prop, fallback, arg):
+ self.cls = cls
+ self.prop = prop
+ self.arg = self._declarative_arg = arg
+ self.fallback = fallback
+ self._dict = util.PopulateDict(self._access_cls)
+ self._resolvers = ()
+
+ def _access_cls(self, key):
+ cls = self.cls
+ if key in cls._decl_class_registry:
+ return _determine_container(key, cls._decl_class_registry[key])
+ elif key in cls.metadata.tables:
+ return cls.metadata.tables[key]
+ elif key in cls.metadata._schemas:
+ return _GetTable(key, cls.metadata)
+ elif '_sa_module_registry' in cls._decl_class_registry and \
+ key in cls._decl_class_registry['_sa_module_registry']:
+ registry = cls._decl_class_registry['_sa_module_registry']
+ return registry.resolve_attr(key)
+ elif self._resolvers:
+ for resolv in self._resolvers:
+ value = resolv(key)
+ if value is not None:
+ return value
+
+ return self.fallback[key]
+
+ def __call__(self):
+ try:
+ x = eval(self.arg, globals(), self._dict)
+
+ if isinstance(x, _GetColumns):
+ return x.cls
else:
- return fallback[key]
+ return x
+ except NameError as n:
+ raise exc.InvalidRequestError(
+ "When initializing mapper %s, expression %r failed to "
+ "locate a name (%r). If this is a class name, consider "
+ "adding this relationship() to the %r class after "
+ "both dependent classes have been defined." %
+ (self.prop.parent, self.arg, n.args[0], self.cls)
+ )
- d = util.PopulateDict(access_cls)
- def return_cls():
- try:
- x = eval(arg, globals(), d)
+def _resolver(cls, prop):
+ import sqlalchemy
+ from sqlalchemy.orm import foreign, remote
- if isinstance(x, _GetColumns):
- return x.cls
- else:
- return x
- except NameError as n:
- raise exc.InvalidRequestError(
- "When initializing mapper %s, expression %r failed to "
- "locate a name (%r). If this is a class name, consider "
- "adding this relationship() to the %r class after "
- "both dependent classes have been defined." %
- (prop.parent, arg, n.args[0], cls)
- )
- return return_cls
+ fallback = sqlalchemy.__dict__.copy()
+ fallback.update({'foreign': foreign, 'remote': remote})
+
+ def resolve_arg(arg):
+ return _class_resolver(cls, prop, fallback, arg)
return resolve_arg