]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Call __del() before remove()
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 28 Dec 2018 03:10:45 +0000 (22:10 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 28 Dec 2018 13:37:03 +0000 (08:37 -0500)
The "remove" event for collections is now called before the item is removed
in the case of the ``collection.remove()`` method, as is consistent with the
behavior for most other forms of collection item removal (such as
``__delitem__``, replacement under ``__setitem__``).  The ``pop()`` methods
are now the only exception as the target item is not available until after
the pop operation proceeds.

This allows ``remove()`` to be consistent in its behavior with all
the other collection operations, allows the "before_delete" hook
to be local to "pop()" operations only, and removes some method overhead.

We are also looking here to gain some more predictability in terms
of the fix for #1103.

Change-Id: I4fdea911517d65cc300fae0e9c351a471e52e4ab

doc/build/changelog/unreleased_13/attr_remove.rst [new file with mode: 0644]
lib/sqlalchemy/orm/attributes.py
lib/sqlalchemy/orm/collections.py
test/orm/test_attributes.py
test/orm/test_hasparent.py
test/profiles.txt

diff --git a/doc/build/changelog/unreleased_13/attr_remove.rst b/doc/build/changelog/unreleased_13/attr_remove.rst
new file mode 100644 (file)
index 0000000..e7a28d6
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+   :tags: bug, orm
+
+   The "remove" event for collections is now called before the item is removed
+   in the case of the ``collection.remove()`` method, as is consistent with the
+   behavior for most other forms of collection item removal (such as
+   ``__delitem__``, replacement under ``__setitem__``).  For ``pop()`` methods,
+   the remove event still fires after the operation.
index ff730d745909c13cf646be3d53faad327faf2317..5ba8be439a0a769045272ef9e8b574839dae690b 100644 (file)
@@ -973,6 +973,14 @@ class CollectionAttributeImpl(AttributeImpl):
         return value
 
     def fire_pre_remove_event(self, state, dict_, initiator):
+        """A special event used for pop() operations.
+
+        The "remove" event needs to have the item to be removed passed to
+        it, which in the case of pop from a set, we don't have a way to access
+        the item before the operation.   the event is used for all pop()
+        operations (even though set.pop is the one where it is really needed).
+
+        """
         state._modified_event(dict_, self, NEVER_SET, True)
 
     def fire_remove_event(self, state, dict_, value, initiator):
index d6c23f5d291af14feeaa152d9b5aaab5ea1aac02..54c29bb5e8aa3feb5e6667262a4205f24b5d21db 100644 (file)
@@ -1009,7 +1009,11 @@ def _instrument_membership_mutator(method, before, argument, after):
 
 
 def __set(collection, item, _sa_initiator=None):
-    """Run set events, may eventually be inlined into decorators."""
+    """Run set events.
+
+    This event always occurs before the collection is actually mutated.
+
+    """
 
     if _sa_initiator is not False:
         executor = collection._sa_adapter
@@ -1019,15 +1023,22 @@ def __set(collection, item, _sa_initiator=None):
 
 
 def __del(collection, item, _sa_initiator=None):
-    """Run del events, may eventually be inlined into decorators."""
+    """Run del events.
+
+    This event occurs before the collection is actually mutated, *except*
+    in the case of a pop operation, in which case it occurs afterwards.
+    For pop operations, the __before_pop hook is called before the
+    operation occurs.
+
+    """
     if _sa_initiator is not False:
         executor = collection._sa_adapter
         if executor:
             executor.fire_remove_event(item, _sa_initiator)
 
 
-def __before_delete(collection, _sa_initiator=None):
-    """Special method to run 'commit existing value' methods"""
+def __before_pop(collection, _sa_initiator=None):
+    """An event which occurs on a before a pop() operation occurs."""
     executor = collection._sa_adapter
     if executor:
         executor.fire_pre_remove_event(_sa_initiator)
@@ -1049,10 +1060,9 @@ def _list_decorators():
 
     def remove(fn):
         def remove(self, value, _sa_initiator=None):
-            __before_delete(self, _sa_initiator)
+            __del(self, value, _sa_initiator)
             # testlib.pragma exempt:__eq__
             fn(self, value)
-            __del(self, value, _sa_initiator)
         _tidy(remove)
         return remove
 
@@ -1156,7 +1166,7 @@ def _list_decorators():
 
     def pop(fn):
         def pop(self, index=-1):
-            __before_delete(self)
+            __before_pop(self)
             item = fn(self, index)
             __del(self, item)
             return item
@@ -1218,18 +1228,21 @@ def _dict_decorators():
 
     def pop(fn):
         def pop(self, key, default=Unspecified):
-            if key in self:
-                __del(self, self[key])
+            __before_pop(self)
+            _to_del = key in self
             if default is Unspecified:
-                return fn(self, key)
+                item = fn(self, key)
             else:
-                return fn(self, key, default)
+                item = fn(self, key, default)
+            if _to_del:
+                __del(self, item)
+            return item
         _tidy(pop)
         return pop
 
     def popitem(fn):
         def popitem(self):
-            __before_delete(self)
+            __before_pop(self)
             item = fn(self)
             __del(self, item[1])
             return item
@@ -1324,8 +1337,10 @@ def _set_decorators():
 
     def pop(fn):
         def pop(self):
-            __before_delete(self)
+            __before_pop(self)
             item = fn(self)
+            # for set in particular, we have no way to access the item
+            # that will be popped before pop is called.
             __del(self, item)
             return item
         _tidy(pop)
index fa060af1d8cdd127689bd3c6bb1209bac5de83b5..f8d453255edae1faad003be21500aaada928ca6f 100644 (file)
@@ -564,23 +564,22 @@ class AttributesTest(fixtures.ORMTest):
                                       extension=[ReceiveEvents('scalar')])
 
         def create_hist():
-            def hist(key, shouldmatch, fn, *arg):
+            def hist(key, fn, *arg):
                 attributes.instance_state(f1)._commit_all(
                     attributes.instance_dict(f1))
                 fn(*arg)
-                histories.append((shouldmatch,
-                                  attributes.get_history(f1, key)))
+                histories.append(attributes.get_history(f1, key))
 
             f1 = Foo()
-            hist('bars', True, f1.bars.append, b3)
-            hist('bars', True, f1.bars.append, b4)
-            hist('bars', False, f1.bars.remove, b2)
-            hist('bar', True, setattr, f1, 'bar', b3)
-            hist('bar', True, setattr, f1, 'bar', None)
-            hist('bar', True, setattr, f1, 'bar', b4)
-            hist('scalar', True, setattr, f1, 'scalar', 5)
-            hist('scalar', True, setattr, f1, 'scalar', None)
-            hist('scalar', True, setattr, f1, 'scalar', 4)
+            hist('bars', f1.bars.append, b3)
+            hist('bars', f1.bars.append, b4)
+            hist('bars', f1.bars.remove, b2)
+            hist('bar', setattr, f1, 'bar', b3)
+            hist('bar', setattr, f1, 'bar', None)
+            hist('bar', setattr, f1, 'bar', b4)
+            hist('scalar', setattr, f1, 'scalar', 5)
+            hist('scalar', setattr, f1, 'scalar', None)
+            hist('scalar', setattr, f1, 'scalar', 4)
 
         histories = []
         commit = False
@@ -591,12 +590,9 @@ class AttributesTest(fixtures.ORMTest):
         create_hist()
         with_commit = histories
         for without, with_ in zip(without_commit, with_commit):
-            shouldmatch, woc = without
-            shouldmatch, wic = with_
-            if shouldmatch:
-                eq_(woc, wic)
-            else:
-                ne_(woc, wic)
+            woc = without
+            wic = with_
+            eq_(woc, wic)
 
     def test_extension_lazyload_assertion(self):
         class Foo(fixtures.BasicEntity):
index 2cb389f11cb08170bf803458189bba7bfe5f9af4..38dd722c20a25ad700732884e2331df9bb6b1e1b 100644 (file)
@@ -135,9 +135,9 @@ class ParentRemovalTest(fixtures.MappedTest):
             u1.addresses.remove, a1
         )
 
-        # unfortunately, u1.addresses was impacted
-        # here
-        assert u1.addresses == []
+        # u1.addresses wasn't actually impacted, because the event was
+        # caught before collection mutation
+        eq_(u1.addresses, [a1])
 
         # expire all and we can continue
         s.expire_all()
index ef13151bcf0651501b3c99cd4aa4fadd2f5a75ed..4aeadffe3169888be1a319f9b70dc891f7853fba 100644 (file)
@@ -1,15 +1,15 @@
 # /home/classic/dev/sqlalchemy/test/profiles.txt
 # This file is written out on a per-environment basis.
-# For each test in aaa_profiling, the corresponding function and 
+# For each test in aaa_profiling, the corresponding function and
 # environment is located within this file.  If it doesn't exist,
 # the test is skipped.
-# If a callcount does exist, it is compared to what we received. 
+# If a callcount does exist, it is compared to what we received.
 # assertions are raised if the counts do not match.
-# 
-# To add a new callcount test, apply the function_call_count 
-# decorator and re-run the tests using the --write-profiles 
+#
+# To add a new callcount test, apply the function_call_count
+# decorator and re-run the tests using the --write-profiles
 # option - this file will be rewritten including the new count.
-# 
+#
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert
 
@@ -261,65 +261,65 @@ test.aaa_profiling.test_orm.AnnotatedOverheadTest.test_no_entity_wo_annotations
 
 # TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set
 
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mssql_pyodbc_dbapiunicode_cextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mssql_pyodbc_dbapiunicode_nocextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mysql_mysqldb_dbapiunicode_cextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mysql_mysqldb_dbapiunicode_nocextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_oracle_cx_oracle_dbapiunicode_cextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_postgresql_psycopg2_dbapiunicode_cextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_sqlite_pysqlite_dbapiunicode_cextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 4256
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mssql_pyodbc_dbapiunicode_cextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mssql_pyodbc_dbapiunicode_nocextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mysql_mysqldb_dbapiunicode_cextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mysql_mysqldb_dbapiunicode_nocextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_oracle_cx_oracle_dbapiunicode_cextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_postgresql_psycopg2_dbapiunicode_cextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_sqlite_pysqlite_dbapiunicode_cextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 4257
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_mysql_mysqldb_dbapiunicode_cextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_mysql_mysqldb_dbapiunicode_nocextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_oracle_cx_oracle_dbapiunicode_cextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_postgresql_psycopg2_dbapiunicode_cextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_sqlite_pysqlite_dbapiunicode_cextensions 4377
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 4377
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mssql_pyodbc_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mssql_pyodbc_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mysql_mysqldb_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_mysql_mysqldb_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_oracle_cx_oracle_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_postgresql_psycopg2_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_sqlite_pysqlite_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mssql_pyodbc_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mssql_pyodbc_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mysql_mysqldb_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_mysql_mysqldb_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_oracle_cx_oracle_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_postgresql_psycopg2_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_sqlite_pysqlite_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_mysql_mysqldb_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_mysql_mysqldb_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_oracle_cx_oracle_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_postgresql_psycopg2_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_sqlite_pysqlite_dbapiunicode_cextensions 3927
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_attribute_set 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 3927
 
 # TEST: test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove
 
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mssql_pyodbc_dbapiunicode_cextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mssql_pyodbc_dbapiunicode_nocextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mysql_mysqldb_dbapiunicode_cextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mysql_mysqldb_dbapiunicode_nocextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_oracle_cx_oracle_dbapiunicode_cextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_postgresql_psycopg2_dbapiunicode_cextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_sqlite_pysqlite_dbapiunicode_cextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 6420
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mssql_pyodbc_dbapiunicode_cextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mssql_pyodbc_dbapiunicode_nocextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mysql_mysqldb_dbapiunicode_cextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mysql_mysqldb_dbapiunicode_nocextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_oracle_cx_oracle_dbapiunicode_cextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_postgresql_psycopg2_dbapiunicode_cextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_sqlite_pysqlite_dbapiunicode_cextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 6422
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_mysql_mysqldb_dbapiunicode_cextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_mysql_mysqldb_dbapiunicode_nocextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_oracle_cx_oracle_dbapiunicode_cextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_postgresql_psycopg2_dbapiunicode_cextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_sqlite_pysqlite_dbapiunicode_cextensions 6622
-test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 6622
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mssql_pyodbc_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mssql_pyodbc_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mysql_mysqldb_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_mysql_mysqldb_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_oracle_cx_oracle_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_postgresql_psycopg2_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_sqlite_pysqlite_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mssql_pyodbc_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mssql_pyodbc_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mysql_mysqldb_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_mysql_mysqldb_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_oracle_cx_oracle_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_oracle_cx_oracle_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_postgresql_psycopg2_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_postgresql_psycopg2_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_sqlite_pysqlite_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.6_sqlite_pysqlite_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_mysql_mysqldb_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_mysql_mysqldb_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_oracle_cx_oracle_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_postgresql_psycopg2_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_sqlite_pysqlite_dbapiunicode_cextensions 5822
+test.aaa_profiling.test_orm.AttributeOverheadTest.test_collection_append_remove 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 5822
 
 # TEST: test.aaa_profiling.test_orm.BranchedOptionTest.test_generate_cache_key_bound_branching