From d60c1689701caed35f906797563ab7ace9217d65 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 7 Apr 2010 12:30:02 -0400 Subject: [PATCH] - dict_ becomes explicit on _get_state_attr_by_column, _set_state_attr_by_column, others, to reduce on expensive state.dict calls. - internal getattr(), setattr(), getcommitted() methods on ColumnProperty, CompositeProperty, RelationshipProperty have been underscored, signature has changed. --- CHANGES | 4 ++ lib/sqlalchemy/orm/collections.py | 4 +- lib/sqlalchemy/orm/mapper.py | 70 +++++++++++++++++-------------- lib/sqlalchemy/orm/properties.py | 24 +++++------ lib/sqlalchemy/orm/strategies.py | 1 + lib/sqlalchemy/orm/sync.py | 10 ++--- 6 files changed, 62 insertions(+), 51 deletions(-) diff --git a/CHANGES b/CHANGES index eba1026c17..cfba6f4a42 100644 --- a/CHANGES +++ b/CHANGES @@ -49,6 +49,10 @@ CHANGES don't use executemany()). For a backend that doesn't support cursor.rowcount at all, a warning is emitted the same as with saves. [ticket:1761] + + - internal getattr(), setattr(), getcommitted() methods + on ColumnProperty, CompositeProperty, RelationshipProperty + have been underscored, signature has changed. - sql - Restored some bind-labeling logic from 0.5 which ensures diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py index 616f2510ab..65a24843d3 100644 --- a/lib/sqlalchemy/orm/collections.py +++ b/lib/sqlalchemy/orm/collections.py @@ -134,13 +134,13 @@ def column_mapped_collection(mapping_spec): def keyfunc(value): state = instance_state(value) m = _state_mapper(state) - return m._get_state_attr_by_column(state, cols[0]) + return m._get_state_attr_by_column(state, state.dict, cols[0]) else: mapping_spec = tuple(cols) def keyfunc(value): state = instance_state(value) m = _state_mapper(state) - return tuple(m._get_state_attr_by_column(state, c) + return tuple(m._get_state_attr_by_column(state, state.dict, c) for c in mapping_spec) return lambda: MappedCollection(keyfunc) diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 56cb1ef4d5..b57400c097 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1116,7 +1116,8 @@ class Mapper(object): return self._primary_key_from_state(state) def _primary_key_from_state(self, state): - return [self._get_state_attr_by_column(state, column) for column in self.primary_key] + dict_ = state.dict + return [self._get_state_attr_by_column(state, dict_, column) for column in self.primary_key] def _get_col_to_prop(self, column): try: @@ -1129,18 +1130,19 @@ class Mapper(object): raise orm_exc.UnmappedColumnError("No column %s is configured on mapper %s..." % (column, self)) # TODO: improve names? - def _get_state_attr_by_column(self, state, column): - return self._get_col_to_prop(column).getattr(state, column) + def _get_state_attr_by_column(self, state, dict_, column): + return self._get_col_to_prop(column)._getattr(state, dict_, column) - def _set_state_attr_by_column(self, state, column, value): - return self._get_col_to_prop(column).setattr(state, value, column) + def _set_state_attr_by_column(self, state, dict_, column, value): + return self._get_col_to_prop(column)._setattr(state, dict_, value, column) def _get_committed_attr_by_column(self, obj, column): state = attributes.instance_state(obj) - return self._get_committed_state_attr_by_column(state, column) + dict_ = attributes.instance_dict(obj) + return self._get_committed_state_attr_by_column(state, dict_, column) - def _get_committed_state_attr_by_column(self, state, column, passive=False): - return self._get_col_to_prop(column).getcommitted(state, column, passive=passive) + def _get_committed_state_attr_by_column(self, state, dict_, column, passive=False): + return self._get_col_to_prop(column)._getcommitted(state, dict_, column, passive=passive) 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. @@ -1171,12 +1173,12 @@ class Mapper(object): return if leftcol.table not in tables: - leftval = self._get_committed_state_attr_by_column(state, leftcol, passive=True) + leftval = self._get_committed_state_attr_by_column(state, state.dict, leftcol, passive=True) if leftval is attributes.PASSIVE_NO_RESULT: raise ColumnsNotAvailable() binary.left = sql.bindparam(None, leftval, type_=binary.right.type) elif rightcol.table not in tables: - rightval = self._get_committed_state_attr_by_column(state, rightcol, passive=True) + rightval = self._get_committed_state_attr_by_column(state, state.dict, rightcol, passive=True) if rightval is attributes.PASSIVE_NO_RESULT: raise ColumnsNotAvailable() binary.right = sql.bindparam(None, rightval, type_=binary.right.type) @@ -1326,6 +1328,7 @@ class Mapper(object): tups.append( (state, + state.dict, mapper, conn, has_identity, @@ -1339,7 +1342,7 @@ class Mapper(object): insert = [] update = [] - for state, mapper, connection, has_identity, \ + for state, state_dict, mapper, connection, has_identity, \ instance_key, row_switch in tups: if table not in mapper._pks_by_table: continue @@ -1366,11 +1369,11 @@ class Mapper(object): value is not None): params[col.key] = value elif col in pks: - value = mapper._get_state_attr_by_column(state, col) + value = mapper._get_state_attr_by_column(state, state_dict, col) if value is not None: params[col.key] = value else: - value = mapper._get_state_attr_by_column(state, col) + value = mapper._get_state_attr_by_column(state, state_dict, col) if ((col.default is None and col.server_default is None) or value is not None): @@ -1378,7 +1381,7 @@ class Mapper(object): value_params[col] = value else: params[col.key] = value - insert.append((state, params, mapper, + insert.append((state, state_dict, params, mapper, connection, value_params)) else: for col in mapper._cols_by_table[table]: @@ -1386,6 +1389,7 @@ class Mapper(object): params[col._label] = \ mapper._get_state_attr_by_column( row_switch or state, + row_switch and row_switch.dict or state_dict, col) params[col.key] = \ mapper.version_id_generator(params[col._label]) @@ -1407,7 +1411,7 @@ class Mapper(object): col not in post_update_cols: if col in pks: params[col._label] = \ - mapper._get_state_attr_by_column(state, col) + mapper._get_state_attr_by_column(state, state_dict, col) continue prop = mapper._columntoproperty[col] @@ -1442,9 +1446,9 @@ class Mapper(object): else: hasdata = True elif col in pks: - params[col._label] = mapper._get_state_attr_by_column(state, col) + params[col._label] = mapper._get_state_attr_by_column(state, state_dict, col) if hasdata: - update.append((state, params, mapper, + update.append((state, state_dict, params, mapper, connection, value_params)) if update: @@ -1467,10 +1471,10 @@ class Mapper(object): statement = table.update(clause) rows = 0 - for state, params, mapper, connection, value_params in update: + for state, state_dict, params, mapper, connection, value_params in update: c = connection.execute(statement.values(value_params), params) mapper._postfetch(uowtransaction, table, - state, c, c.last_updated_params(), value_params) + state, state_dict, c, c.last_updated_params(), value_params) rows += c.rowcount @@ -1489,22 +1493,22 @@ class Mapper(object): if insert: statement = table.insert() - for state, params, mapper, connection, value_params in insert: + for state, state_dict, params, mapper, connection, value_params in insert: c = connection.execute(statement.values(value_params), params) primary_key = c.inserted_primary_key if primary_key is not None: # set primary key attributes for i, col in enumerate(mapper._pks_by_table[table]): - if mapper._get_state_attr_by_column(state, col) is None and \ + if mapper._get_state_attr_by_column(state, state_dict, col) is None and \ len(primary_key) > i: - mapper._set_state_attr_by_column(state, col, primary_key[i]) + mapper._set_state_attr_by_column(state, state_dict, col, primary_key[i]) mapper._postfetch(uowtransaction, table, - state, c, c.last_inserted_params(), value_params) + state, state_dict, c, c.last_inserted_params(), value_params) if not postupdate: - for state, mapper, connection, has_identity, \ + for state, state_dict, mapper, connection, has_identity, \ instance_key, row_switch in tups: # expire readonly attributes @@ -1532,7 +1536,7 @@ class Mapper(object): mapper.extension.after_update(mapper, connection, state.obj()) def _postfetch(self, uowtransaction, table, - state, resultproxy, params, value_params): + state, dict_, resultproxy, params, value_params): """Expire attributes in need of newly persisted database state.""" postfetch_cols = resultproxy.postfetch_cols() @@ -1548,7 +1552,7 @@ class Mapper(object): for c in generated_cols: if c.key in params and c in self._columntoproperty: - self._set_state_attr_by_column(state, c, params[c.key]) + self._set_state_attr_by_column(state, dict_, c, params[c.key]) if postfetch_cols: _expire_state(state, state.dict, @@ -1607,6 +1611,7 @@ class Mapper(object): mapper.extension.before_delete(mapper, conn, state.obj()) tups.append((state, + state.dict, _state_mapper(state), _state_has_identity(state), conn)) @@ -1615,18 +1620,18 @@ class Mapper(object): for table in reversed(table_to_mapper.keys()): delete = util.defaultdict(list) - for state, mapper, has_identity, connection in tups: + for state, state_dict, mapper, has_identity, connection in tups: if not has_identity or table not in mapper._pks_by_table: continue params = {} delete[connection].append(params) for col in mapper._pks_by_table[table]: - params[col.key] = mapper._get_state_attr_by_column(state, col) + params[col.key] = mapper._get_state_attr_by_column(state, state_dict, col) if mapper.version_id_col is not None and \ table.c.contains_column(mapper.version_id_col): params[mapper.version_id_col.key] = \ - mapper._get_state_attr_by_column(state, mapper.version_id_col) + mapper._get_state_attr_by_column(state, state_dict, mapper.version_id_col) for connection, del_objects in delete.iteritems(): mapper = table_to_mapper[table] @@ -1677,7 +1682,7 @@ class Mapper(object): (c.rowcount, len(del_objects)) ) - for state, mapper, has_identity, connection in tups: + for state, state_dict, mapper, has_identity, connection in tups: if 'after_delete' in mapper.extension: mapper.extension.after_delete(mapper, connection, state.obj()) @@ -1809,12 +1814,13 @@ class Mapper(object): context.version_check and \ self._get_state_attr_by_column( state, + dict_, self.version_id_col) != row[version_id_col]: raise orm_exc.ConcurrentModificationError( "Instance '%s' version of %s does not match %s" % (state_str(state), - self._get_state_attr_by_column(state, self.version_id_col), + self._get_state_attr_by_column(state, dict_, self.version_id_col), row[version_id_col])) elif refresh_state: # out of band refresh_state detected (i.e. its not in the session.identity_map) @@ -2002,7 +2008,7 @@ def _event_on_resurrect(state, instance): # of the dict based on the mapping. instrumenting_mapper = state.manager.info[_INSTRUMENTOR] for col, val in zip(instrumenting_mapper.primary_key, state.key[1]): - instrumenting_mapper._set_state_attr_by_column(state, col, val) + instrumenting_mapper._set_state_attr_by_column(state, state.dict, col, val) def _sort_states(states): diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 41024101b8..6d5cc05247 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -99,14 +99,14 @@ class ColumnProperty(StrategizedProperty): def copy(self): return ColumnProperty(deferred=self.deferred, group=self.group, *self.columns) - def getattr(self, state, column): - return state.get_impl(self.key).get(state, state.dict) + def _getattr(self, state, dict_, column): + return state.get_impl(self.key).get(state, dict_) - def getcommitted(self, state, column, passive=False): - return state.get_impl(self.key).get_committed_value(state, state.dict, passive=passive) + def _getcommitted(self, state, dict_, column, passive=False): + return state.get_impl(self.key).get_committed_value(state, dict_, passive=passive) - def setattr(self, state, value, column): - state.get_impl(self.key).set(state, state.dict, value, None) + def _setattr(self, state, dict_, value, column): + state.get_impl(self.key).set(state, dict_, value, None) def merge(self, session, source_state, source_dict, dest_state, dest_dict, load, _recursive): if self.key in source_dict: @@ -164,18 +164,18 @@ class CompositeProperty(ColumnProperty): # which issues assertions that do not apply to CompositeColumnProperty super(ColumnProperty, self).do_init() - def getattr(self, state, column): - obj = state.get_impl(self.key).get(state, state.dict) + def _getattr(self, state, dict_, column): + obj = state.get_impl(self.key).get(state, dict_) return self.get_col_value(column, obj) - def getcommitted(self, state, column, passive=False): + def _getcommitted(self, state, dict_, column, passive=False): # TODO: no coverage here - obj = state.get_impl(self.key).get_committed_value(state, state.dict, passive=passive) + obj = state.get_impl(self.key).get_committed_value(state, dict_, passive=passive) return self.get_col_value(column, obj) - def setattr(self, state, value, column): + def _setattr(self, state, dict_, value, column): - obj = state.get_impl(self.key).get(state, state.dict) + obj = state.get_impl(self.key).get(state, dict_) if obj is None: obj = self.composite_class(*[None for c in self.columns]) state.get_impl(self.key).set(state, state.dict, obj, None) diff --git a/lib/sqlalchemy/orm/strategies.py b/lib/sqlalchemy/orm/strategies.py index 39657564a0..96aac7d3a6 100644 --- a/lib/sqlalchemy/orm/strategies.py +++ b/lib/sqlalchemy/orm/strategies.py @@ -592,6 +592,7 @@ class LoadLazyAttribute(object): val = instance_mapper.\ _get_committed_state_attr_by_column( state, + state.dict, strategy._equated_columns[primary_key], **kw) if val is attributes.PASSIVE_NO_RESULT: diff --git a/lib/sqlalchemy/orm/sync.py b/lib/sqlalchemy/orm/sync.py index 30daacbdf9..b9ddbb6e70 100644 --- a/lib/sqlalchemy/orm/sync.py +++ b/lib/sqlalchemy/orm/sync.py @@ -14,12 +14,12 @@ def populate(source, source_mapper, dest, dest_mapper, synchronize_pairs, uowcommit, passive_updates): for l, r in synchronize_pairs: try: - value = source_mapper._get_state_attr_by_column(source, l) + value = source_mapper._get_state_attr_by_column(source, source.dict, l) except exc.UnmappedColumnError: _raise_col_to_prop(False, source_mapper, l, dest_mapper, r) try: - dest_mapper._set_state_attr_by_column(dest, r, value) + dest_mapper._set_state_attr_by_column(dest, dest.dict, r, value) except exc.UnmappedColumnError: _raise_col_to_prop(True, source_mapper, l, dest_mapper, r) @@ -41,7 +41,7 @@ def clear(dest, dest_mapper, synchronize_pairs): (r, mapperutil.state_str(dest)) ) try: - dest_mapper._set_state_attr_by_column(dest, r, None) + dest_mapper._set_state_attr_by_column(dest, dest.dict, r, None) except exc.UnmappedColumnError: _raise_col_to_prop(True, None, l, dest_mapper, r) @@ -49,7 +49,7 @@ def update(source, source_mapper, dest, old_prefix, synchronize_pairs): for l, r in synchronize_pairs: try: oldvalue = source_mapper._get_committed_attr_by_column(source.obj(), l) - value = source_mapper._get_state_attr_by_column(source, l) + value = source_mapper._get_state_attr_by_column(source, source.dict, l) except exc.UnmappedColumnError: _raise_col_to_prop(False, source_mapper, l, None, r) dest[r.key] = value @@ -58,7 +58,7 @@ def update(source, source_mapper, dest, old_prefix, synchronize_pairs): def populate_dict(source, source_mapper, dict_, synchronize_pairs): for l, r in synchronize_pairs: try: - value = source_mapper._get_state_attr_by_column(source, l) + value = source_mapper._get_state_attr_by_column(source, source.dict, l) except exc.UnmappedColumnError: _raise_col_to_prop(False, source_mapper, l, None, r) -- 2.47.3