Ticket #15107: 15107-2.diff

File 15107-2.diff, 71.0 KB (added by Claude Paroz, 13 years ago)

Commands output through logging

  • django/contrib/auth/management/commands/changepassword.py

    diff --git a/django/contrib/auth/management/commands/changepassword.py b/django/contrib/auth/management/commands/changepassword.py
    index 56448f1..f267da6 100644
    a b class Command(BaseCommand):  
    2727        except User.DoesNotExist:
    2828            raise CommandError("user '%s' does not exist" % username)
    2929
    30         print "Changing password for user '%s'" % u.username
     30        self.info("Changing password for user '%s'" % u.username)
    3131
    3232        MAX_TRIES = 3
    3333        count = 0
    class Command(BaseCommand):  
    3636            p1 = self._get_pass()
    3737            p2 = self._get_pass("Password (again): ")
    3838            if p1 != p2:
    39                 print "Passwords do not match. Please try again."
     39                self.info("Passwords do not match. Please try again.")
    4040                count = count + 1
    4141
    4242        if count == MAX_TRIES:
  • django/contrib/auth/management/commands/createsuperuser.py

    diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py
    index b3a3479..1770930 100644
    a b class Command(BaseCommand):  
    7373                    if default_username and username == '':
    7474                        username = default_username
    7575                    if not RE_VALID_USERNAME.match(username):
    76                         sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
     76                        self.error("Error: That username is invalid. Use only letters, digits and underscores.")
    7777                        username = None
    7878                        continue
    7979                    try:
    class Command(BaseCommand):  
    8181                    except User.DoesNotExist:
    8282                        break
    8383                    else:
    84                         sys.stderr.write("Error: That username is already taken.\n")
     84                        self.error("Error: That username is already taken.")
    8585                        username = None
    8686
    8787                # Get an email
    class Command(BaseCommand):  
    9191                    try:
    9292                        is_valid_email(email)
    9393                    except exceptions.ValidationError:
    94                         sys.stderr.write("Error: That e-mail address is invalid.\n")
     94                        self.error("Error: That e-mail address is invalid.")
    9595                        email = None
    9696                    else:
    9797                        break
    class Command(BaseCommand):  
    102102                        password = getpass.getpass()
    103103                        password2 = getpass.getpass('Password (again): ')
    104104                        if password != password2:
    105                             sys.stderr.write("Error: Your passwords didn't match.\n")
     105                            self.error("Error: Your passwords didn't match.")
    106106                            password = None
    107107                            continue
    108108                    if password.strip() == '':
    109                         sys.stderr.write("Error: Blank passwords aren't allowed.\n")
     109                        self.error("Error: Blank passwords aren't allowed.")
    110110                        password = None
    111111                        continue
    112112                    break
    113113            except KeyboardInterrupt:
    114                 sys.stderr.write("\nOperation cancelled.\n")
     114                self.error("\nOperation cancelled.")
    115115                sys.exit(1)
    116116
    117117        User.objects.create_superuser(username, email, password)
    118118        if verbosity >= 1:
    119           self.stdout.write("Superuser created successfully.\n")
    120 
     119          self.info("Superuser created successfully.")
  • django/contrib/staticfiles/management/commands/collectstatic.py

    diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py
    index 7004ff0..281078b 100644
    a b Type 'yes' to continue, or 'no' to cancel: """  
    165165
    166166        if self.verbosity >= 1:
    167167            template = ("\n%(modified_count)s %(identifier)s %(action)s"
    168                         "%(destination)s%(unmodified)s%(post_processed)s.\n")
     168                        "%(destination)s%(unmodified)s%(post_processed)s.")
    169169            summary = template % {
    170170                'modified_count': modified_count,
    171171                'identifier': 'static file' + (modified_count != 1 and 's' or ''),
    Type 'yes' to continue, or 'no' to cancel: """  
    178178                                   ', %s post-processed'
    179179                                   % post_processed_count or ''),
    180180            }
    181             self.stdout.write(smart_str(summary))
     181            self.info(smart_str(summary))
    182182
    183183    def log(self, msg, level=2):
    184184        """
    185185        Small log helper
    186186        """
    187         msg = smart_str(msg)
    188         if not msg.endswith("\n"):
    189             msg += "\n"
    190187        if self.verbosity >= level:
    191             self.stdout.write(msg)
     188            self.info(smart_str(msg))
    192189
    193190    def clear_dir(self, path):
    194191        """
  • django/contrib/staticfiles/management/commands/findstatic.py

    diff --git a/django/contrib/staticfiles/management/commands/findstatic.py b/django/contrib/staticfiles/management/commands/findstatic.py
    index bcf0c2f..77d23d7 100644
    a b class Command(LabelCommand):  
    2323                result = [result]
    2424            output = u'\n  '.join(
    2525                (smart_unicode(os.path.realpath(path)) for path in result))
    26             self.stdout.write(
    27                 smart_str(u"Found '%s' here:\n  %s\n" % (path, output)))
     26            self.info(
     27                smart_str(u"Found '%s' here:\n  %s" % (path, output)))
    2828        else:
    2929            if verbosity >= 1:
    30                 self.stderr.write(
    31                     smart_str("No matching file found for '%s'.\n" % path))
     30                self.error("No matching file found for '%s'." % path)
  • django/core/management/__init__.py

    diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
    index 8e83304..9dd72da 100644
    a b import warnings  
    88from django.core.management.base import BaseCommand, CommandError, handle_default_options
    99from django.core.management.color import color_style
    1010from django.utils.importlib import import_module
     11from django.utils.log import getLogger
    1112
    1213# For backwards compatibility: get_version() used to be in this module.
    1314from django import get_version
    from django import get_version  
    1516# A cache of loaded commands, so that call_command
    1617# doesn't have to reload every time it's called.
    1718_commands = None
     19logger = getLogger('django.commands')
    1820
    1921def find_commands(management_dir):
    2022    """
    def call_command(name, *args, **options):  
    139141    # when the script runs from the command line, but since call_command can
    140142    # be called programatically, we need to simulate the loading and handling
    141143    # of defaults (see #10080 for details).
    142     defaults = {}
     144    defaults = {'raise_on_error': True}
    143145    for opt in klass.option_list:
    144146        if opt.default is NO_DEFAULT:
    145147            defaults[opt.dest] = None
    def call_command(name, *args, **options):  
    149151
    150152    return klass.execute(*args, **defaults)
    151153
     154
    152155class LaxOptionParser(OptionParser):
    153156    """
    154157    An option parser that doesn't raise any errors on unknown options.
    class ManagementUtility(object):  
    251254        try:
    252255            app_name = get_commands()[subcommand]
    253256        except KeyError:
    254             sys.stderr.write("Unknown command: %r\nType '%s help' for usage.\n" % \
     257            logger.error("Unknown command: %r\nType '%s help' for usage." % \
    255258                (subcommand, self.prog_name))
    256259            sys.exit(1)
    257260        if isinstance(app_name, BaseCommand):
    class ManagementUtility(object):  
    363366        if subcommand == 'help':
    364367            if len(args) <= 2:
    365368                parser.print_lax_help()
    366                 sys.stdout.write(self.main_help_text() + '\n')
     369                logger.info(self.main_help_text())
    367370            elif args[2] == '--commands':
    368                 sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
     371                logger.info(self.main_help_text(commands_only=True))
    369372            else:
    370373                self.fetch_command(args[2]).print_help(self.prog_name, args[2])
    371374        elif subcommand == 'version':
    372             sys.stdout.write(parser.get_version() + '\n')
     375            logger.info(parser.get_version())
    373376        # Special-cases: We want 'django-admin.py --version' and
    374377        # 'django-admin.py --help' to work, for backwards compatibility.
    375378        elif self.argv[1:] == ['--version']:
    class ManagementUtility(object):  
    377380            pass
    378381        elif self.argv[1:] in (['--help'], ['-h']):
    379382            parser.print_lax_help()
    380             sys.stdout.write(self.main_help_text() + '\n')
     383            logger.info(self.main_help_text())
    381384        else:
    382385            self.fetch_command(subcommand).run_from_argv(self.argv)
    383386
  • django/core/management/base.py

    diff --git a/django/core/management/base.py b/django/core/management/base.py
    index db855e1..d9bb9ce 100644
    a b import sys  
    99
    1010from optparse import make_option, OptionParser
    1111import traceback
     12import warnings
    1213
    1314import django
    1415from django.core.exceptions import ImproperlyConfigured
    1516from django.core.management.color import color_style
    1617from django.utils.encoding import smart_str
     18from django.utils.log import getLogger, setup_commands_logger
    1719
    1820
    1921class CommandError(Exception):
    def handle_default_options(options):  
    4547        sys.path.insert(0, options.pythonpath)
    4648
    4749
     50class OutputRedirector(object):
     51    """
     52    Utility redirector class used until self.stderr and self.sdtout are
     53    removed from BaseCommand class (1.6)
     54    """
     55    def __init__(self, proxy_func):
     56        self.proxy_func = proxy_func
     57
     58    def write(self, msg):
     59        warnings.warn(
     60            "The 'self.stdout' and 'self.stderr' objects are deprecated, "
     61            "update your management command to use the new info() and error() "
     62            "methods; please see the Django 1.4 release notes "
     63            "(https://docs.djangoproject.com/en/dev/releases/1.4/).",
     64            PendingDeprecationWarning)
     65        self.proxy_func(msg)
     66
     67
    4868class BaseCommand(object):
    4969    """
    5070    The base class from which all management commands ultimately
    class BaseCommand(object):  
    142162
    143163    def __init__(self):
    144164        self.style = color_style()
     165        self._logger = getLogger('django.commands')
    145166
    146167    def get_version(self):
    147168        """
    class BaseCommand(object):  
    221242                if show_traceback:
    222243                    traceback.print_exc()
    223244                else:
    224                     sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
     245                    self.error('Error: %s' % e)
    225246                sys.exit(1)
    226247
     248        if 'stdout' in options or 'stderr' in options:
     249            # Set up a temporary logger
     250            self._logger = setup_commands_logger(
     251                'django.commands_temp',
     252                options.get('stdout', sys.stdout),
     253                options.get('stderr', sys.stderr)
     254            )
     255        # Temporarily redirect, until deprecation path is over (1.6)
     256        self.stdout = OutputRedirector(self.info)
     257        self.stderr = OutputRedirector(self.error)
    227258        try:
    228             self.stdout = options.get('stdout', sys.stdout)
    229             self.stderr = options.get('stderr', sys.stderr)
    230259            if self.requires_model_validation:
    231260                self.validate()
    232261            output = self.handle(*args, **options)
    class BaseCommand(object):  
    237266                    from django.db import connections, DEFAULT_DB_ALIAS
    238267                    connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
    239268                    if connection.ops.start_transaction_sql():
    240                         self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()) + '\n')
    241                 self.stdout.write(output)
    242                 if self.output_transaction:
    243                     self.stdout.write('\n' + self.style.SQL_KEYWORD("COMMIT;") + '\n')
     269                        output = "%s\n%s" % (
     270                            self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()),
     271                            output
     272                        )
     273                    output = "%s\n%s" % (output, self.style.SQL_KEYWORD("COMMIT;"))
     274                self.info(output)
    244275        except CommandError, e:
    245             if show_traceback:
    246                 traceback.print_exc()
     276            if options.get('raise_on_error', False):
     277                raise
    247278            else:
    248                 self.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
    249             sys.exit(1)
     279                if show_traceback:
     280                    traceback.print_exc()
     281                else:
     282                    self.error('Error: %s' % e)
     283                sys.exit(1)
     284        finally:
     285            if self._logger.name == 'django.commands_temp':
     286                for h in self._logger.handlers:
     287                    h.close()
    250288        if saved_lang is not None:
    251289            translation.activate(saved_lang)
    252290
    class BaseCommand(object):  
    269307            error_text = s.read()
    270308            raise CommandError("One or more models did not validate:\n%s" % error_text)
    271309        if display_num_errors:
    272             self.stdout.write("%s error%s found\n" % (num_errors, num_errors != 1 and 's' or ''))
     310            self.info("%s error%s found" % (num_errors, num_errors != 1 and 's' or ''))
     311
     312    def info(self, msg):
     313        """ Output a message on the logger (stdout by default) """
     314        self._logger.info(msg)
     315
     316    def error(self, msg):
     317        """ Output an error on the logger (stderr by default) """
     318        self._logger.error(smart_str(self.style.ERROR(msg)))
    273319
    274320    def handle(self, *args, **options):
    275321        """
  • django/core/management/commands/compilemessages.py

    diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py
    index b5eaeb1..accc3f8 100644
    a b def has_bom(fn):  
    1111            sample.startswith(codecs.BOM_UTF16_LE) or \
    1212            sample.startswith(codecs.BOM_UTF16_BE)
    1313
    14 def compile_messages(stderr, locale=None):
     14def compile_messages(logger, locale=None):
    1515    basedirs = [os.path.join('conf', 'locale'), 'locale']
    1616    if os.environ.get('DJANGO_SETTINGS_MODULE'):
    1717        from django.conf import settings
    def compile_messages(stderr, locale=None):  
    2929        for dirpath, dirnames, filenames in os.walk(basedir):
    3030            for f in filenames:
    3131                if f.endswith('.po'):
    32                     stderr.write('processing file %s in %s\n' % (f, dirpath))
     32                    logger.info('processing file %s in %s' % (f, dirpath))
    3333                    fn = os.path.join(dirpath, f)
    3434                    if has_bom(fn):
    3535                        raise CommandError("The %s file has a BOM (Byte Order Mark). Django only supports .po files encoded in UTF-8 and without any BOM." % fn)
    class Command(BaseCommand):  
    6060
    6161    def handle(self, **options):
    6262        locale = options.get('locale')
    63         compile_messages(self.stderr, locale=locale)
     63        compile_messages(self._logger, locale=locale)
  • django/core/management/commands/createcachetable.py

    diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py
    index 08fa5f2..2a94b51 100644
    a b  
    11from optparse import make_option
    22
    33from django.core.cache.backends.db import BaseDatabaseCache
    4 from django.core.management.base import LabelCommand
     4from django.core.management.base import LabelCommand, CommandError
    55from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
    66from django.db.utils import DatabaseError
    77
    class Command(LabelCommand):  
    5555        try:
    5656            curs.execute("\n".join(full_statement))
    5757        except DatabaseError, e:
    58             self.stderr.write(
    59                 self.style.ERROR("Cache table '%s' could not be created.\nThe error was: %s.\n" %
    60                     (tablename, e)))
    6158            transaction.rollback_unless_managed(using=db)
     59            raise CommandError("Cache table '%s' could not be created.\nThe error was: %s." % (
     60                tablename, e))
    6261        else:
    6362            for statement in index_output:
    6463                curs.execute(statement)
  • django/core/management/commands/flush.py

    diff --git a/django/core/management/commands/flush.py b/django/core/management/commands/flush.py
    index 6d0f14e..c6655a1 100644
    a b class Command(NoArgsCommand):  
    2828        verbosity = int(options.get('verbosity'))
    2929        interactive = options.get('interactive')
    3030
    31         self.style = no_style()
    32 
    3331        # Import the 'management' module within each installed app, to register
    3432        # dispatcher events.
    3533        for app_name in settings.INSTALLED_APPS:
    class Command(NoArgsCommand):  
    3836            except ImportError:
    3937                pass
    4038
    41         sql_list = sql_flush(self.style, connection, only_django=True)
     39        sql_list = sql_flush(no_style(), connection, only_django=True)
    4240
    4341        if interactive:
    4442            confirm = raw_input("""You have requested a flush of the database.
    The full error: %s""" % (connection.settings_dict['NAME'], e))  
    8280            call_command('loaddata', 'initial_data', **kwargs)
    8381
    8482        else:
    85             print "Flush cancelled."
     83            return "Flush cancelled."
  • django/core/management/commands/inspectdb.py

    diff --git a/django/core/management/commands/inspectdb.py b/django/core/management/commands/inspectdb.py
    index 8da0d7e..9daf8c4 100644
    a b class Command(NoArgsCommand):  
    2020    def handle_noargs(self, **options):
    2121        try:
    2222            for line in self.handle_inspection(options):
    23                 self.stdout.write("%s\n" % line)
     23                self.info(line)
    2424        except NotImplementedError:
    2525            raise CommandError("Database inspection isn't supported for the currently selected database backend.")
    2626
  • django/core/management/commands/loaddata.py

    diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
    index 0c234fb..7824c8e 100644
    a b import traceback  
    1111
    1212from django.conf import settings
    1313from django.core import serializers
    14 from django.core.management.base import BaseCommand
     14from django.core.management.base import BaseCommand, CommandError
    1515from django.core.management.color import no_style
    1616from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
    1717      IntegrityError, DatabaseError)
    try:  
    2424except ImportError:
    2525    has_bz2 = False
    2626
     27
    2728class Command(BaseCommand):
    2829    help = 'Installs the named fixture(s) in the database.'
    2930    args = "fixture [fixture ...]"
    class Command(BaseCommand):  
    3839        using = options.get('database')
    3940
    4041        connection = connections[using]
    41         self.style = no_style()
    4242
    4343        if not len(fixture_labels):
    44             self.stderr.write(
    45                 self.style.ERROR("No database fixture specified. Please provide the path of at least one fixture in the command line.\n")
    46             )
    47             return
     44            raise CommandError("No database fixture specified. "
     45                "Please provide the path of at least one fixture in the command line.")
    4846
    4947        verbosity = int(options.get('verbosity'))
    5048        show_traceback = options.get('traceback')
    class Command(BaseCommand):  
    128126
    129127                    if formats:
    130128                        if verbosity >= 2:
    131                             self.stdout.write("Loading '%s' fixtures...\n" % fixture_name)
     129                            self.info("Loading '%s' fixtures..." % fixture_name)
    132130                    else:
    133                         self.stderr.write(
    134                             self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format.\n" %
    135                                 (fixture_name, format)))
    136                         if commit:
    137                             transaction.rollback(using=using)
    138                             transaction.leave_transaction_management(using=using)
    139                         return
     131                        raise CommandError("Problem installing fixture '%s': %s is not a known serialization format." %
     132                            (fixture_name, format))
    140133
    141134                    if os.path.isabs(fixture_name):
    142135                        fixture_dirs = [fixture_name]
    class Command(BaseCommand):  
    145138
    146139                    for fixture_dir in fixture_dirs:
    147140                        if verbosity >= 2:
    148                             self.stdout.write("Checking %s for fixtures...\n" % humanize(fixture_dir))
     141                            self.info("Checking %s for fixtures..." % humanize(fixture_dir))
    149142
    150143                        label_found = False
    151144                        for combo in product([using, None], formats, compression_formats):
    class Command(BaseCommand):  
    158151                            )
    159152
    160153                            if verbosity >= 3:
    161                                 self.stdout.write("Trying %s for %s fixture '%s'...\n" % \
    162                                     (humanize(fixture_dir), file_name, fixture_name))
     154                                self.info("Trying %s for %s fixture '%s'..." % (
     155                                    humanize(fixture_dir), file_name, fixture_name))
    163156                            full_path = os.path.join(fixture_dir, file_name)
    164157                            open_method = compression_types[compression_format]
    165158                            try:
    166159                                fixture = open_method(full_path, 'r')
    167160                            except IOError:
    168161                                if verbosity >= 2:
    169                                     self.stdout.write("No %s fixture '%s' in %s.\n" % \
    170                                         (format, fixture_name, humanize(fixture_dir)))
     162                                    self.info("No %s fixture '%s' in %s." % (
     163                                        format, fixture_name, humanize(fixture_dir)))
    171164                            else:
    172165                                try:
    173166                                    if label_found:
    174                                         self.stderr.write(self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting.\n" %
    175                                             (fixture_name, humanize(fixture_dir))))
    176                                         if commit:
    177                                             transaction.rollback(using=using)
    178                                             transaction.leave_transaction_management(using=using)
    179                                         return
     167                                        raise CommandError("Multiple fixtures named '%s' in %s. Aborting." %
     168                                            (fixture_name, humanize(fixture_dir)))
    180169
    181170                                    fixture_count += 1
    182171                                    objects_in_fixture = 0
    183172                                    loaded_objects_in_fixture = 0
    184173                                    if verbosity >= 2:
    185                                         self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
    186                                             (format, fixture_name, humanize(fixture_dir)))
     174                                        self.info("Installing %s fixture '%s' from %s." % (
     175                                            format, fixture_name, humanize(fixture_dir)))
    187176
    188177                                    objects = serializers.deserialize(format, fixture, using=using)
    189178
    class Command(BaseCommand):  
    212201                                # If the fixture we loaded contains 0 objects, assume that an
    213202                                # error was encountered during fixture loading.
    214203                                if objects_in_fixture == 0:
    215                                     self.stderr.write(
    216                                         self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)\n" %
    217                                             (fixture_name)))
    218                                     if commit:
    219                                         transaction.rollback(using=using)
    220                                         transaction.leave_transaction_management(using=using)
    221                                     return
     204                                    raise CommandError("No fixture data found for '%s'. (File format may be invalid.)" %
     205                                        (fixture_name))
    222206
    223207            # Since we disabled constraint checks, we must manually check for
    224208            # any invalid keys that might have been added
    class Command(BaseCommand):  
    227211
    228212        except (SystemExit, KeyboardInterrupt):
    229213            raise
     214        except CommandError:
     215            if commit:
     216                transaction.rollback(using=using)
     217                transaction.leave_transaction_management(using=using)
     218            raise
    230219        except Exception:
    231220            if commit:
    232221                transaction.rollback(using=using)
    class Command(BaseCommand):  
    234223            if show_traceback:
    235224                traceback.print_exc()
    236225            else:
    237                 self.stderr.write(
    238                     self.style.ERROR("Problem installing fixture '%s': %s\n" %
    239                          (full_path, ''.join(traceback.format_exception(sys.exc_type,
    240                              sys.exc_value, sys.exc_traceback)))))
     226                self.error("Problem installing fixture '%s': %s" % (
     227                           full_path, ''.join(traceback.format_exception(sys.exc_type,
     228                           sys.exc_value, sys.exc_traceback))))
    241229            return
    242230
    243231
    244232        # If we found even one object in a fixture, we need to reset the
    245233        # database sequences.
    246234        if loaded_object_count > 0:
    247             sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
     235            sequence_sql = connection.ops.sequence_reset_sql(no_style(), models)
    248236            if sequence_sql:
    249237                if verbosity >= 2:
    250                     self.stdout.write("Resetting sequences\n")
     238                    self.info("Resetting sequences")
    251239                for line in sequence_sql:
    252240                    cursor.execute(line)
    253241
    class Command(BaseCommand):  
    257245
    258246        if verbosity >= 1:
    259247            if fixture_object_count == loaded_object_count:
    260                 self.stdout.write("Installed %d object(s) from %d fixture(s)\n" % (
     248                self.info("Installed %d object(s) from %d fixture(s)" % (
    261249                    loaded_object_count, fixture_count))
    262250            else:
    263                 self.stdout.write("Installed %d object(s) (of %d) from %d fixture(s)\n" % (
     251                self.info("Installed %d object(s) (of %d) from %d fixture(s)" % (
    264252                    loaded_object_count, fixture_object_count, fixture_count))
    265253
    266254        # Close the DB connection. This is required as a workaround for an
  • django/core/management/commands/makemessages.py

    diff --git a/django/core/management/commands/makemessages.py b/django/core/management/commands/makemessages.py
    index 24d5bea..2a11cc7 100644
    a b def _popen(cmd):  
    4646    return p.communicate()
    4747
    4848def walk(root, topdown=True, onerror=None, followlinks=False,
    49          ignore_patterns=None, verbosity=0, stdout=sys.stdout):
     49         ignore_patterns=None, verbosity=0, logger=None):
    5050    """
    5151    A version of os.walk that can follow symlinks for Python < 2.6
    5252    """
    def walk(root, topdown=True, onerror=None, followlinks=False,  
    6363        for dirname in remove_dirs:
    6464            dirnames.remove(dirname)
    6565            if verbosity > 1:
    66                 stdout.write('ignoring directory %s\n' % dirname)
     66                logger.info('ignoring directory %s' % dirname)
    6767        yield (dirpath, dirnames, filenames)
    6868        if followlinks:
    6969            for d in dirnames:
    def is_ignored(path, ignore_patterns):  
    8181            return True
    8282    return False
    8383
    84 def find_files(root, ignore_patterns, verbosity, stdout=sys.stdout, symlinks=False):
     84def find_files(root, ignore_patterns, verbosity, logger, symlinks=False):
    8585    """
    8686    Helper function to get all files in the given root.
    8787    """
    8888    all_files = []
    8989    for (dirpath, dirnames, filenames) in walk(root, followlinks=symlinks,
    90             ignore_patterns=ignore_patterns, verbosity=verbosity, stdout=stdout):
     90            ignore_patterns=ignore_patterns, verbosity=verbosity, logger=logger):
    9191        for filename in filenames:
    9292            norm_filepath = os.path.normpath(os.path.join(dirpath, filename))
    9393            if is_ignored(norm_filepath, ignore_patterns):
    9494                if verbosity > 1:
    95                     stdout.write('ignoring file %s in %s\n' % (filename, dirpath))
     95                    logger.info('ignoring file %s in %s' % (filename, dirpath))
    9696            else:
    9797                all_files.extend([(dirpath, filename)])
    9898    all_files.sort()
    9999    return all_files
    100100
    101 def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout):
     101def copy_plural_forms(msgs, locale, domain, verbosity, logger):
    102102    """
    103103    Copies plural forms header contents from a Django catalog of locale to
    104104    the msgs string, inserting it at the right place. msgs should be the
    def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout):  
    115115            m = plural_forms_re.search(open(django_po, 'rU').read())
    116116            if m:
    117117                if verbosity > 1:
    118                     stdout.write("copying plural forms: %s\n" % m.group('value'))
     118                    logger.info("copying plural forms: %s" % m.group('value'))
    119119                lines = []
    120120                seen = False
    121121                for line in msgs.split('\n'):
    def write_pot_file(potfile, msgs, file, work_file, is_templatized):  
    148148        f.close()
    149149
    150150def process_file(file, dirpath, potfile, domain, verbosity,
    151                  extensions, wrap, location, stdout=sys.stdout):
     151                 extensions, wrap, location, logger):
    152152    """
    153153    Extract translatable literals from :param file: for :param domain:
    154154    creating or updating the :param potfile: POT file.
    def process_file(file, dirpath, potfile, domain, verbosity,  
    159159    from django.utils.translation import templatize
    160160
    161161    if verbosity > 1:
    162         stdout.write('processing file %s in %s\n' % (file, dirpath))
     162        logger.info('processing file %s in %s' % (file, dirpath))
    163163    _, file_ext = os.path.splitext(file)
    164164    if domain == 'djangojs' and file_ext in extensions:
    165165        is_templatized = True
    def process_file(file, dirpath, potfile, domain, verbosity,  
    218218    if is_templatized:
    219219        os.unlink(work_file)
    220220
    221 def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
     221def write_po_file(pofile, potfile, domain, locale, verbosity, logger,
    222222                  copy_pforms, wrap, location, no_obsolete):
    223223    """
    224224    Creates of updates the :param pofile: PO file for :param domain: and :param
    def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,  
    244244            raise CommandError(
    245245                "errors happened while running msgmerge\n%s" % errors)
    246246    elif copy_pforms:
    247         msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout)
     247        msgs = copy_plural_forms(msgs, locale, domain, verbosity, logger)
    248248    msgs = msgs.replace(
    249249        "#. #-#-#-#-#  %s.pot (PACKAGE VERSION)  #-#-#-#-#\n" % domain, "")
    250250    f = open(pofile, 'wb')
    def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,  
    262262
    263263def make_messages(locale=None, domain='django', verbosity=1, all=False,
    264264        extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
    265         no_location=False, no_obsolete=False, stdout=sys.stdout):
     265        no_location=False, no_obsolete=False, logger=None):
    266266    """
    267267    Uses the ``locale/`` directory from the Django SVN tree or an
    268268    application/project to process all files with translatable literals for
    def make_messages(locale=None, domain='django', verbosity=1, all=False,  
    324324
    325325    for locale in locales:
    326326        if verbosity > 0:
    327             stdout.write("processing language %s" % locale)
     327            logger.info("processing language %s" % locale)
    328328        basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
    329329        if not os.path.isdir(basedir):
    330330            os.makedirs(basedir)
    def make_messages(locale=None, domain='django', verbosity=1, all=False,  
    336336            os.unlink(potfile)
    337337
    338338        for dirpath, file in find_files(".", ignore_patterns, verbosity,
    339                 stdout, symlinks=symlinks):
     339                logger, symlinks=symlinks):
    340340            process_file(file, dirpath, potfile, domain, verbosity, extensions,
    341                     wrap, location, stdout)
     341                    wrap, location, logger)
    342342
    343343        if os.path.exists(potfile):
    344             write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
     344            write_po_file(pofile, potfile, domain, locale, verbosity, logger,
    345345                    not invoked_for_django, wrap, location, no_obsolete)
    346346
    347347
    class Command(NoArgsCommand):  
    399399        extensions = handle_extensions(exts)
    400400
    401401        if verbosity > 1:
    402             self.stdout.write('examining files with the extensions: %s\n'
    403                              % get_text_list(list(extensions), 'and'))
     402            self.info('examining files with the extensions: %s'
     403                      % get_text_list(list(extensions), 'and'))
    404404
    405405        make_messages(locale, domain, verbosity, process_all, extensions,
    406             symlinks, ignore_patterns, no_wrap, no_location, no_obsolete, self.stdout)
     406            symlinks, ignore_patterns, no_wrap, no_location, no_obsolete, self._logger)
  • django/core/management/commands/reset.py

    diff --git a/django/core/management/commands/reset.py b/django/core/management/commands/reset.py
    index 9539212..bfdcb55 100644
    a b Hint: Look at the output of 'django-admin.py sqlreset %s'. That's the SQL this c  
    5959The full error: %s""" % (app_name, app_name, e))
    6060            transaction.commit_unless_managed()
    6161        else:
    62             print "Reset cancelled."
     62            return "Reset cancelled."
  • django/core/management/commands/runserver.py

    diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
    index fa11f93..cf90aac 100644
    a b class BaseRunserverCommand(BaseCommand):  
    8787        shutdown_message = options.get('shutdown_message', '')
    8888        quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C'
    8989
    90         self.stdout.write("Validating models...\n\n")
     90        self.info("Validating models...\n")
    9191        self.validate(display_num_errors=True)
    92         self.stdout.write((
     92        self.info(
    9393            "Django version %(version)s, using settings %(settings)r\n"
    9494            "Development server is running at http://%(addr)s:%(port)s/\n"
    95             "Quit the server with %(quit_command)s.\n"
    96         ) % {
    97             "version": self.get_version(),
    98             "settings": settings.SETTINGS_MODULE,
    99             "addr": self._raw_ipv6 and '[%s]' % self.addr or self.addr,
    100             "port": self.port,
    101             "quit_command": quit_command,
    102         })
     95            "Quit the server with %(quit_command)s.\n" % {
     96                "version": self.get_version(),
     97                "settings": settings.SETTINGS_MODULE,
     98                "addr": self._raw_ipv6 and '[%s]' % self.addr or self.addr,
     99                "port": self.port,
     100                "quit_command": quit_command,
     101            }
     102        )
    103103        # django.core.management.base forces the locale to en-us. We should
    104104        # set it up correctly for the first request (particularly important
    105105        # in the "--noreload" case).
    class BaseRunserverCommand(BaseCommand):  
    120120                error_text = ERRORS[e.args[0].args[0]]
    121121            except (AttributeError, KeyError):
    122122                error_text = str(e)
    123             sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n')
     123            self.error("Error: %s" % error_text)
    124124            # Need to use an OS exit because sys.exit doesn't work in a thread
    125125            os._exit(1)
    126126        except KeyboardInterrupt:
    127127            if shutdown_message:
    128                 self.stdout.write("%s\n" % shutdown_message)
     128                self.info(shutdown_message)
    129129            sys.exit(0)
    130130
    131131class Command(BaseRunserverCommand):
  • django/core/management/commands/syncdb.py

    diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
    index 852fa15..0282070 100644
    a b class Command(NoArgsCommand):  
    8282
    8383        # Create the tables for each model
    8484        if verbosity >= 1:
    85             print "Creating tables ..."
     85            self.info("Creating tables ...")
    8686        for app_name, model_list in manifest.items():
    8787            for model in model_list:
    8888                # Create the model's database table, if it doesn't already exist.
    8989                if verbosity >= 3:
    90                     print "Processing %s.%s model" % (app_name, model._meta.object_name)
     90                    self.info("Processing %s.%s model" % (app_name, model._meta.object_name))
    9191                sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
    9292                seen_models.add(model)
    9393                created_models.add(model)
    class Command(NoArgsCommand):  
    9797                        sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
    9898                sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
    9999                if verbosity >= 1 and sql:
    100                     print "Creating table %s" % model._meta.db_table
     100                    self.info("Creating table %s" % model._meta.db_table)
    101101                for statement in sql:
    102102                    cursor.execute(statement)
    103103                tables.append(connection.introspection.table_name_converter(model._meta.db_table))
    class Command(NoArgsCommand):  
    115115        # Install custom SQL for the app (but only if this
    116116        # is a model we've just created)
    117117        if verbosity >= 1:
    118             print "Installing custom SQL ..."
     118            self.info("Installing custom SQL ...")
    119119        for app_name, model_list in manifest.items():
    120120            for model in model_list:
    121121                if model in created_models:
    122122                    custom_sql = custom_sql_for_model(model, self.style, connection)
    123123                    if custom_sql:
    124124                        if verbosity >= 2:
    125                             print "Installing custom SQL for %s.%s model" % (app_name, model._meta.object_name)
     125                            self.info("Installing custom SQL for %s.%s model" % (
     126                                app_name, model._meta.object_name))
    126127                        try:
    127128                            for sql in custom_sql:
    128129                                cursor.execute(sql)
    129130                        except Exception, e:
    130                             sys.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \
    131                                                 (app_name, model._meta.object_name, e))
     131                            self.error("Failed to install custom SQL for %s.%s model: %s" % (
     132                                       app_name, model._meta.object_name, e))
    132133                            if show_traceback:
    133134                                traceback.print_exc()
    134135                            transaction.rollback_unless_managed(using=db)
    class Command(NoArgsCommand):  
    136137                            transaction.commit_unless_managed(using=db)
    137138                    else:
    138139                        if verbosity >= 3:
    139                             print "No custom SQL for %s.%s model" % (app_name, model._meta.object_name)
     140                            self.info("No custom SQL for %s.%s model" % (
     141                                app_name, model._meta.object_name))
    140142
    141143        if verbosity >= 1:
    142             print "Installing indexes ..."
     144            self.info("Installing indexes ...")
    143145        # Install SQL indices for all newly created models
    144146        for app_name, model_list in manifest.items():
    145147            for model in model_list:
    class Command(NoArgsCommand):  
    147149                    index_sql = connection.creation.sql_indexes_for_model(model, self.style)
    148150                    if index_sql:
    149151                        if verbosity >= 2:
    150                             print "Installing index for %s.%s model" % (app_name, model._meta.object_name)
     152                            self.info("Installing index for %s.%s model" % (
     153                                app_name, model._meta.object_name))
    151154                        try:
    152155                            for sql in index_sql:
    153156                                cursor.execute(sql)
    154157                        except Exception, e:
    155                             sys.stderr.write("Failed to install index for %s.%s model: %s\n" % \
    156                                                 (app_name, model._meta.object_name, e))
     158                            self.error("Failed to install index for %s.%s model: %s" % (
     159                                                app_name, model._meta.object_name, e))
    157160                            transaction.rollback_unless_managed(using=db)
    158161                        else:
    159162                            transaction.commit_unless_managed(using=db)
  • django/core/management/templates.py

    diff --git a/django/core/management/templates.py b/django/core/management/templates.py
    index 1d26e97..196f65e 100644
    a b class TemplateCommand(BaseCommand):  
    9898        for file in options.get('files'):
    9999            extra_files.extend(map(lambda x: x.strip(), file.split(',')))
    100100        if self.verbosity >= 2:
    101             self.stdout.write("Rendering %s template files with "
    102                               "extensions: %s\n" %
    103                               (app_or_project, ', '.join(extensions)))
    104             self.stdout.write("Rendering %s template files with "
    105                               "filenames: %s\n" %
    106                               (app_or_project, ', '.join(extra_files)))
     101            self.info("Rendering %s template files with extensions: %s" %
     102                      (app_or_project, ', '.join(extensions)))
     103            self.info("Rendering %s template files with filenames: %s" %
     104                      (app_or_project, ', '.join(extra_files)))
    107105
    108106        base_name = '%s_name' % app_or_project
    109107        base_subdir = '%s_template' % app_or_project
    class TemplateCommand(BaseCommand):  
    160158                    new_file.write(content)
    161159
    162160                if self.verbosity >= 2:
    163                     self.stdout.write("Creating %s\n" % new_path)
     161                    self.info("Creating %s" % new_path)
    164162                try:
    165163                    shutil.copymode(old_path, new_path)
    166164                    self.make_writeable(new_path)
    class TemplateCommand(BaseCommand):  
    168166                    notice = self.style.NOTICE(
    169167                        "Notice: Couldn't set permission bits on %s. You're "
    170168                        "probably using an uncommon filesystem setup. No "
    171                         "problem.\n" % new_path)
    172                     sys.stderr.write(smart_str(notice))
     169                        "problem." % new_path)
     170                    self.error(notice)
    173171
    174172        if self.paths_to_remove:
    175173            if self.verbosity >= 2:
    176                 self.stdout.write("Cleaning up temporary files.\n")
     174                self.info("Cleaning up temporary files.")
    177175            for path_to_remove in self.paths_to_remove:
    178176                if path.isfile(path_to_remove):
    179177                    os.remove(path_to_remove)
    class TemplateCommand(BaseCommand):  
    226224        filename, display_url = cleanup_url(url)
    227225
    228226        if self.verbosity >= 2:
    229             self.stdout.write("Downloading %s\n" % display_url)
     227            self.info("Downloading %s" % display_url)
    230228        try:
    231229            the_path, info = urllib.urlretrieve(url,
    232230                                                path.join(tempdir, filename))
    class TemplateCommand(BaseCommand):  
    281279        tempdir = tempfile.mkdtemp(prefix=prefix, suffix='_extract')
    282280        self.paths_to_remove.append(tempdir)
    283281        if self.verbosity >= 2:
    284             self.stdout.write("Extracting %s\n" % filename)
     282            self.info("Extracting %s" % filename)
    285283        try:
    286284            archive.extract(filename, tempdir)
    287285            return tempdir
  • django/utils/log.py

    diff --git a/django/utils/log.py b/django/utils/log.py
    index df2089f..6ffa871 100644
    a b  
    11import logging
     2import sys
    23import traceback
    34
    45from django.conf import settings
    try:  
    2122except ImportError:
    2223    from django.utils.dictconfig import dictConfig
    2324
    24 getLogger = logging.getLogger
    25 
    26 # Ensure the creation of the Django logger
    27 # with a null handler. This ensures we don't get any
    28 # 'No handlers could be found for logger "django"' messages
    29 logger = getLogger('django')
    30 if not logger.handlers:
    31     logger.addHandler(NullHandler())
    32 
    3325
    3426class AdminEmailHandler(logging.Handler):
    3527    """An exception log handler that emails log entries to site admins.
    class CallbackFilter(logging.Filter):  
    10395class RequireDebugFalse(logging.Filter):
    10496    def filter(self, record):
    10597        return not settings.DEBUG
     98
     99
     100class SingleLevelFilter(logging.Filter):
     101    def __init__(self, passlevel, reject):
     102        self.passlevel = passlevel
     103        self.reject = reject
     104
     105    def filter(self, record):
     106        if self.reject:
     107            return (record.levelno != self.passlevel)
     108        else:
     109            return (record.levelno == self.passlevel)
     110
     111
     112def setup_commands_logger(name, stdout, stderr):
     113    logger = getLogger(name)
     114    if not logger.handlers or name.endswith('temp'):
     115        logger.setLevel(logging.DEBUG)
     116        logger.handlers = []
     117        handler_out = logging.StreamHandler(stdout)
     118        handler_out.addFilter(SingleLevelFilter(logging.INFO, False))
     119        handler_err = logging.StreamHandler(stderr)
     120        handler_err.addFilter(SingleLevelFilter(logging.INFO, True))
     121        logger.addHandler(handler_out)
     122        logger.addHandler(handler_err)
     123    return logger
     124
     125getLogger = logging.getLogger
     126
     127# Ensure the creation of the Django logger
     128# with a null handler. This ensures we don't get any
     129# 'No handlers could be found for logger "django"' messages
     130logger = getLogger('django')
     131if not logger.handlers:
     132    logger.addHandler(NullHandler())
     133
     134setup_commands_logger('django.commands', sys.stdout, sys.stderr)
  • docs/howto/custom-management-commands.txt

    diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
    index 1de256a..921b164 100644
    a b look like this:  
    6262                poll.opened = False
    6363                poll.save()
    6464
    65                 self.stdout.write('Successfully closed poll "%s"\n' % poll_id)
     65                self.info('Successfully closed poll "%s"' % poll_id)
    6666
    6767.. note::
    6868    When you are using management commands and wish to provide console
    69     output, you should write to ``self.stdout`` and ``self.stderr``,
    70     instead of printing to ``stdout`` and ``stderr`` directly. By
    71     using these proxies, it becomes much easier to test your custom
    72     command.
     69    output, you should use the :meth:`~BaseCommand.info` or
     70    :meth:`~BaseCommand.error` methods, instead of printing to ``stdout``
     71    and ``stderr`` directly. By using these proxies, it becomes much easier
     72    to test your custom command or redirect output when needed.
    7373
    7474The new custom command can be called using ``python manage.py closepoll
    7575<poll_id>``.
    the :meth:`~BaseCommand.handle` method must be implemented.  
    248248
    249249    The actual logic of the command. Subclasses must implement this method.
    250250
     251.. method:: BaseCommand.info(message)
     252
     253    Output a message on the console (stdout), unless the default
     254    'django.commands' logger has been customized.
     255
     256.. method:: BaseCommand.error(message)
     257
     258    Output an error message on the console (stderr), unless the default
     259    'django.commands' logger has been customized.
     260
    251261.. _ref-basecommand-subclasses:
    252262
    253263BaseCommand subclasses
  • docs/internals/deprecation.txt

    diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
    index 16dbec8..9bac6e0 100644
    a b these changes.  
    267267  in 1.4. The backward compatibility will be removed --
    268268  ``HttpRequest.raw_post_data`` will no longer work.
    269269
     270* The self.stdout and self.stderr attributes of management BaseCommand will be
     271  removed. They are replaced by the info() and error() methods, added in 1.4.
     272
    2702732.0
    271274---
    272275
  • docs/releases/1.4-beta-1.txt

    diff --git a/docs/releases/1.4-beta-1.txt b/docs/releases/1.4-beta-1.txt
    index a955b39..1a19921 100644
    a b Django 1.4 also includes several smaller improvements worth noting:  
    599599
    600600.. _django/views/debug.py: http://code.djangoproject.com/browser/django/trunk/django/views/debug.py
    601601
     602* Management commands have now ``info()`` and ``error()`` methods for console
     603  output. Output directed to those methods can also be configured by customizing
     604  the 'django.commands' logger.
     605
    602606
    603607Backwards incompatible changes in 1.4
    604608=====================================
  • docs/releases/1.4.txt

    diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
    index b444467..adecee4 100644
    a b Django 1.4 also includes several smaller improvements worth noting:  
    608608  :attr:`Sitemap.protocol <django.contrib.sitemaps.Sitemap.protocol>` class
    609609  attribute.
    610610
     611* Management commands have now ``info()`` and ``error()`` methods for console
     612  output. Output directed to those methods can also be configured by customizing
     613  the 'django.commands' logger.
     614
     615
    611616Backwards incompatible changes in 1.4
    612617=====================================
    613618
  • docs/topics/logging.txt

    diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt
    index cb0a136..b691a7f 100644
    a b For performance reasons, SQL logging is only enabled when  
    455455``settings.DEBUG`` is set to ``True``, regardless of the logging
    456456level or handlers that are installed.
    457457
     458``django.commands``
     459~~~~~~~~~~~~~~~~~~~
     460
     461Messages related to management commands. By default, this logger outputs
     462message on standard output (console).
     463
    458464Handlers
    459465--------
    460466
  • tests/modeltests/fixtures/tests.py

    diff --git a/tests/modeltests/fixtures/tests.py b/tests/modeltests/fixtures/tests.py
    index d22010d..7174cea 100644
    a b class FixtureLoadingTests(TestCase):  
    185185            exclude_list=['fixtures.Article', 'fixtures.Book', 'sites'])
    186186
    187187        # Excluding a bogus app should throw an error
    188         self.assertRaises(SystemExit,
    189                           self._dumpdata_assert,
    190                           ['fixtures', 'sites'],
    191                           '',
    192                           exclude_list=['foo_app'])
     188        with self.assertRaisesRegexp(management.CommandError,
     189                                     "Unknown app in excludes: foo_app"):
     190            self._dumpdata_assert(['fixtures', 'sites'], '', exclude_list=['foo_app'])
    193191
    194192        # Excluding a bogus model should throw an error
    195         self.assertRaises(SystemExit,
    196                           self._dumpdata_assert,
    197                           ['fixtures', 'sites'],
    198                           '',
    199                           exclude_list=['fixtures.FooModel'])
     193        with self.assertRaisesRegexp(management.CommandError,
     194                                     "Unknown model in excludes: fixtures.FooModel"):
     195            self._dumpdata_assert(['fixtures', 'sites'], '', exclude_list=['fixtures.FooModel'])
    200196
    201197    def test_dumpdata_with_filtering_manager(self):
    202198        spy1 = Spy.objects.create(name='Paul')
    class FixtureLoadingTests(TestCase):  
    233229    def test_ambiguous_compressed_fixture(self):
    234230        # The name "fixture5" is ambigous, so loading it will raise an error
    235231        new_io = StringIO.StringIO()
    236         management.call_command('loaddata', 'fixture5', verbosity=0, stderr=new_io, commit=False)
    237         output = new_io.getvalue().strip().split('\n')
    238         self.assertEqual(len(output), 1)
    239         self.assertTrue(output[0].startswith("Multiple fixtures named 'fixture5'"))
     232        with self.assertRaisesRegexp(management.CommandError,
     233                                     "Multiple fixtures named 'fixture5'"):
     234            management.call_command('loaddata', 'fixture5', verbosity=0,
     235                                    stderr=new_io, commit=False)
    240236
    241237    def test_db_loading(self):
    242238        # Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly
    class FixtureLoadingTests(TestCase):  
    261257        new_io = StringIO.StringIO()
    262258        management.call_command('loaddata', 'invalid.json', verbosity=0, stderr=new_io, commit=False)
    263259        output = new_io.getvalue().strip().split('\n')
    264         self.assertRegexpMatches(output[-1], "Error: Could not load fixtures.Article\(pk=1\): .*$")
     260        # Last lines may be polluted by error formatting
     261        self.assertIn("Error: Could not load fixtures.Article(pk=1):", "".join(output[-3:]))
    265262
    266263    def test_loading_using(self):
    267264        # Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly
    class FixtureTransactionTests(TransactionTestCase):  
    317314        # Try to load fixture 2 using format discovery; this will fail
    318315        # because there are two fixture2's in the fixtures directory
    319316        new_io = StringIO.StringIO()
    320         management.call_command('loaddata', 'fixture2', verbosity=0, stderr=new_io)
    321         output = new_io.getvalue().strip().split('\n')
    322         self.assertEqual(len(output), 1)
    323         self.assertTrue(output[0].startswith("Multiple fixtures named 'fixture2'"))
     317        with self.assertRaisesRegexp(management.CommandError,
     318                                     "Multiple fixtures named 'fixture2'"):
     319            management.call_command('loaddata', 'fixture2', verbosity=0, stderr=new_io)
    324320
    325321        # object list is unaffected
    326322        self.assertQuerysetEqual(Article.objects.all(), [
  • tests/modeltests/user_commands/management/commands/dance.py

    diff --git a/tests/modeltests/user_commands/management/commands/dance.py b/tests/modeltests/user_commands/management/commands/dance.py
    index 4ad5579..47875d2 100644
    a b class Command(BaseCommand):  
    1515
    1616    def handle(self, *args, **options):
    1717        example = options["example"]
    18         self.stdout.write("I don't feel like dancing %s." % options["style"])
     18        self.info("I don't feel like dancing %s." % options["style"])
  • tests/modeltests/user_commands/tests.py

    diff --git a/tests/modeltests/user_commands/tests.py b/tests/modeltests/user_commands/tests.py
    index e138e07..de1687a 100644
    a b class CommandTests(TestCase):  
    1313        out = StringIO()
    1414        management.call_command('dance', stdout=out)
    1515        self.assertEqual(out.getvalue(),
    16             "I don't feel like dancing Rock'n'Roll.")
     16            "I don't feel like dancing Rock'n'Roll.\n")
    1717
    1818    def test_command_style(self):
    1919        out = StringIO()
    2020        management.call_command('dance', style='Jive', stdout=out)
    2121        self.assertEqual(out.getvalue(),
    22             "I don't feel like dancing Jive.")
     22            "I don't feel like dancing Jive.\n")
    2323
    2424    def test_language_preserved(self):
    2525        out = StringIO()
  • tests/regressiontests/cache/tests.py

    diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
    index bd29cde..3c6280d 100644
    a b class DBCacheTests(BaseCacheTests, TransactionTestCase):  
    819819        self.perform_cull_test(50, 18)
    820820
    821821    def test_second_call_doesnt_crash(self):
    822         err = StringIO.StringIO()
    823         management.call_command('createcachetable', self._table_name, verbosity=0, interactive=False, stderr=err)
    824         self.assertTrue("Cache table 'test cache table' could not be created" in err.getvalue())
     822        with self.assertRaisesRegexp(management.CommandError,
     823            "Cache table 'test cache table' could not be created"):
     824            management.call_command(
     825                'createcachetable',
     826                self._table_name,
     827                verbosity=0,
     828                interactive=False
     829            )
    825830
    826831
    827832DBCacheWithTimeZoneTests = override_settings(USE_TZ=True)(DBCacheTests)
  • tests/regressiontests/fixtures_regress/tests.py

    diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py
    index ed8b404..305b349 100644
    a b  
    11# -*- coding: utf-8 -*-
    22# Unittests for fixtures.
    3 from __future__ import absolute_import
     3from __future__ import absolute_import, with_statement
    44
    55import os
    66import re
    class TestFixtures(TestCase):  
    119119        Test for ticket #4371 -- Loading data of an unknown format should fail
    120120        Validate that error conditions are caught correctly
    121121        """
    122         stderr = StringIO()
    123         management.call_command(
    124             'loaddata',
    125             'bad_fixture1.unkn',
    126             verbosity=0,
    127             commit=False,
    128             stderr=stderr,
    129         )
    130         self.assertEqual(
    131             stderr.getvalue(),
    132             "Problem installing fixture 'bad_fixture1': unkn is not a known serialization format.\n"
    133         )
     122        with self.assertRaisesRegexp(CommandError,
     123            "Problem installing fixture 'bad_fixture1': unkn is not a known serialization format."):
     124            management.call_command(
     125                'loaddata',
     126                'bad_fixture1.unkn',
     127                verbosity=0,
     128                commit=False,
     129            )
    134130
    135131    def test_invalid_data(self):
    136132        """
    class TestFixtures(TestCase):  
    138134        using explicit filename.
    139135        Validate that error conditions are caught correctly
    140136        """
    141         stderr = StringIO()
    142         management.call_command(
    143             'loaddata',
    144             'bad_fixture2.xml',
    145             verbosity=0,
    146             commit=False,
    147             stderr=stderr,
    148         )
    149         self.assertEqual(
    150             stderr.getvalue(),
    151             "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n"
    152         )
     137        with self.assertRaisesRegexp(CommandError,
     138            "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
     139            management.call_command(
     140                'loaddata',
     141                'bad_fixture2.xml',
     142                verbosity=0,
     143                commit=False,
     144            )
    153145
    154146    def test_invalid_data_no_ext(self):
    155147        """
    class TestFixtures(TestCase):  
    157149        without file extension.
    158150        Validate that error conditions are caught correctly
    159151        """
    160         stderr = StringIO()
    161         management.call_command(
    162             'loaddata',
    163             'bad_fixture2',
    164             verbosity=0,
    165             commit=False,
    166             stderr=stderr,
    167         )
    168         self.assertEqual(
    169             stderr.getvalue(),
    170             "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n"
    171         )
     152        with self.assertRaisesRegexp(CommandError,
     153            "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
     154            management.call_command(
     155                'loaddata',
     156                'bad_fixture2',
     157                verbosity=0,
     158                commit=False,
     159            )
    172160
    173161    def test_empty(self):
    174162        """
    175163        Test for ticket #4371 -- Loading a fixture file with no data returns an error.
    176164        Validate that error conditions are caught correctly
    177165        """
    178         stderr = StringIO()
    179         management.call_command(
    180             'loaddata',
    181             'empty',
    182             verbosity=0,
    183             commit=False,
    184             stderr=stderr,
    185         )
    186         self.assertEqual(
    187             stderr.getvalue(),
    188             "No fixture data found for 'empty'. (File format may be invalid.)\n"
    189         )
    190 
    191     def test_abort_loaddata_on_error(self):
    192         """
    193         Test for ticket #4371 -- If any of the fixtures contain an error,
    194         loading is aborted.
    195         Validate that error conditions are caught correctly
    196         """
    197         stderr = StringIO()
    198         management.call_command(
    199             'loaddata',
    200             'empty',
    201             verbosity=0,
    202             commit=False,
    203             stderr=stderr,
    204         )
    205         self.assertEqual(
    206             stderr.getvalue(),
    207             "No fixture data found for 'empty'. (File format may be invalid.)\n"
    208         )
     166        with self.assertRaisesRegexp(CommandError,
     167            "No fixture data found for 'empty'. \(File format may be invalid.\)"):
     168            management.call_command(
     169                'loaddata',
     170                'empty',
     171                verbosity=0,
     172                commit=False,
     173            )
    209174
    210175    def test_error_message(self):
    211176        """
    212177        (Regression for #9011 - error message is correct)
    213178        """
    214         stderr = StringIO()
    215         management.call_command(
    216             'loaddata',
    217             'bad_fixture2',
    218             'animal',
    219             verbosity=0,
    220             commit=False,
    221             stderr=stderr,
    222         )
    223         self.assertEqual(
    224             stderr.getvalue(),
    225             "No fixture data found for 'bad_fixture2'. (File format may be invalid.)\n"
    226         )
     179        with self.assertRaisesRegexp(CommandError,
     180            "No fixture data found for 'bad_fixture2'. \(File format may be invalid.\)"):
     181            management.call_command(
     182                'loaddata',
     183                'bad_fixture2',
     184                'animal',
     185                verbosity=0,
     186                commit=False,
     187            )
    227188
    228189    def test_pg_sequence_resetting_checks(self):
    229190        """
    class TestFixtures(TestCase):  
    337298        platypus_json = '{"pk": %d, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}'
    338299        platypus_json = platypus_json % animal.pk
    339300
    340         self.assertEqual(len(data), len('[%s]' % ', '.join([lion_json, emu_json, platypus_json])))
     301        # -1 is for the final newline
     302        self.assertEqual(len(data)-1, len('[%s]' % ', '.join([lion_json, emu_json, platypus_json])))
    341303        self.assertTrue(lion_json in data)
    342304        self.assertTrue(emu_json in data)
    343305        self.assertTrue(platypus_json in data)
    class TestFixtures(TestCase):  
    358320        )
    359321        self.assertEqual(
    360322            stdout.getvalue(),
    361             """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]"""
     323            """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]\n"""
    362324            % widget.pk
    363325            )
    364326
    class TestFixtures(TestCase):  
    387349            commit=False,
    388350            stderr=stderr,
    389351        )
    390         self.assertTrue(
    391             stderr.getvalue().startswith('Problem installing fixture')
    392         )
     352        self.assertIn('Problem installing fixture', stderr.getvalue())
    393353
    394354    _cur_dir = os.path.dirname(os.path.abspath(__file__))
    395355
    class TestFixtures(TestCase):  
    414374        """
    415375        Regression for #7043 - Error is quickly reported when no fixtures is provided in the command line.
    416376        """
    417         stderr = StringIO()
    418         management.call_command(
    419             'loaddata',
    420             verbosity=0,
    421             commit=False,
    422             stderr=stderr,
    423         )
    424         self.assertEqual(
    425             stderr.getvalue(), 'No database fixture specified. Please provide the path of at least one fixture in the command line.\n'
    426         )
     377        with self.assertRaisesRegexp(CommandError,
     378            "No database fixture specified. "
     379            "Please provide the path of at least one fixture in the command line."):
     380            management.call_command(
     381                'loaddata',
     382                verbosity=0,
     383                commit=False,
     384            )
    427385
    428386    def test_loaddata_not_existant_fixture_file(self):
    429387        stdout_output = StringIO()
    class NaturalKeyFixtureTests(TestCase):  
    524482        )
    525483        self.assertEqual(
    526484            stdout.getvalue(),
    527             """[{"pk": 2, "model": "fixtures_regress.store", "fields": {"name": "Amazon"}}, {"pk": 3, "model": "fixtures_regress.store", "fields": {"name": "Borders"}}, {"pk": 4, "model": "fixtures_regress.person", "fields": {"name": "Neal Stephenson"}}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]"""
     485            """[{"pk": 2, "model": "fixtures_regress.store", "fields": {"name": "Amazon"}}, {"pk": 3, "model": "fixtures_regress.store", "fields": {"name": "Borders"}}, {"pk": 4, "model": "fixtures_regress.person", "fields": {"name": "Neal Stephenson"}}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]\n"""
    528486        )
    529487
    530488    def test_dependency_sorting(self):
  • tests/regressiontests/i18n/commands/compilation.py

    diff --git a/tests/regressiontests/i18n/commands/compilation.py b/tests/regressiontests/i18n/commands/compilation.py
    index ee558b2..0731b18 100644
    a b  
    11from __future__ import with_statement
    22
    33import os
    4 try:
    5     from cStringIO import StringIO
    6 except ImportError:
    7     from StringIO import StringIO
     4from StringIO import StringIO
    85
    9 from django.core.management import CommandError
    10 from django.core.management.commands.compilemessages import compile_messages
     6from django.core.management import call_command, CommandError
    117from django.test import TestCase
    128from django.test.utils import override_settings
    139from django.utils import translation
    1410
    1511test_dir = os.path.abspath(os.path.dirname(__file__))
    1612
     13
    1714class MessageCompilationTests(TestCase):
    1815
    1916    def setUp(self):
    class PoFileTests(MessageCompilationTests):  
    3027
    3128    def test_bom_rejection(self):
    3229        os.chdir(test_dir)
    33         # We don't use the django.core.management infrastructure (call_command()
    34         # et al) because CommandError's cause exit(1) there. We test the
    35         # underlying compile_messages function instead
    3630        out = StringIO()
    37         self.assertRaises(CommandError, compile_messages, out, locale=self.LOCALE)
     31        self.assertRaises(CommandError, call_command, 'compilemessages',
     32                          locale=self.LOCALE, stdout=out, stderr=out)
    3833        self.assertFalse(os.path.exists(self.MO_FILE))
    3934
    4035
    class PoFileContentsTests(MessageCompilationTests):  
    5045
    5146    def test_percent_symbol_in_po_file(self):
    5247        os.chdir(test_dir)
    53         # We don't use the django.core.management infrastructure (call_command()
    54         # et al) because CommandError's cause exit(1) there. We test the
    55         # underlying compile_messages function instead
    56         out = StringIO()
    57         compile_messages(out, locale=self.LOCALE)
     48        call_command('compilemessages', locale=self.LOCALE, stdout=StringIO())
    5849        self.assertTrue(os.path.exists(self.MO_FILE))
    5950
    6051
    class PercentRenderingTests(MessageCompilationTests):  
    6960    def test_percent_symbol_escaping(self):
    7061        from django.template import Template, Context
    7162        os.chdir(test_dir)
    72         # We don't use the django.core.management infrastructure (call_command()
    73         # et al) because CommandError's cause exit(1) there. We test the
    74         # underlying compile_messages function instead
    75         out = StringIO()
    76         compile_messages(out, locale=self.LOCALE)
     63        call_command('compilemessages', locale=self.LOCALE, stdout=StringIO())
    7764        with translation.override(self.LOCALE):
    7865            t = Template('{% load i18n %}{% trans "Looks like a str fmt spec %% o but shouldn\'t be interpreted as such" %}')
    7966            rendered = t.render(Context({}))
  • tests/regressiontests/staticfiles_tests/tests.py

    diff --git a/tests/regressiontests/staticfiles_tests/tests.py b/tests/regressiontests/staticfiles_tests/tests.py
    index 680027b..61ad992 100644
    a b class TestFindStatic(CollectionTestCase, TestDefaults):  
    187187    Test ``findstatic`` management command.
    188188    """
    189189    def _get_file(self, filepath):
    190         _stdout = sys.stdout
    191         sys.stdout = StringIO()
    192         try:
    193             call_command('findstatic', filepath, all=False, verbosity='0')
    194             sys.stdout.seek(0)
    195             lines = [l.strip() for l in sys.stdout.readlines()]
    196             contents = codecs.open(
    197                 smart_unicode(lines[1].strip()), "r", "utf-8").read()
    198         finally:
    199             sys.stdout = _stdout
     190        out = StringIO()
     191        call_command('findstatic', filepath, all=False, verbosity='0', stdout=out)
     192        lines = [l.strip() for l in out.getvalue().split('\n') if l != '']
     193        contents = codecs.open(
     194            smart_unicode(lines[1].strip()), "r", "utf-8").read()
    200195        return contents
    201196
    202197    def test_all_files(self):
    203198        """
    204199        Test that findstatic returns all candidate files if run without --first.
    205200        """
    206         _stdout = sys.stdout
    207         sys.stdout = StringIO()
    208         try:
    209             call_command('findstatic', 'test/file.txt', verbosity='0')
    210             sys.stdout.seek(0)
    211             lines = [l.strip() for l in sys.stdout.readlines()]
    212         finally:
    213             sys.stdout = _stdout
     201        out = StringIO()
     202        call_command('findstatic', 'test/file.txt', verbosity='0', stdout=out)
     203        lines = [l.strip() for l in out.getvalue().split('\n') if l != '']
    214204        self.assertEqual(len(lines), 3)  # three because there is also the "Found <file> here" line
    215205        self.assertIn('project', lines[1])
    216206        self.assertIn('apps', lines[2])
Back to Top