summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy')
-rw-r--r--lib/sqlalchemy/ext/declarative/api.py21
-rw-r--r--lib/sqlalchemy/ext/declarative/base.py10
-rw-r--r--lib/sqlalchemy/orm/mapper.py14
3 files changed, 22 insertions, 23 deletions
diff --git a/lib/sqlalchemy/ext/declarative/api.py b/lib/sqlalchemy/ext/declarative/api.py
index 713ea0aba..3d46bd4cb 100644
--- a/lib/sqlalchemy/ext/declarative/api.py
+++ b/lib/sqlalchemy/ext/declarative/api.py
@@ -163,21 +163,16 @@ class declared_attr(interfaces._MappedAttribute, property):
self._cascading = cascading
def __get__(desc, self, cls):
- # use the ClassManager for memoization of values. This is better than
- # adding yet another attribute onto the class, or using weakrefs
- # here which are slow and take up memory. It also allows us to
- # warn for non-mapped use of declared_attr.
-
- manager = attributes.manager_of_class(cls)
- if manager is None:
- util.warn(
- "Unmanaged access of declarative attribute %s from "
- "non-mapped class %s" %
- (desc.fget.__name__, cls.__name__))
+ reg = cls.__dict__.get('_sa_declared_attr_reg', None)
+ if reg is None:
+ manager = attributes.manager_of_class(cls)
+ if manager is None:
+ util.warn(
+ "Unmanaged access of declarative attribute %s from "
+ "non-mapped class %s" %
+ (desc.fget.__name__, cls.__name__))
return desc.fget(cls)
- reg = manager.info.get('declared_attr_reg', None)
-
if reg is None:
return desc.fget(cls)
elif desc in reg:
diff --git a/lib/sqlalchemy/ext/declarative/base.py b/lib/sqlalchemy/ext/declarative/base.py
index 062936ea7..57eb54f63 100644
--- a/lib/sqlalchemy/ext/declarative/base.py
+++ b/lib/sqlalchemy/ext/declarative/base.py
@@ -115,10 +115,10 @@ class _MapperConfig(object):
self.column_copies = {}
self._setup_declared_events()
- # register up front, so that @declared_attr can memoize
- # function evaluations in .info
- manager = instrumentation.register_class(self.cls)
- manager.info['declared_attr_reg'] = {}
+ # temporary registry. While early 1.0 versions
+ # set up the ClassManager here, by API contract
+ # we can't do that until there's a mapper.
+ self.cls._sa_declared_attr_reg = {}
self._scan_attributes()
@@ -529,7 +529,7 @@ class _MapperConfig(object):
self.local_table,
**self.mapper_args
)
- del mp_.class_manager.info['declared_attr_reg']
+ del self.cls._sa_declared_attr_reg
return mp_
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index 924130874..468846d40 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -1096,8 +1096,6 @@ class Mapper(InspectionAttr):
"""
- # when using declarative as of 1.0, the register_class has
- # already happened from within declarative.
manager = attributes.manager_of_class(self.class_)
if self.non_primary:
@@ -1120,14 +1118,20 @@ class Mapper(InspectionAttr):
"create a non primary Mapper. clear_mappers() will "
"remove *all* current mappers from all classes." %
self.class_)
-
- if manager is None:
- manager = instrumentation.register_class(self.class_)
+ # else:
+ # a ClassManager may already exist as
+ # ClassManager.instrument_attribute() creates
+ # new managers for each subclass if they don't yet exist.
_mapper_registry[self] = True
+ # note: this *must be called before instrumentation.register_class*
+ # to maintain the documented behavior of instrument_class
self.dispatch.instrument_class(self, self.class_)
+ if manager is None:
+ manager = instrumentation.register_class(self.class_)
+
self.class_manager = manager
manager.mapper = self