From 7c6b03752f41381b3d5e8086c959ceac6b321737 Mon Sep 17 00:00:00 2001 From: Krishnaprasad MG Date: Mon, 30 Jun 2025 14:42:05 +0200 Subject: [PATCH] Fix logger error message with partial callbacks --- django/db/backends/base/base.py | 12 ++++++------ django/test/testcases.py | 7 +++---- tests/test_utils/tests.py | 30 ++++++++++++++++++++++++++++++ tests/transaction_hooks/tests.py | 27 +++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 10 deletions(-) diff --git a/django/db/backends/base/base.py b/django/db/backends/base/base.py index 54328c8450..481f173c43 100644 --- a/django/db/backends/base/base.py +++ b/django/db/backends/base/base.py @@ -741,10 +741,10 @@ class BaseDatabaseWrapper: try: func() except Exception as e: - logger.error( - f"Error calling {func.__qualname__} in on_commit() (%s).", + name = getattr(func, "__qualname__", func) + logger.exception( + f"Error calling {name} in on_commit() (%s).", e, - exc_info=True, ) else: func() @@ -759,11 +759,11 @@ class BaseDatabaseWrapper: try: func() except Exception as e: - logger.error( - f"Error calling {func.__qualname__} in on_commit() during " + name = getattr(func, "__qualname__", func) + logger.exception( + f"Error calling {name} in on_commit() during " f"transaction (%s).", e, - exc_info=True, ) else: func() diff --git a/django/test/testcases.py b/django/test/testcases.py index d4d61c8fba..0479c4cbee 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -1485,11 +1485,10 @@ class TestCase(TransactionTestCase): try: callback() except Exception as e: - logger.error( - f"Error calling {callback.__qualname__} in " - f"on_commit() (%s).", + name = getattr(callback, "__qualname__", callback) + logger.exception( + f"Error calling {name} in on_commit() (%s).", e, - exc_info=True, ) else: callback() diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py index 494a0ea8d3..4a47f3e48b 100644 --- a/tests/test_utils/tests.py +++ b/tests/test_utils/tests.py @@ -4,6 +4,7 @@ import threading import traceback import unittest import warnings +from functools import partial from io import StringIO from unittest import mock @@ -2089,6 +2090,35 @@ class CaptureOnCommitCallbacksTests(TestCase): self.assertIsInstance(raised_exception, MyException) self.assertEqual(str(raised_exception), "robust callback") + def test_execute_robust_with_callback_as_partial(self): + class MyException(Exception): + pass + + def hook(): + self.callback_called = True + raise MyException("robust callback") + + hook_partial = partial(hook) + + with self.assertLogs("django.test", "ERROR") as cm: + with self.captureOnCommitCallbacks(execute=True) as callbacks: + transaction.on_commit(hook_partial, robust=True) + + self.assertEqual(len(callbacks), 1) + self.assertIs(self.callback_called, True) + + log_record = cm.records[0] + self.assertRegex( + log_record.getMessage(), + r"Error calling functools\.partial\(\.hook" + r" at .+>\) in on_commit\(\) \(robust callback\)\.", + ) + self.assertIsNotNone(log_record.exc_info) + raised_exception = log_record.exc_info[1] + self.assertIsInstance(raised_exception, MyException) + self.assertEqual(str(raised_exception), "robust callback") + class DisallowedDatabaseQueriesTests(SimpleTestCase): def test_disallowed_database_connections(self): diff --git a/tests/transaction_hooks/tests.py b/tests/transaction_hooks/tests.py index 938e92575f..d10fdc4d07 100644 --- a/tests/transaction_hooks/tests.py +++ b/tests/transaction_hooks/tests.py @@ -1,3 +1,5 @@ +from functools import partial + from django.db import connection, transaction from django.test import TransactionTestCase, skipUnlessDBFeature @@ -84,6 +86,31 @@ class TestConnectionOnCommit(TransactionTestCase): self.assertIsInstance(raised_exception, ForcedError) self.assertEqual(str(raised_exception), "robust callback") + def test_robust_transaction_with_callback_as_partial(self): + def robust_callback(): + raise ForcedError("robust callback") + + robust_callback_partial = partial(robust_callback) + + with self.assertLogs("django.db.backends", "ERROR") as cm: + with transaction.atomic(): + transaction.on_commit(robust_callback_partial, robust=True) + self.do(1) + + self.assertDone([1]) + log_record = cm.records[0] + self.assertRegex( + log_record.getMessage(), + r"Error calling functools\.partial\(\." + r"robust_callback at .+>\) in on_commit\(\)" + r" during transaction \(robust callback\)\.", + ) + self.assertIsNotNone(log_record.exc_info) + raised_exception = log_record.exc_info[1] + self.assertIsInstance(raised_exception, ForcedError) + self.assertEqual(str(raised_exception), "robust callback") + def test_delays_execution_until_after_transaction_commit(self): with transaction.atomic(): self.do(1)