Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-mm committed Jan 4, 2025
2 parents 9130980 + 51df0df commit 973c82c
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 4 deletions.
5 changes: 4 additions & 1 deletion django/core/management/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def add_arguments(self, actions):
super().add_arguments(self._reordered_actions(actions))


class OutputWrapper(TextIOBase):
class OutputWrapper:
"""
Wrapper around stdout/stderr
"""
Expand Down Expand Up @@ -181,6 +181,9 @@ def write(self, msg="", style_func=None, ending=None):
self._out.write(style_func(msg))


TextIOBase.register(OutputWrapper)


class BaseCommand:
"""
The base class from which all management commands ultimately
Expand Down
7 changes: 5 additions & 2 deletions django/test/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from django.test.utils import teardown_databases as _teardown_databases
from django.test.utils import teardown_test_environment
from django.utils.datastructures import OrderedSet
from django.utils.version import PY312
from django.utils.version import PY312, PY313

try:
import ipdb as pdb
Expand Down Expand Up @@ -126,7 +126,10 @@ def debug(self, error):
self.buffer = False
exc_type, exc_value, traceback = error
print("\nOpening PDB: %r" % exc_value)
pdb.post_mortem(traceback)
if PY313:
pdb.post_mortem(exc_value)
else:
pdb.post_mortem(traceback)


class DummyList:
Expand Down
26 changes: 25 additions & 1 deletion tests/user_commands/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import sys
from argparse import ArgumentDefaultsHelpFormatter
from io import StringIO
from io import BytesIO, StringIO, TextIOWrapper
from pathlib import Path
from unittest import mock

Expand All @@ -11,6 +11,7 @@
from django.core import management
from django.core.checks import Tags
from django.core.management import BaseCommand, CommandError, find_commands
from django.core.management.base import OutputWrapper
from django.core.management.utils import (
find_command,
get_random_secret_key,
Expand All @@ -28,6 +29,29 @@
from .utils import AssertFormatterFailureCaughtContext


class OutputWrapperTests(SimpleTestCase):
def test_unhandled_exceptions(self):
cases = [
StringIO("Hello world"),
TextIOWrapper(BytesIO(b"Hello world")),
]
for out in cases:
with self.subTest(out=out):
wrapper = OutputWrapper(out)
out.close()

unraisable_exceptions = []

def unraisablehook(unraisable):
unraisable_exceptions.append(unraisable)
sys.__unraisablehook__(unraisable)

with mock.patch.object(sys, "unraisablehook", unraisablehook):
del wrapper

self.assertEqual(unraisable_exceptions, [])


# A minimal set of apps to avoid system checks running on all apps.
@override_settings(
INSTALLED_APPS=[
Expand Down

0 comments on commit 973c82c

Please sign in to comment.