diff --git a/django/core/management/base.py b/django/core/management/base.py index af040288d0..9c8940e99f 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -10,7 +10,7 @@ from optparse import make_option, OptionParser import django from django.core.exceptions import ImproperlyConfigured -from django.core.management.color import color_style +from django.core.management.color import color_style, no_style from django.utils.encoding import force_str from django.utils.six import StringIO @@ -171,6 +171,8 @@ class BaseCommand(object): help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'), make_option('--traceback', action='store_true', help='Raise on exception'), + make_option('--no-color', action='store_true', dest='no_color', default=False, + help="Don't colorize the command output."), ) help = '' args = '' @@ -254,7 +256,11 @@ class BaseCommand(object): ``self.requires_model_validation``, except if force-skipped). """ self.stdout = OutputWrapper(options.get('stdout', sys.stdout)) - self.stderr = OutputWrapper(options.get('stderr', sys.stderr), self.style.ERROR) + if options.get('no_color'): + self.style = no_style() + self.stderr = OutputWrapper(options.get('stderr', sys.stderr)) + else: + self.stderr = OutputWrapper(options.get('stderr', sys.stderr), self.style.ERROR) if self.can_import_settings: from django.conf import settings diff --git a/django/core/management/color.py b/django/core/management/color.py index 8c7a87fe71..708823705b 100644 --- a/django/core/management/color.py +++ b/django/core/management/color.py @@ -30,7 +30,7 @@ def color_style(): class dummy: pass style = dummy() # The nocolor palette has all available roles. - # Use that pallete as the basis for populating + # Use that palette as the basis for populating # the palette as defined in the environment. for role in termcolors.PALETTES[termcolors.NOCOLOR_PALETTE]: format = color_settings.get(role,{}) diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 565c779525..6be9d0f441 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -1429,6 +1429,19 @@ that ``django-admin.py`` should print to the console. * ``2`` means verbose output. * ``3`` means *very* verbose output. +.. django-admin-option:: --no-color + +.. versionadded:: 1.7 + +Example usage:: + + django-admin.py sqlall --no-color + +By default, ``django-admin.py`` will format the output to be colorized. For +example, errors will be printed to the console in red and SQL statements will +be syntax highlighted. To prevent this and have a plain text output, pass the +``--no-color`` option when running your command. + Common options ============== diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 8d863c849a..217fdff287 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -92,6 +92,9 @@ Minor features * :func:`~django.core.mail.send_mail` now accepts an ``html_message`` parameter for sending a multipart ``text/plain`` and ``text/html`` email. +* The :djadminopt:`--no-color` option for ``django-admin.py`` allows you to + disable the colorization of management command output. + Backwards incompatible changes in 1.7 ===================================== diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index 6e1f916996..68615b787e 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -18,7 +18,7 @@ import unittest import django from django import conf, get_version from django.conf import settings -from django.core.management import BaseCommand, CommandError +from django.core.management import BaseCommand, CommandError, call_command from django.db import connection from django.test.runner import DiscoverRunner from django.utils.encoding import force_text @@ -922,14 +922,21 @@ class ManageAlternateSettings(AdminScriptTestCase): "alternate: manage.py can execute user commands if settings are provided as argument" args = ['noargs_command', '--settings=alternate_settings'] out, err = self.run_manage(args) - self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") self.assertNoOutput(err) def test_custom_command_with_environment(self): "alternate: manage.py can execute user commands if settings are provided in environment" args = ['noargs_command'] out, err = self.run_manage(args, 'alternate_settings') - self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertNoOutput(err) + + def test_custom_command_output_color(self): + "alternate: manage.py output syntax color can be deactivated with the `--no-color` option" + args = ['noargs_command', '--no-color', '--settings=alternate_settings'] + out, err = self.run_manage(args) + self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', True), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") self.assertNoOutput(err) @@ -1272,40 +1279,55 @@ class CommandTypes(AdminScriptTestCase): self.assertNoOutput(err) self.assertOutput(out, "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s).") + def test_no_color(self): + "--no-color prevent colorization of the output" + out = StringIO() + call_command("sqlall", "admin_scripts", no_color=True, stdout=out) + self.assertEqual(out.getvalue(), """BEGIN; +CREATE TABLE "admin_scripts_article" ( + "id" integer NOT NULL PRIMARY KEY, + "headline" varchar(100) NOT NULL, + "pub_date" datetime NOT NULL +) +; + +COMMIT; +""") + def test_base_command(self): "User BaseCommands can execute when a label is provided" args = ['base_command', 'testlabel'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_base_command_no_label(self): "User BaseCommands can execute when no labels are provided" args = ['base_command'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_base_command_multiple_label(self): "User BaseCommands can execute when no labels are provided" args = ['base_command', 'testlabel', 'anotherlabel'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('no_color', False), ('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_base_command_with_option(self): "User BaseCommands can execute with options when a label is provided" args = ['base_command', 'testlabel', '--option_a=x'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_base_command_with_options(self): "User BaseCommands can execute with multiple options when a label is provided" args = ['base_command', 'testlabel', '-a', 'x', '--option_b=y'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_base_run_from_argv(self): """ @@ -1351,7 +1373,7 @@ class CommandTypes(AdminScriptTestCase): args = ['noargs_command'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:NoArgsCommand options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_noargs_with_args(self): "NoArg Commands raise an error if an argument is provided" @@ -1366,7 +1388,7 @@ class CommandTypes(AdminScriptTestCase): self.assertNoOutput(err) self.assertOutput(out, "EXECUTE:AppCommand app=, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_app_command_no_apps(self): "User AppCommands raise an error when no app name is provided" @@ -1381,10 +1403,10 @@ class CommandTypes(AdminScriptTestCase): self.assertNoOutput(err) self.assertOutput(out, "EXECUTE:AppCommand app=, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") self.assertOutput(out, "EXECUTE:AppCommand app=, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "'>, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_app_command_invalid_appname(self): "User AppCommands can execute when a single app name is provided" @@ -1403,7 +1425,7 @@ class CommandTypes(AdminScriptTestCase): args = ['label_command', 'testlabel'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") def test_label_command_no_label(self): "User LabelCommands raise an error if no label is provided" @@ -1416,8 +1438,8 @@ class CommandTypes(AdminScriptTestCase): args = ['label_command', 'testlabel', 'anotherlabel'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") - self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") class ArgumentOrder(AdminScriptTestCase): """Tests for 2-stage argument parsing scheme. @@ -1441,35 +1463,35 @@ class ArgumentOrder(AdminScriptTestCase): args = ['base_command', 'testlabel', '--settings=alternate_settings', '--option_a=x'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") def test_setting_then_short_option(self): "Short options passed after settings are correctly handled" args = ['base_command', 'testlabel', '--settings=alternate_settings', '--option_a=x'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") def test_option_then_setting(self): "Options passed before settings are correctly handled" args = ['base_command', 'testlabel', '--option_a=x', '--settings=alternate_settings'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") def test_short_option_then_setting(self): "Short options passed before settings are correctly handled" args = ['base_command', 'testlabel', '-a', 'x', '--settings=alternate_settings'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") def test_option_then_setting_then_option(self): "Options are correctly handled when they are passed before and after a setting" args = ['base_command', 'testlabel', '--option_a=x', '--settings=alternate_settings', '--option_b=y'] out, err = self.run_manage(args) self.assertNoOutput(err) - self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") + self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('no_color', False), ('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None), ('verbosity', '1')]") class StartProject(LiveServerTestCase, AdminScriptTestCase):