can you perhaps place a "pdb.set_trace()" inside of session._flush()? using the debugger you can see the source of every flush() call. Generally, it occurs each time a query is about to emit SQL.
On Mon, May 7, 2018 at 9:37 PM, Colton Allen <cmanalle...@gmail.com> wrote: > What exactly causes the session to flush? I'm trying to track down a nasty > bug in my versioning system. > > Sorry for the long code dump. I retooled > examples/versioned_history/history_meta.py so it should look familiar. The > function that's breaking is "column_has_changed". I've added some logs as > well. > > # WHEN IT WORKS! > > CRITICAL:root:BEFORE MAPPING NEW VALUES > CRITICAL:root:BEFORE SAVE > CRITICAL:root:BEFORE REVISE > CRITICAL:root:CHECK COLUMN CHANGES > CRITICAL:root:AFTER REVISE > CRITICAL:root:flush! > CRITICAL:root:AFTER SAVE > CRITICAL:root:flush! > > # WHEN IT DOESN'T WORK! > > CRITICAL:root:BEFORE MAPPING NEW VALUES > CRITICAL:root:BEFORE SAVE > CRITICAL:root:BEFORE REVISE > CRITICAL:root:flush! > CRITICAL:root:CHECK COLUMN CHANGES > CRITICAL:root:AFTER REVISE > CRITICAL:root:AFTER SAVE > CRITICAL:root:flush! > > controller.py > > for k, v in dict.items(): > setattr(model, k, v) > model.revise() > db.session.add(model) > db.session.commit() > > model.py > > class RevisionMixin: > """Version control manager.""" > > def revise(self): > db.session.add(self) > write_revision(self) > > version.py > > def write_revision(target): > target_mapper = orm.object_mapper(target) > revision_class = target.__versioned__['model'] > revision_mapper = revision_class.__mapper__ > > object_changed = False > state = {} > > for column in iter_mapper_columns(target_mapper, revision_mapper): > state[column.key] = getattr(target, column.key) > column_changed = column_has_changed(target, column.key) > object_changed = object_changed or column_changed > > for relationship, changed in iter_relationships(target, target_mapper): > if hasattr(revision_class, relationship.key): > state[relationship.key] = getattr(target, relationship.key) > object_changed = object_changed or changed > > if not isinstance(target.id, str) or object_changed: > _write_revision(target, state) > > > def _write_revision(target, state): > version = target.version or 0 > version = version + 1 > state['version'] = version > state['updated_at'] = db.now() > state['primary'] = target > > revision = target.__versioned__['model'](**state) > db.session.add(revision) > > target.version = version > target.updated_at = state['updated_at'] > > > def iter_mapper_columns(primary, revision): > mappers = zip(primary.iterate_to_root(), revision.iterate_to_root()) > for om, hm in mappers: > if hm.single: > continue > for column in iter_shared_columns(om, hm): > yield column > > > def iter_shared_columns(mapper, comparison_mapper): > for comparison_mapper_column in comparison_mapper.local_table.c: > if 'version_meta' in comparison_mapper_column.info: > continue > > try: > mapper_column = > mapper.local_table.c[comparison_mapper_column.key] > yield mapper.get_property_by_column(mapper_column) > except UnmappedColumnError: > continue > > > def iter_relationships(target, mapper): > for prop in mapper.iterate_properties: > if isinstance(prop, RelationshipProperty): > passive = attributes.PASSIVE_NO_INITIALIZE > changed = attributes.get_history( > target, prop.key, passive=passive).has_changes() > yield prop, changed > > > def column_has_changed(target, column_name): > # Sometimes the instance state history can't be properly > # calculated? No flushing during versioning. Unsure why its not > # working. > added, _, deleted = attributes.get_history(target, column_name) > return bool(added or deleted) > > > def relationship_has_changed(prop): > for p in prop.local_columns: > if p.foreign_keys: > return True > return False > > > -- > SQLAlchemy - > The Python SQL Toolkit and Object Relational Mapper > > http://www.sqlalchemy.org/ > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > --- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at https://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.