From: Mike Bayer Date: Thu, 2 Jun 2011 00:25:33 +0000 (-0400) Subject: take out a little cruft. Spend two hours trying to make things simpler, X-Git-Tag: rel_0_7_1~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6400a1cc967fe2bc26e4ebb5a3c132bdd6adefef;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git take out a little cruft. Spend two hours trying to make things simpler, maybe we dont need state.callables (nope we do), maybe we can move populate_state out (nope we lose speed that way), things are the way they are... --- diff --git a/lib/sqlalchemy/orm/instrumentation.py b/lib/sqlalchemy/orm/instrumentation.py index 7fe3335e0c..f14b752533 100644 --- a/lib/sqlalchemy/orm/instrumentation.py +++ b/lib/sqlalchemy/orm/instrumentation.py @@ -110,6 +110,7 @@ class ClassManager(dict): @util.memoized_property def mapper(self): + # raises unless self.mapper has been assigned raise exc.UnmappedClassError(self.class_) def _attr_has_impl(self, key): @@ -120,27 +121,6 @@ class ClassManager(dict): return key in self and self[key].impl is not None - def _configure_create_arguments(self, - _source=None, - deferred_scalar_loader=None): - """Accept extra **kw arguments passed to create_manager_for_cls. - - The current contract of ClassManager and other managers is that they - take a single "cls" argument in their constructor (as per - test/orm/instrumentation.py InstrumentationCollisionTest). This - is to provide consistency with the current API of "class manager" - callables and such which may return various ClassManager and - ClassManager-like instances. So create_manager_for_cls sends - in ClassManager-specific arguments via this method once the - non-proxied ClassManager is available. - - """ - if _source: - deferred_scalar_loader = _source.deferred_scalar_loader - - if deferred_scalar_loader: - self.deferred_scalar_loader = deferred_scalar_loader - def _subclass_manager(self, cls): """Create a new ClassManager for a subclass of this ClassManager's class. @@ -526,8 +506,6 @@ class InstrumentationRegistry(object): self._extended = True _install_lookup_strategy(self) - manager._configure_create_arguments(**kw) - manager.factory = factory self._manager_finders[class_] = manager.manager_getter() self._state_finders[class_] = manager.state_getter() diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index a426e28ac2..08c377930b 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -612,14 +612,13 @@ class Mapper(object): self.dispatch.instrument_class(self, self.class_) if manager is None: - manager = instrumentation.register_class(self.class_, - deferred_scalar_loader = _load_scalar_attributes - ) + manager = instrumentation.register_class(self.class_) self.class_manager = manager manager.mapper = self - + manager.deferred_scalar_loader = self._load_scalar_attributes + # The remaining members can be added by any mapper, # e_name None or not. if manager.info.get(_INSTRUMENTOR, False): @@ -1519,6 +1518,65 @@ class Mapper(object): return state.manager[prop.key].impl.\ get_committed_value(state, dict_, passive=passive) + def _load_scalar_attributes(self, state, attribute_names): + """initiate a column-based attribute refresh operation.""" + + #assert mapper is _state_mapper(state) + session = sessionlib._state_session(state) + if not session: + raise orm_exc.DetachedInstanceError( + "Instance %s is not bound to a Session; " + "attribute refresh operation cannot proceed" % + (state_str(state))) + + has_key = bool(state.key) + + result = False + + if self.inherits and not self.concrete: + statement = self._optimized_get_statement(state, attribute_names) + if statement is not None: + result = session.query(self).from_statement(statement).\ + _load_on_ident(None, + only_load_props=attribute_names, + refresh_state=state) + + if result is False: + if has_key: + identity_key = state.key + else: + # this codepath is rare - only valid when inside a flush, and the + # object is becoming persistent but hasn't yet been assigned an identity_key. + # check here to ensure we have the attrs we need. + pk_attrs = [self._columntoproperty[col].key + for col in self.primary_key] + if state.expired_attributes.intersection(pk_attrs): + raise sa_exc.InvalidRequestError("Instance %s cannot be refreshed - it's not " + " persistent and does not " + "contain a full primary key." % state_str(state)) + identity_key = self._identity_key_from_state(state) + + if (_none_set.issubset(identity_key) and \ + not self.allow_partial_pks) or \ + _none_set.issuperset(identity_key): + util.warn("Instance %s to be refreshed doesn't " + "contain a full primary key - can't be refreshed " + "(and shouldn't be expired, either)." + % state_str(state)) + return + + result = session.query(self)._load_on_ident( + identity_key, + refresh_state=state, + only_load_props=attribute_names) + + # if instance is pending, a refresh operation + # may not complete (even if PK attributes are assigned) + if has_key and result is None: + raise orm_exc.ObjectDeletedError( + "Instance '%s' has been deleted." % + state_str(state)) + def _optimized_get_statement(self, state, attribute_names): """assemble a WHERE clause which retrieves a given state by primary key, using a minimized set of tables. @@ -2424,7 +2482,10 @@ class Mapper(object): # occur within a flush() identitykey = self._identity_key_from_state(refresh_state) else: - identitykey = identity_class, tuple([row[column] for column in pk_cols]) + identitykey = ( + identity_class, + tuple([row[column] for column in pk_cols]) + ) instance = session_identity_map.get(identitykey) if instance is not None: @@ -2475,9 +2536,8 @@ class Mapper(object): if create_instance: for fn in create_instance: - instance = fn(self, - context, - row, self.class_) + instance = fn(self, context, + row, self.class_) if instance is not EXT_CONTINUE: manager = attributes.manager_of_class( instance.__class__) @@ -2494,12 +2554,13 @@ class Mapper(object): state = attributes.instance_state(instance) state.key = identitykey - # manually adding instance to session. for a complete add, - # session._finalize_loaded() must be called. + # attach instance to session. state.session_id = context.session.hash_key session_identity_map.add(state) if currentload or populate_existing: + # state is being fully loaded, so populate. + # add to the "context.progress" collection. if isnew: state.runid = context.runid context.progress[state] = dict_ @@ -2522,9 +2583,9 @@ class Mapper(object): state.manager.dispatch.refresh(state, context, only_load_props) elif state in context.partials or state.unloaded: - # populate attributes on non-loading instances which have - # been expired - # TODO: apply eager loads to un-lazy loaded collections ? + # state is having a partial set of its attributes + # refreshed. Populate those attributes, + # and add to the "context.partials" collection. if state in context.partials: isnew = False @@ -2532,7 +2593,6 @@ class Mapper(object): else: isnew = True attrs = state.unloaded - # allow query.instances to commit the subset of attrs context.partials[state] = (dict_, attrs) if populate_instance: @@ -2747,64 +2807,6 @@ def _event_on_resurrect(state): def _sort_states(states): return sorted(states, key=operator.attrgetter('sort_key')) -def _load_scalar_attributes(state, attribute_names): - """initiate a column-based attribute refresh operation.""" - - mapper = _state_mapper(state) - session = sessionlib._state_session(state) - if not session: - raise orm_exc.DetachedInstanceError( - "Instance %s is not bound to a Session; " - "attribute refresh operation cannot proceed" % - (state_str(state))) - - has_key = bool(state.key) - - result = False - - if mapper.inherits and not mapper.concrete: - statement = mapper._optimized_get_statement(state, attribute_names) - if statement is not None: - result = session.query(mapper).from_statement(statement).\ - _load_on_ident(None, - only_load_props=attribute_names, - refresh_state=state) - - if result is False: - if has_key: - identity_key = state.key - else: - # this codepath is rare - only valid when inside a flush, and the - # object is becoming persistent but hasn't yet been assigned an identity_key. - # check here to ensure we have the attrs we need. - pk_attrs = [mapper._columntoproperty[col].key - for col in mapper.primary_key] - if state.expired_attributes.intersection(pk_attrs): - raise sa_exc.InvalidRequestError("Instance %s cannot be refreshed - it's not " - " persistent and does not " - "contain a full primary key." % state_str(state)) - identity_key = mapper._identity_key_from_state(state) - - if (_none_set.issubset(identity_key) and \ - not mapper.allow_partial_pks) or \ - _none_set.issuperset(identity_key): - util.warn("Instance %s to be refreshed doesn't " - "contain a full primary key - can't be refreshed " - "(and shouldn't be expired, either)." - % state_str(state)) - return - - result = session.query(mapper)._load_on_ident( - identity_key, - refresh_state=state, - only_load_props=attribute_names) - - # if instance is pending, a refresh operation - # may not complete (even if PK attributes are assigned) - if has_key and result is None: - raise orm_exc.ObjectDeletedError( - "Instance '%s' has been deleted." % - state_str(state)) class _ColumnMapping(util.py25_dict): diff --git a/lib/sqlalchemy/util/compat.py b/lib/sqlalchemy/util/compat.py index 0fb0045008..69d648498a 100644 --- a/lib/sqlalchemy/util/compat.py +++ b/lib/sqlalchemy/util/compat.py @@ -81,7 +81,6 @@ except ImportError: return func(*(args + fargs), **newkeywords) return newfunc - if py3k: # they're bringing it back in 3.2. brilliant ! def callable(fn):