diff --git a/django/core/management/commands/shell.py b/django/core/management/commands/shell.py index 1711cd95a1..9c500a0105 100644 --- a/django/core/management/commands/shell.py +++ b/django/core/management/commands/shell.py @@ -129,10 +129,13 @@ class Command(BaseCommand): return namespace amount = len(namespace) - msg = f"{amount} objects imported automatically" + objects_str = "objects" if amount != 1 else "object" + msg = f"{amount} {objects_str} imported automatically" if verbosity < 2: - self.stdout.write(f"{msg} (use -v 2 for details).", self.style.SUCCESS) + if amount: + msg += " (use -v 2 for details)" + self.stdout.write(f"{msg}.", self.style.SUCCESS) return namespace imports_by_module = defaultdict(list) @@ -163,9 +166,12 @@ class Command(BaseCommand): else: import_string = isort.code(import_string) - self.stdout.write( - f"{msg}, including:\n\n{import_string}", self.style.SUCCESS, ending="\n\n" - ) + if import_string: + msg = f"{msg}, including:\n\n{import_string}" + else: + msg = f"{msg}." + + self.stdout.write(msg, self.style.SUCCESS, ending="\n\n") return namespace diff --git a/tests/shell/tests.py b/tests/shell/tests.py index 3ca12edfed..c3cff25aad 100644 --- a/tests/shell/tests.py +++ b/tests/shell/tests.py @@ -7,7 +7,7 @@ from django.contrib.auth.models import Group, Permission, User from django.contrib.contenttypes.models import ContentType from django.core.management import CommandError, call_command from django.core.management.commands import shell -from django.db import models +from django.db import connection, models from django.test import SimpleTestCase from django.test.utils import ( captured_stdin, @@ -275,6 +275,44 @@ class ShellCommandAutoImportsTestCase(SimpleTestCase): " from shell.models import Phone, Marker", ) + def test_message_with_stdout_one_object(self): + class TestCommand(shell.Command): + def get_namespace(self): + return {"connection": connection} + + with captured_stdout() as stdout: + TestCommand().get_and_report_namespace(verbosity=2) + + cases = { + 0: "", + 1: "1 object imported automatically (use -v 2 for details).", + 2: ( + "1 object imported automatically, including:\n\n" + " from django.utils.connection import connection" + ), + } + for verbosity, expected in cases.items(): + with self.subTest(verbosity=verbosity): + with captured_stdout() as stdout: + TestCommand().get_and_report_namespace(verbosity=verbosity) + self.assertEqual(stdout.getvalue().strip(), expected) + + def test_message_with_stdout_zero_objects(self): + class TestCommand(shell.Command): + def get_namespace(self): + return {} + + cases = { + 0: "", + 1: "0 objects imported automatically.", + 2: "0 objects imported automatically.", + } + for verbosity, expected in cases.items(): + with self.subTest(verbosity=verbosity): + with captured_stdout() as stdout: + TestCommand().get_and_report_namespace(verbosity=verbosity) + self.assertEqual(stdout.getvalue().strip(), expected) + @override_settings(INSTALLED_APPS=["shell", "django.contrib.contenttypes"]) def test_message_with_stdout_listing_objects_with_isort(self): sorted_imports = (