#33410: captureOnCommitCallbacks executes callbacks multiple times -------------------------------------+------------------------------------- Reporter: flaeppe | Owner: flaeppe Type: Bug | Status: assigned Component: Testing | Version: dev framework | Keywords: Severity: Normal | captureOnCommitCallbacks Triage Stage: | Has patch: 0 Unreviewed | Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 0 UI/UX: 0 | -------------------------------------+------------------------------------- When recursively adding multiple on commit callbacks, `captureOnCommitCallbacks` executes some callbacks multiple times. Below is a test case to reproduce the error.
{{{ #!div style="font-size: 80%" {{{#!python def test_execute_tree(self): """ A visualisation of the callback tree tested. Each node is expected to be visited only once. The child count of a node symbolises the amount of on commit callbacks. root └── branch_1 ├── branch_2 │ ├── leaf_1 │ └── leaf_2 └── leaf_3 """ ( branch_1_call_counter, branch_2_call_counter, leaf_1_call_counter, leaf_2_call_counter, leaf_3_call_counter, ) = [itertools.count(start=1) for _ in range(5)] def leaf_3(): next(leaf_3_call_counter) def leaf_2(): next(leaf_2_call_counter) def leaf_1(): next(leaf_1_call_counter) def branch_2(): next(branch_2_call_counter) transaction.on_commit(leaf_1) transaction.on_commit(leaf_2) def branch_1(): next(branch_1_call_counter) transaction.on_commit(branch_2) transaction.on_commit(leaf_3) with self.captureOnCommitCallbacks(execute=True) as callbacks: with transaction.atomic(): transaction.on_commit(branch_1) # Every counter shall only have been called once, starting at 1; next value then # has to be 2 self.assertEqual(next(branch_1_call_counter), 2) self.assertEqual(next(branch_2_call_counter), 2) self.assertEqual(next(leaf_1_call_counter), 2) self.assertEqual(next(leaf_2_call_counter), 2) self.assertEqual(next(leaf_3_call_counter), 2) # Make sure all calls can be seen and the execution order is correct self.assertEqual( [(id(callback), callback.__name__) for callback in callbacks], [ (id(branch_1), "branch_1"), (id(branch_2), "branch_2"), (id(leaf_3), "leaf_3"), (id(leaf_1), "leaf_1"), (id(leaf_2), "leaf_2"), ], ) }}} }}} -- Ticket URL: <https://code.djangoproject.com/ticket/33410> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/050.e65f414f3dfd085519bac60decae4c8d%40djangoproject.com.