summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-08-02 19:25:43 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-08-02 19:25:43 -0400
commitf22ed46dd241a9261d2eec1bec12e0685582e101 (patch)
tree620f398ab272e6da89c5b8f04974abcc59c460ac
parentbeaefd799dcc8954cbbbc9c8df9ede55cbee1e1c (diff)
downloadsqlalchemy-3149.tar.gz
dev3149
-rw-r--r--lib/sqlalchemy/ext/declarative/api.py25
-rw-r--r--lib/sqlalchemy/ext/declarative/base.py11
2 files changed, 25 insertions, 11 deletions
diff --git a/lib/sqlalchemy/ext/declarative/api.py b/lib/sqlalchemy/ext/declarative/api.py
index 251b06fed..d4450da58 100644
--- a/lib/sqlalchemy/ext/declarative/api.py
+++ b/lib/sqlalchemy/ext/declarative/api.py
@@ -172,7 +172,7 @@ class declared_attr(interfaces._MappedAttribute, property):
def property(cls):
return _declared_property
- defer_defer_defer = False
+ should_resolve_late = False
class _memoized_declared_attr(declared_attr):
@@ -182,7 +182,7 @@ class _memoized_declared_attr(declared_attr):
self._cascading = cascading
def __get__(desc, self, cls):
- if desc.defer_defer_defer:
+ if desc.should_resolve_late:
return desc
elif cls in desc.reg:
return desc.reg[cls]
@@ -190,6 +190,18 @@ class _memoized_declared_attr(declared_attr):
desc.reg[cls] = obj = desc.fget(cls)
return obj
+ def resolve_early(self, cls, name):
+ if not self._cascading:
+ return getattr(cls, name)
+ else:
+ return self.__get__(self, cls)
+
+ def resolve_late(self, cls, name):
+ if self.should_resolve_late:
+ return self.fget(cls)
+ else:
+ raise NotImplementedError()
+
@classproperty
def cascading(cls):
return lambda decorated: cls(decorated, cascading=True)
@@ -200,8 +212,7 @@ class _declared_column(_memoized_declared_attr):
class _declared_property(_memoized_declared_attr):
- defer_defer_defer = True
-
+ should_resolve_late = True
def declarative_base(bind=None, metadata=None, mapper=None, cls=object,
@@ -433,6 +444,12 @@ class AbstractConcreteBase(ConcreteBase):
pjoin = cls._create_polymorphic_union(mappers)
cls.__mapper__ = m = mapper(cls, pjoin, polymorphic_on=pjoin.c.type)
+ for base in cls.__mro__:
+ for name, obj in vars(base).items():
+ if isinstance(obj, _memoized_declared_attr) \
+ and obj._cascading:
+ m.add_property(name, obj.resolve_late(cls, name))
+
for scls in cls.__subclasses__():
sm = _mapper_or_none(scls)
if sm.concrete and cls in scls.__bases__:
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py
index cee22637d..d17338bcb 100644
--- a/lib/sqlalchemy/ext/declarative/base.py
+++ b/lib/sqlalchemy/ext/declarative/base.py
@@ -132,11 +132,8 @@ def _as_declarative(cls, classname, dict_):
"column_property(), relationship(), etc.) must "
"be declared as @declared_attr callables "
"on declarative mixin classes.")
- elif isinstance(obj, _memoized_declared_attr): # and \
- if obj._cascading:
- dict_[name] = ret = obj.__get__(obj, cls)
- else:
- dict_[name] = ret = getattr(cls, name)
+ elif isinstance(obj, _memoized_declared_attr):
+ dict_[name] = ret = obj.resolve_early(cls, name)
if isinstance(ret, (Column, MapperProperty)) and \
ret.doc is None:
ret.doc = obj.__doc__
@@ -166,7 +163,7 @@ def _as_declarative(cls, classname, dict_):
value = dict_[k]
if isinstance(value, declarative_props):
- if value.defer_defer_defer:
+ if value.should_resolve_late:
add_later[k] = value
else:
value = getattr(cls, k)
@@ -426,7 +423,7 @@ class _MapperConfig(object):
**mapper_args
)
for k, v in self.add_later.items():
- setattr(self.cls, k, v.fget(self.cls))
+ setattr(self.cls, k, v.resolve_late(self.cls, k))
class _DeferredMapperConfig(_MapperConfig):