summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkihuni <stephenkihuni55@gmail.com>2025-11-02 08:50:45 +0300
committerJacob Walls <jacobtylerwalls@gmail.com>2025-11-20 15:40:07 -0500
commitb1a65eac7c09250d36e12464fc8fff2a401246b6 (patch)
tree50edf2b1eca970b169d75cfdf07d6c8049f1dbff
parentee2e0e202874db31449d3c7c292504652fa87f69 (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.py3
-rw-r--r--django/utils/version.py1
-rw-r--r--docs/releases/6.1.txt4
-rw-r--r--tests/admin_scripts/tests.py16
-rw-r--r--tests/user_commands/tests.py16
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):
"""