diff options
| author | kihuni <stephenkihuni55@gmail.com> | 2025-11-02 08:50:45 +0300 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-11-20 15:40:07 -0500 |
| commit | b1a65eac7c09250d36e12464fc8fff2a401246b6 (patch) | |
| tree | 50edf2b1eca970b169d75cfdf07d6c8049f1dbff | |
| parent | ee2e0e202874db31449d3c7c292504652fa87f69 (diff) | |
Fixed #36321 -- Defaulted suggest_on_error=True in management commands.
Python 3.15 defaults suggest_on_error=True, but the feature is available
from 3.14, so this change opts in earlier. This change can be reverted
when Python 3.15 is the minimum supported version.
| -rw-r--r-- | django/core/management/base.py | 3 | ||||
| -rw-r--r-- | django/utils/version.py | 1 | ||||
| -rw-r--r-- | docs/releases/6.1.txt | 4 | ||||
| -rw-r--r-- | tests/admin_scripts/tests.py | 16 | ||||
| -rw-r--r-- | tests/user_commands/tests.py | 16 |
5 files changed, 34 insertions, 6 deletions
diff --git a/django/core/management/base.py b/django/core/management/base.py index 92a3abb01e..db7a01cc4c 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -15,6 +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, PY315 ALL_CHECKS = "__all__" @@ -57,6 +58,8 @@ class CommandParser(ArgumentParser): ): self.missing_args_message = missing_args_message self.called_from_command_line = called_from_command_line + if PY314 and not PY315: + kwargs.setdefault("suggest_on_error", True) super().__init__(**kwargs) def parse_args(self, args=None, namespace=None): 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 f3338f8933..41b554bb5d 100644 --- a/docs/releases/6.1.txt +++ b/docs/releases/6.1.txt @@ -228,7 +228,9 @@ Logging Management Commands ~~~~~~~~~~~~~~~~~~~ -* ... +* 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/admin_scripts/tests.py b/tests/admin_scripts/tests.py index 0c27194568..19ef99ac49 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -38,7 +38,7 @@ from django.db.migrations.recorder import MigrationRecorder from django.test import LiveServerTestCase, SimpleTestCase, TestCase, override_settings from django.test.utils import captured_stderr, captured_stdout from django.urls import path -from django.utils.version import PY313, get_docs_version +from django.utils.version import PY313, PY314, get_docs_version from django.views.static import serve from . import urls @@ -2446,10 +2446,16 @@ class Discovery(SimpleTestCase): class CommandDBOptionChoiceTests(SimpleTestCase): def test_invalid_choice_db_option(self): - expected_error = ( - r"Error: argument --database: invalid choice: 'deflaut' " - r"\(choose from '?default'?, '?other'?\)" - ) + if PY314: + expected_error = ( + r"Error: argument --database: invalid choice: 'deflaut', " + r"maybe you meant 'default'\? \(choose from default, other\)" + ) + else: + expected_error = ( + r"Error: argument --database: invalid choice: 'deflaut' " + r"\(choose from '?default'?, '?other'?\)" + ) args = [ "changepassword", "createsuperuser", diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py index e282bd4bc9..afd376307a 100644 --- a/tests/user_commands/tests.py +++ b/tests/user_commands/tests.py @@ -1,5 +1,6 @@ import os import sys +import unittest from argparse import ArgumentDefaultsHelpFormatter from io import BytesIO, StringIO, TextIOWrapper from pathlib import Path @@ -24,6 +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, PY315 from .management.commands import dance from .utils import AssertFormatterFailureCaughtContext @@ -454,6 +456,20 @@ class CommandTests(SimpleTestCase): self.assertIn("Working...", out.getvalue()) self.assertIs(mocked_flush.called, True) + @unittest.skipUnless(PY314 and not PY315, "Only relevant for Python 3.14") + def test_suggest_on_error_defaults_true(self): + command = BaseCommand() + parser = command.create_parser("prog_name", "subcommand") + self.assertTrue(parser.suggest_on_error) + + @unittest.skipUnless(PY314 and not PY315, "Only relevant for Python 3.14") + def test_suggest_on_error_explicit_false(self): + command = BaseCommand() + parser = command.create_parser( + "prog_name", "subcommand", suggest_on_error=False + ) + self.assertFalse(parser.suggest_on_error) + class CommandRunTests(AdminScriptTestCase): """ |
