From 987d418ae278ec5161f046ce20ff49ccc5533f40 Mon Sep 17 00:00:00 2001 From: kihuni Date: Thu, 6 Nov 2025 00:02:34 +0300 Subject: [PATCH] Fixed #36321 -- Added argparse suggest_on_error support for Python 3.14. When running Django management commands on Python 3.14, argparse's suggest_on_error feature is now enabled. This provides helpful suggestions for mistyped subparser names and argument choices. --- django/core/management/base.py | 5 +-- django/utils/version.py | 1 + docs/releases/6.1.txt | 7 ++-- tests/user_commands/tests.py | 70 ++++------------------------------ 4 files changed, 14 insertions(+), 69 deletions(-) diff --git a/django/core/management/base.py b/django/core/management/base.py index f98e72f54a..db7a01cc4c 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -15,7 +15,7 @@ from django.core import checks from django.core.exceptions import ImproperlyConfigured from django.core.management.color import color_style, no_style from django.db import DEFAULT_DB_ALIAS, connections -from django.utils.version import PY314 +from django.utils.version import PY314, PY315 ALL_CHECKS = "__all__" @@ -58,8 +58,7 @@ class CommandParser(ArgumentParser): ): self.missing_args_message = missing_args_message self.called_from_command_line = called_from_command_line - # Enable suggest_on_error for Python 3.14+ - if PY314 and called_from_command_line: + if PY314 and not PY315: kwargs.setdefault("suggest_on_error", True) super().__init__(**kwargs) diff --git a/django/utils/version.py b/django/utils/version.py index 2bb650ac89..9f694070c5 100644 --- a/django/utils/version.py +++ b/django/utils/version.py @@ -20,6 +20,7 @@ PY311 = sys.version_info >= (3, 11) PY312 = sys.version_info >= (3, 12) PY313 = sys.version_info >= (3, 13) PY314 = sys.version_info >= (3, 14) +PY315 = sys.version_info >= (3, 15) def get_version(version=None): diff --git a/docs/releases/6.1.txt b/docs/releases/6.1.txt index f83d4f51eb..b1e77931ef 100644 --- a/docs/releases/6.1.txt +++ b/docs/releases/6.1.txt @@ -225,10 +225,9 @@ Logging Management Commands ~~~~~~~~~~~~~~~~~~~ -* Management commands now use argparse's ``suggest_on_error`` feature when - running on Python 3.14+. This provides helpful suggestions when command-line - arguments are misspelled. For example, ``--verbositty`` will suggest - ``--verbosity``. +* Management commands now set :class:`~argparse.ArgumentParser`\'s + ``suggest_on_error`` argument to ``True`` by default on Python 3.14, enabling + suggestions for mistyped subcommand names and argument choices. Migrations ~~~~~~~~~~ diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py index d6554125c7..76521b7c0c 100644 --- a/tests/user_commands/tests.py +++ b/tests/user_commands/tests.py @@ -25,7 +25,7 @@ from django.db import connection from django.test import SimpleTestCase, override_settings from django.test.utils import captured_stderr, extend_sys_path from django.utils import translation -from django.utils.version import PY314 +from django.utils.version import PY314, PY315 from .management.commands import dance from .utils import AssertFormatterFailureCaughtContext @@ -456,79 +456,25 @@ class CommandTests(SimpleTestCase): self.assertIn("Working...", out.getvalue()) self.assertIs(mocked_flush.called, True) - -class SuggestOnErrorTests(SimpleTestCase): - """ - Tests for argparse suggest_on_error feature on Python 3.14+. - """ - - def test_parser_kwargs_suggest_on_error_on_python_314_plus(self): + @unittest.skipUnless(PY314 and not PY315, "Requires Python 3.14") + def test_suggest_on_error_defaults_true(self): """ - CommandParser sets suggest_on_error=True on Python 3.14+. + CommandParser sets suggest_on_error=True on Python 3.14. """ command = BaseCommand() - command._called_from_command_line = True # ADD THIS LINE parser = command.create_parser("prog_name", "subcommand") + self.assertTrue(parser.suggest_on_error) - if PY314: - self.assertTrue( - getattr(parser, "suggest_on_error", False), - "Parser should have suggest_on_error=True on Python 3.14+", - ) - - @unittest.skipUnless(PY314, "Requires Python 3.14+") - def test_custom_suggest_on_error_respected(self): + @unittest.skipUnless(PY314 and not PY315, "Requires Python 3.14") + def test_suggest_on_error_custom(self): """ Explicit suggest_on_error=False is respected. """ command = BaseCommand() - command._called_from_command_line = True # ADD THIS LINE parser = command.create_parser( "prog_name", "subcommand", suggest_on_error=False ) - self.assertFalse( - parser.suggest_on_error, - "Explicit suggest_on_error=False is respected", - ) - - @unittest.skipUnless(PY314, "Requires Python 3.14+") - def test_misspelled_option_suggests_correct_option(self): - """ - On Python 3.14+, misspelled options trigger suggestions when available. - """ - command = BaseCommand() - command._called_from_command_line = True - parser = command.create_parser("django-admin", "test") - - err = StringIO() - with mock.patch("sys.stderr", err): - with self.assertRaises(SystemExit) as cm: - parser.parse_args(["--verbositty", "2"]) - self.assertEqual(cm.exception.code, 2) - - error_output = err.getvalue().lower() - # Ensure it failed for the right reason - self.assertIn("unrecognized arguments", error_output) - - # On Python 3.14+, suggestions *may* appear depending on environment - if "did you mean" in error_output: - self.assertIn("--verbosity", error_output) - - def test_suggest_on_error_works_with_management_commands(self): - """ - Management commands have suggest_on_error on Python 3.14+. - """ - from .management.commands.dance import Command as DanceCommand - - dance_cmd = DanceCommand() - dance_cmd._called_from_command_line = True # ADD THIS LINE - parser = dance_cmd.create_parser("django-admin", "dance") - - if PY314: - self.assertTrue( - getattr(parser, "suggest_on_error", False), - "Management command parsers should have suggest_on_error=True", - ) + self.assertFalse(parser.suggest_on_error) class CommandRunTests(AdminScriptTestCase):