Ticket #15107: 15107-3.diff

File 15107-3.diff, 70.4 KB (added by Claude Paroz, 12 years ago)

Updated to current trunk

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

    commit a6ed2cf0f2f5ba30f6753e6ac38337d570050aad
    Author: Claude Paroz <claude@2xlibre.net>
    Date:   Sat May 5 21:01:12 2012 +0200
    
        Set output of commands through logging methods
    
    diff --git a/django/contrib/auth/management/commands/changepassword.py b/django/contrib/auth/management/commands/changepassword.py
    index d125dfe..d46cb4f 100644
    a b class Command(BaseCommand):  
    3535        except User.DoesNotExist:
    3636            raise CommandError("user '%s' does not exist" % username)
    3737
    38         self.stdout.write("Changing password for user '%s'\n" % u.username)
     38        self.info("Changing password for user '%s'" % u.username)
    3939
    4040        MAX_TRIES = 3
    4141        count = 0
    class Command(BaseCommand):  
    4444            p1 = self._get_pass()
    4545            p2 = self._get_pass("Password (again): ")
    4646            if p1 != p2:
    47                 self.stdout.write("Passwords do not match. Please try again.\n")
     47                self.info("Passwords do not match. Please try again.")
    4848                count = count + 1
    4949
    5050        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 ad65977..99e2e8e 100644
    a b class Command(BaseCommand):  
    8080                    if default_username and username == '':
    8181                        username = default_username
    8282                    if not RE_VALID_USERNAME.match(username):
    83                         sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
     83                        self.error("Error: That username is invalid. Use only letters, digits and underscores.")
    8484                        username = None
    8585                        continue
    8686                    try:
    class Command(BaseCommand):  
    8888                    except User.DoesNotExist:
    8989                        break
    9090                    else:
    91                         sys.stderr.write("Error: That username is already taken.\n")
     91                        self.error("Error: That username is already taken.")
    9292                        username = None
    9393
    9494                # Get an email
    class Command(BaseCommand):  
    9898                    try:
    9999                        is_valid_email(email)
    100100                    except exceptions.ValidationError:
    101                         sys.stderr.write("Error: That e-mail address is invalid.\n")
     101                        self.error("Error: That e-mail address is invalid.")
    102102                        email = None
    103103                    else:
    104104                        break
    class Command(BaseCommand):  
    109109                        password = getpass.getpass()
    110110                        password2 = getpass.getpass('Password (again): ')
    111111                        if password != password2:
    112                             sys.stderr.write("Error: Your passwords didn't match.\n")
     112                            self.error("Error: Your passwords didn't match.")
    113113                            password = None
    114114                            continue
    115115                    if password.strip() == '':
    116                         sys.stderr.write("Error: Blank passwords aren't allowed.\n")
     116                        self.error("Error: Blank passwords aren't allowed.")
    117117                        password = None
    118118                        continue
    119119                    break
    120120            except KeyboardInterrupt:
    121                 sys.stderr.write("\nOperation cancelled.\n")
     121                self.error("\nOperation cancelled.")
    122122                sys.exit(1)
    123123
    124124        User.objects.db_manager(database).create_superuser(username, email, password)
    125125        if verbosity >= 1:
    126           self.stdout.write("Superuser created successfully.\n")
    127 
     126          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 cab96c8..499a57a 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 0464eb2..d831858 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):  
    362365        if subcommand == 'help':
    363366            if len(args) <= 2:
    364367                parser.print_lax_help()
    365                 sys.stdout.write(self.main_help_text() + '\n')
     368                logger.info(self.main_help_text())
    366369            elif args[2] == '--commands':
    367                 sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
     370                logger.info(self.main_help_text(commands_only=True))
    368371            else:
    369372                self.fetch_command(args[2]).print_help(self.prog_name, args[2])
    370373        elif subcommand == 'version':
    371             sys.stdout.write(parser.get_version() + '\n')
     374            logger.info(parser.get_version())
    372375        # Special-cases: We want 'django-admin.py --version' and
    373376        # 'django-admin.py --help' to work, for backwards compatibility.
    374377        elif self.argv[1:] == ['--version']:
    class ManagementUtility(object):  
    376379            pass
    377380        elif self.argv[1:] in (['--help'], ['-h']):
    378381            parser.print_lax_help()
    379             sys.stdout.write(self.main_help_text() + '\n')
     382            logger.info(self.main_help_text())
    380383        else:
    381384            self.fetch_command(subcommand).run_from_argv(self.argv)
    382385
  • django/core/management/base.py

    diff --git a/django/core/management/base.py b/django/core/management/base.py
    index a936877..d91a2d3 100644
    a b import sys  
    88
    99from optparse import make_option, OptionParser
    1010import traceback
     11import warnings
    1112
    1213import django
    1314from django.core.exceptions import ImproperlyConfigured
    1415from django.core.management.color import color_style
    1516from django.utils.encoding import smart_str
     17from django.utils.log import getLogger, setup_commands_logger
    1618
    1719
    1820class CommandError(Exception):
    def handle_default_options(options):  
    4446        sys.path.insert(0, options.pythonpath)
    4547
    4648
     49class OutputRedirector(object):
     50    """
     51    Utility redirector class used until self.stderr and self.sdtout are
     52    removed from BaseCommand class (1.7)
     53    """
     54    def __init__(self, proxy_func):
     55        self.proxy_func = proxy_func
     56
     57    def write(self, msg):
     58        warnings.warn(
     59            "The 'self.stdout' and 'self.stderr' objects are deprecated, "
     60            "update your management command to use the new info() and error() "
     61            "methods; please see the Django 1.5 release notes "
     62            "(https://docs.djangoproject.com/en/dev/releases/1.5/).",
     63            PendingDeprecationWarning)
     64        self.proxy_func(msg)
     65
     66
    4767class BaseCommand(object):
    4868    """
    4969    The base class from which all management commands ultimately
    class BaseCommand(object):  
    141161
    142162    def __init__(self):
    143163        self.style = color_style()
     164        self._logger = getLogger('django.commands')
    144165
    145166    def get_version(self):
    146167        """
    class BaseCommand(object):  
    220241                if show_traceback:
    221242                    traceback.print_exc()
    222243                else:
    223                     sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
     244                    self.error('Error: %s' % e)
    224245                sys.exit(1)
    225246
     247        if 'stdout' in options or 'stderr' in options:
     248            # Set up a temporary logger
     249            self._logger = setup_commands_logger(
     250                'django.commands_temp',
     251                options.get('stdout', sys.stdout),
     252                options.get('stderr', sys.stderr)
     253            )
     254        # Temporarily redirect, until deprecation path is over (1.6)
     255        self.stdout = OutputRedirector(self.info)
     256        self.stderr = OutputRedirector(self.error)
    226257        try:
    227             self.stdout = options.get('stdout', sys.stdout)
    228             self.stderr = options.get('stderr', sys.stderr)
    229258            if self.requires_model_validation and not options.get('skip_validation'):
    230259                self.validate()
    231260            output = self.handle(*args, **options)
    class BaseCommand(object):  
    236265                    from django.db import connections, DEFAULT_DB_ALIAS
    237266                    connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
    238267                    if connection.ops.start_transaction_sql():
    239                         self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()) + '\n')
    240                 self.stdout.write(output)
    241                 if self.output_transaction:
    242                     self.stdout.write('\n' + self.style.SQL_KEYWORD("COMMIT;") + '\n')
     268                        output = "%s\n%s" % (
     269                            self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()),
     270                            output
     271                        )
     272                    output = "%s\n%s" % (output, self.style.SQL_KEYWORD("COMMIT;"))
     273                self.info(output)
    243274        except CommandError as e:
    244             if show_traceback:
    245                 traceback.print_exc()
     275            if options.get('raise_on_error', False):
     276                raise
    246277            else:
    247                 self.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e)))
    248             sys.exit(1)
     278                if show_traceback:
     279                    traceback.print_exc()
     280                else:
     281                    self.error('Error: %s' % e)
     282                sys.exit(1)
    249283        finally:
     284            if self._logger.name == 'django.commands_temp':
     285                for h in self._logger.handlers:
     286                    h.close()
    250287            if saved_lang is not None:
    251288                translation.activate(saved_lang)
    252289
    class BaseCommand(object):  
    269306            error_text = s.read()
    270307            raise CommandError("One or more models did not validate:\n%s" % error_text)
    271308        if display_num_errors:
    272             self.stdout.write("%s error%s found\n" % (num_errors, num_errors != 1 and 's' or ''))
     309            self.info("%s error%s found" % (num_errors, num_errors != 1 and 's' or ''))
     310
     311    def info(self, msg):
     312        """ Output a message on the logger (stdout by default) """
     313        self._logger.info(msg)
     314
     315    def error(self, msg):
     316        """ Output an error on the logger (stderr by default) """
     317        self._logger.error(smart_str(self.style.ERROR(msg)))
    273318
    274319    def handle(self, *args, **options):
    275320        """
  • django/core/management/commands/compilemessages.py

    diff --git a/django/core/management/commands/compilemessages.py b/django/core/management/commands/compilemessages.py
    index 354787e..b1e5f48 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 82a126b..403722a 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 as 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 ce3c6e8..a6c1a8b 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             self.stdout.write("Flush cancelled.\n")
     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 10fd9bd..1220186 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 848b637..05bc211 100644
    a b import traceback  
    77
    88from django.conf import settings
    99from django.core import serializers
    10 from django.core.management.base import BaseCommand
     10from django.core.management.base import BaseCommand, CommandError
    1111from django.core.management.color import no_style
    1212from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
    1313      IntegrityError, DatabaseError)
    try:  
    2020except ImportError:
    2121    has_bz2 = False
    2222
     23
    2324class Command(BaseCommand):
    2425    help = 'Installs the named fixture(s) in the database.'
    2526    args = "fixture [fixture ...]"
    class Command(BaseCommand):  
    3435        using = options.get('database')
    3536
    3637        connection = connections[using]
    37         self.style = no_style()
    3838
    3939        if not len(fixture_labels):
    40             self.stderr.write(
    41                 self.style.ERROR("No database fixture specified. Please provide the path of at least one fixture in the command line.\n")
    42             )
    43             return
     40            raise CommandError("No database fixture specified. "
     41                "Please provide the path of at least one fixture in the command line.")
    4442
    4543        verbosity = int(options.get('verbosity'))
    4644        show_traceback = options.get('traceback')
    class Command(BaseCommand):  
    124122
    125123                    if formats:
    126124                        if verbosity >= 2:
    127                             self.stdout.write("Loading '%s' fixtures...\n" % fixture_name)
     125                            self.info("Loading '%s' fixtures..." % fixture_name)
    128126                    else:
    129                         self.stderr.write(
    130                             self.style.ERROR("Problem installing fixture '%s': %s is not a known serialization format.\n" %
    131                                 (fixture_name, format)))
    132                         if commit:
    133                             transaction.rollback(using=using)
    134                             transaction.leave_transaction_management(using=using)
    135                         return
     127                        raise CommandError("Problem installing fixture '%s': %s is not a known serialization format." %
     128                            (fixture_name, format))
    136129
    137130                    if os.path.isabs(fixture_name):
    138131                        fixture_dirs = [fixture_name]
    class Command(BaseCommand):  
    141134
    142135                    for fixture_dir in fixture_dirs:
    143136                        if verbosity >= 2:
    144                             self.stdout.write("Checking %s for fixtures...\n" % humanize(fixture_dir))
     137                            self.info("Checking %s for fixtures..." % humanize(fixture_dir))
    145138
    146139                        label_found = False
    147140                        for combo in product([using, None], formats, compression_formats):
    class Command(BaseCommand):  
    154147                            )
    155148
    156149                            if verbosity >= 3:
    157                                 self.stdout.write("Trying %s for %s fixture '%s'...\n" % \
    158                                     (humanize(fixture_dir), file_name, fixture_name))
     150                                self.info("Trying %s for %s fixture '%s'..." % (
     151                                    humanize(fixture_dir), file_name, fixture_name))
    159152                            full_path = os.path.join(fixture_dir, file_name)
    160153                            open_method = compression_types[compression_format]
    161154                            try:
    162155                                fixture = open_method(full_path, 'r')
    163156                            except IOError:
    164157                                if verbosity >= 2:
    165                                     self.stdout.write("No %s fixture '%s' in %s.\n" % \
    166                                         (format, fixture_name, humanize(fixture_dir)))
     158                                    self.info("No %s fixture '%s' in %s." % (
     159                                        format, fixture_name, humanize(fixture_dir)))
    167160                            else:
    168161                                try:
    169162                                    if label_found:
    170                                         self.stderr.write(self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting.\n" %
    171                                             (fixture_name, humanize(fixture_dir))))
    172                                         if commit:
    173                                             transaction.rollback(using=using)
    174                                             transaction.leave_transaction_management(using=using)
    175                                         return
     163                                        raise CommandError("Multiple fixtures named '%s' in %s. Aborting." %
     164                                            (fixture_name, humanize(fixture_dir)))
    176165
    177166                                    fixture_count += 1
    178167                                    objects_in_fixture = 0
    179168                                    loaded_objects_in_fixture = 0
    180169                                    if verbosity >= 2:
    181                                         self.stdout.write("Installing %s fixture '%s' from %s.\n" % \
    182                                             (format, fixture_name, humanize(fixture_dir)))
     170                                        self.info("Installing %s fixture '%s' from %s." % (
     171                                            format, fixture_name, humanize(fixture_dir)))
    183172
    184173                                    objects = serializers.deserialize(format, fixture, using=using)
    185174
    class Command(BaseCommand):  
    208197                                # If the fixture we loaded contains 0 objects, assume that an
    209198                                # error was encountered during fixture loading.
    210199                                if objects_in_fixture == 0:
    211                                     self.stderr.write(
    212                                         self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)\n" %
    213                                             (fixture_name)))
    214                                     if commit:
    215                                         transaction.rollback(using=using)
    216                                         transaction.leave_transaction_management(using=using)
    217                                     return
     200                                    raise CommandError("No fixture data found for '%s'. (File format may be invalid.)" %
     201                                        (fixture_name))
    218202
    219203            # Since we disabled constraint checks, we must manually check for
    220204            # any invalid keys that might have been added
    class Command(BaseCommand):  
    223207
    224208        except (SystemExit, KeyboardInterrupt):
    225209            raise
     210        except CommandError:
     211            if commit:
     212                transaction.rollback(using=using)
     213                transaction.leave_transaction_management(using=using)
     214            raise
    226215        except Exception:
    227216            if commit:
    228217                transaction.rollback(using=using)
    class Command(BaseCommand):  
    230219            if show_traceback:
    231220                traceback.print_exc()
    232221            else:
    233                 self.stderr.write(
    234                     self.style.ERROR("Problem installing fixture '%s': %s\n" %
    235                          (full_path, ''.join(traceback.format_exception(sys.exc_type,
    236                              sys.exc_value, sys.exc_traceback)))))
     222                self.error("Problem installing fixture '%s': %s" % (
     223                           full_path, ''.join(traceback.format_exception(sys.exc_type,
     224                           sys.exc_value, sys.exc_traceback))))
    237225            return
    238226
    239227
    240228        # If we found even one object in a fixture, we need to reset the
    241229        # database sequences.
    242230        if loaded_object_count > 0:
    243             sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
     231            sequence_sql = connection.ops.sequence_reset_sql(no_style(), models)
    244232            if sequence_sql:
    245233                if verbosity >= 2:
    246                     self.stdout.write("Resetting sequences\n")
     234                    self.info("Resetting sequences")
    247235                for line in sequence_sql:
    248236                    cursor.execute(line)
    249237
    class Command(BaseCommand):  
    253241
    254242        if verbosity >= 1:
    255243            if fixture_object_count == loaded_object_count:
    256                 self.stdout.write("Installed %d object(s) from %d fixture(s)\n" % (
     244                self.info("Installed %d object(s) from %d fixture(s)" % (
    257245                    loaded_object_count, fixture_count))
    258246            else:
    259                 self.stdout.write("Installed %d object(s) (of %d) from %d fixture(s)\n" % (
     247                self.info("Installed %d object(s) (of %d) from %d fixture(s)" % (
    260248                    loaded_object_count, fixture_object_count, fixture_count))
    261249
    262250        # 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 046ffb4..bba43d3 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):  
    116116                m = plural_forms_re.search(fp.read())
    117117            if m:
    118118                if verbosity > 1:
    119                     stdout.write("copying plural forms: %s\n" % m.group('value'))
     119                    logger.info("copying plural forms: %s" % m.group('value'))
    120120                lines = []
    121121                seen = False
    122122                for line in msgs.split('\n'):
    def write_pot_file(potfile, msgs, file, work_file, is_templatized):  
    146146        fp.write(msgs)
    147147
    148148def process_file(file, dirpath, potfile, domain, verbosity,
    149                  extensions, wrap, location, stdout=sys.stdout):
     149                 extensions, wrap, location, logger):
    150150    """
    151151    Extract translatable literals from :param file: for :param domain:
    152152    creating or updating the :param potfile: POT file.
    def process_file(file, dirpath, potfile, domain, verbosity,  
    157157    from django.utils.translation import templatize
    158158
    159159    if verbosity > 1:
    160         stdout.write('processing file %s in %s\n' % (file, dirpath))
     160        logger.info('processing file %s in %s' % (file, dirpath))
    161161    _, file_ext = os.path.splitext(file)
    162162    if domain == 'djangojs' and file_ext in extensions:
    163163        is_templatized = True
    def process_file(file, dirpath, potfile, domain, verbosity,  
    212212    if is_templatized:
    213213        os.unlink(work_file)
    214214
    215 def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
     215def write_po_file(pofile, potfile, domain, locale, verbosity, logger,
    216216                  copy_pforms, wrap, location, no_obsolete):
    217217    """
    218218    Creates of updates the :param pofile: PO file for :param domain: and :param
    def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,  
    235235            raise CommandError(
    236236                "errors happened while running msgmerge\n%s" % errors)
    237237    elif copy_pforms:
    238         msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout)
     238        msgs = copy_plural_forms(msgs, locale, domain, verbosity, logger)
    239239    msgs = msgs.replace(
    240240        "#. #-#-#-#-#  %s.pot (PACKAGE VERSION)  #-#-#-#-#\n" % domain, "")
    241241    with open(pofile, 'wb') as fp:
    def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,  
    250250
    251251def make_messages(locale=None, domain='django', verbosity=1, all=False,
    252252        extensions=None, symlinks=False, ignore_patterns=None, no_wrap=False,
    253         no_location=False, no_obsolete=False, stdout=sys.stdout):
     253        no_location=False, no_obsolete=False, logger=None):
    254254    """
    255255    Uses the ``locale/`` directory from the Django Git tree or an
    256256    application/project to process all files with translatable literals for
    def make_messages(locale=None, domain='django', verbosity=1, all=False,  
    312312
    313313    for locale in locales:
    314314        if verbosity > 0:
    315             stdout.write("processing language %s\n" % locale)
     315            logger.info("processing language %s" % locale)
    316316        basedir = os.path.join(localedir, locale, 'LC_MESSAGES')
    317317        if not os.path.isdir(basedir):
    318318            os.makedirs(basedir)
    def make_messages(locale=None, domain='django', verbosity=1, all=False,  
    324324            os.unlink(potfile)
    325325
    326326        for dirpath, file in find_files(".", ignore_patterns, verbosity,
    327                 stdout, symlinks=symlinks):
     327                logger, symlinks=symlinks):
    328328            process_file(file, dirpath, potfile, domain, verbosity, extensions,
    329                     wrap, location, stdout)
     329                    wrap, location, logger)
    330330
    331331        if os.path.exists(potfile):
    332             write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
     332            write_po_file(pofile, potfile, domain, locale, verbosity, logger,
    333333                    not invoked_for_django, wrap, location, no_obsolete)
    334334
    335335
    class Command(NoArgsCommand):  
    387387        extensions = handle_extensions(exts)
    388388
    389389        if verbosity > 1:
    390             self.stdout.write('examining files with the extensions: %s\n'
    391                              % get_text_list(list(extensions), 'and'))
     390            self.info('examining files with the extensions: %s'
     391                      % get_text_list(list(extensions), 'and'))
    392392
    393393        make_messages(locale, domain, verbosity, process_all, extensions,
    394             symlinks, ignore_patterns, no_wrap, no_location, no_obsolete, self.stdout)
     394            symlinks, ignore_patterns, no_wrap, no_location, no_obsolete, self._logger)
  • django/core/management/commands/runserver.py

    diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
    index e618219..f4b2bf1 100644
    a b class Command(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 Command(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
    131131
  • django/core/management/commands/syncdb.py

    diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
    index 88caea1..c7d172a 100644
    a b class Command(NoArgsCommand):  
    8181
    8282        # Create the tables for each model
    8383        if verbosity >= 1:
    84             self.stdout.write("Creating tables ...\n")
     84            self.info("Creating tables ...")
    8585        for app_name, model_list in manifest.items():
    8686            for model in model_list:
    8787                # Create the model's database table, if it doesn't already exist.
    8888                if verbosity >= 3:
    89                     self.stdout.write("Processing %s.%s model\n" % (app_name, model._meta.object_name))
     89                    self.info("Processing %s.%s model" % (app_name, model._meta.object_name))
    9090                sql, references = connection.creation.sql_create_model(model, self.style, seen_models)
    9191                seen_models.add(model)
    9292                created_models.add(model)
    class Command(NoArgsCommand):  
    9696                        sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references))
    9797                sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references))
    9898                if verbosity >= 1 and sql:
    99                     self.stdout.write("Creating table %s\n" % model._meta.db_table)
     99                    self.info("Creating table %s" % model._meta.db_table)
    100100                for statement in sql:
    101101                    cursor.execute(statement)
    102102                tables.append(connection.introspection.table_name_converter(model._meta.db_table))
    class Command(NoArgsCommand):  
    114114        # Install custom SQL for the app (but only if this
    115115        # is a model we've just created)
    116116        if verbosity >= 1:
    117             self.stdout.write("Installing custom SQL ...\n")
     117            self.info("Installing custom SQL ...")
    118118        for app_name, model_list in manifest.items():
    119119            for model in model_list:
    120120                if model in created_models:
    121121                    custom_sql = custom_sql_for_model(model, self.style, connection)
    122122                    if custom_sql:
    123123                        if verbosity >= 2:
    124                             self.stdout.write("Installing custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
     124                            self.info("Installing custom SQL for %s.%s model" % (
     125                                app_name, model._meta.object_name))
    125126                        try:
    126127                            for sql in custom_sql:
    127128                                cursor.execute(sql)
    128129                        except Exception as e:
    129                             self.stderr.write("Failed to install custom SQL for %s.%s model: %s\n" % \
    130                                                 (app_name, model._meta.object_name, e))
     130                            self.error("Failed to install custom SQL for %s.%s model: %s" % (
     131                                       app_name, model._meta.object_name, e))
    131132                            if show_traceback:
    132133                                traceback.print_exc()
    133134                            transaction.rollback_unless_managed(using=db)
    class Command(NoArgsCommand):  
    135136                            transaction.commit_unless_managed(using=db)
    136137                    else:
    137138                        if verbosity >= 3:
    138                             self.stdout.write("No custom SQL for %s.%s model\n" % (app_name, model._meta.object_name))
     139                            self.info("No custom SQL for %s.%s model" % (
     140                                app_name, model._meta.object_name))
    139141
    140142        if verbosity >= 1:
    141             self.stdout.write("Installing indexes ...\n")
     143            self.info("Installing indexes ...")
    142144        # Install SQL indices for all newly created models
    143145        for app_name, model_list in manifest.items():
    144146            for model in model_list:
    class Command(NoArgsCommand):  
    146148                    index_sql = connection.creation.sql_indexes_for_model(model, self.style)
    147149                    if index_sql:
    148150                        if verbosity >= 2:
    149                             self.stdout.write("Installing index for %s.%s model\n" % (app_name, model._meta.object_name))
     151                            self.info("Installing index for %s.%s model" % (
     152                                app_name, model._meta.object_name))
    150153                        try:
    151154                            for sql in index_sql:
    152155                                cursor.execute(sql)
    153156                        except Exception as e:
    154                             self.stderr.write("Failed to install index for %s.%s model: %s\n" % \
    155                                                 (app_name, model._meta.object_name, e))
     157                            self.error("Failed to install index for %s.%s model: %s" % (
     158                                                app_name, model._meta.object_name, e))
    156159                            transaction.rollback_unless_managed(using=db)
    157160                        else:
    158161                            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 735e29a..6955a7b 100644
    a b class TemplateCommand(BaseCommand):  
    9999        for file in options.get('files'):
    100100            extra_files.extend(map(lambda x: x.strip(), file.split(',')))
    101101        if self.verbosity >= 2:
    102             self.stdout.write("Rendering %s template files with "
    103                               "extensions: %s\n" %
    104                               (app_or_project, ', '.join(extensions)))
    105             self.stdout.write("Rendering %s template files with "
    106                               "filenames: %s\n" %
    107                               (app_or_project, ', '.join(extra_files)))
     102            self.info("Rendering %s template files with extensions: %s" %
     103                      (app_or_project, ', '.join(extensions)))
     104            self.info("Rendering %s template files with filenames: %s" %
     105                      (app_or_project, ', '.join(extra_files)))
    108106
    109107        base_name = '%s_name' % app_or_project
    110108        base_subdir = '%s_template' % app_or_project
    class TemplateCommand(BaseCommand):  
    161159                    new_file.write(content)
    162160
    163161                if self.verbosity >= 2:
    164                     self.stdout.write("Creating %s\n" % new_path)
     162                    self.info("Creating %s" % new_path)
    165163                try:
    166164                    shutil.copymode(old_path, new_path)
    167165                    self.make_writeable(new_path)
    class TemplateCommand(BaseCommand):  
    169167                    notice = self.style.NOTICE(
    170168                        "Notice: Couldn't set permission bits on %s. You're "
    171169                        "probably using an uncommon filesystem setup. No "
    172                         "problem.\n" % new_path)
    173                     sys.stderr.write(smart_str(notice))
     170                        "problem." % new_path)
     171                    self.error(notice)
    174172
    175173        if self.paths_to_remove:
    176174            if self.verbosity >= 2:
    177                 self.stdout.write("Cleaning up temporary files.\n")
     175                self.info("Cleaning up temporary files.")
    178176            for path_to_remove in self.paths_to_remove:
    179177                if path.isfile(path_to_remove):
    180178                    os.remove(path_to_remove)
    class TemplateCommand(BaseCommand):  
    227225        filename, display_url = cleanup_url(url)
    228226
    229227        if self.verbosity >= 2:
    230             self.stdout.write("Downloading %s\n" % display_url)
     228            self.info("Downloading %s" % display_url)
    231229        try:
    232230            the_path, info = urllib.urlretrieve(url,
    233231                                                path.join(tempdir, filename))
    class TemplateCommand(BaseCommand):  
    282280        tempdir = tempfile.mkdtemp(prefix=prefix, suffix='_extract')
    283281        self.paths_to_remove.append(tempdir)
    284282        if self.verbosity >= 2:
    285             self.stdout.write("Extracting %s\n" % filename)
     283            self.info("Extracting %s" % filename)
    286284        try:
    287285            archive.extract(filename, tempdir)
    288286            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 ba8765b..30c57e5 100644
    a b look like this:  
    6161                poll.opened = False
    6262                poll.save()
    6363
    64                 self.stdout.write('Successfully closed poll "%s"\n' % poll_id)
     64                self.info('Successfully closed poll "%s"' % poll_id)
    6565
    6666.. note::
    6767    When you are using management commands and wish to provide console
    68     output, you should write to ``self.stdout`` and ``self.stderr``,
    69     instead of printing to ``stdout`` and ``stderr`` directly. By
    70     using these proxies, it becomes much easier to test your custom
    71     command.
     68    output, you should use the :meth:`~BaseCommand.info` or
     69    :meth:`~BaseCommand.error` methods, instead of printing to ``stdout``
     70    and ``stderr`` directly. By using these proxies, it becomes much easier
     71    to test your custom command or redirect output when needed.
    7272
    7373The new custom command can be called using ``python manage.py closepoll
    7474<poll_id>``.
    the :meth:`~BaseCommand.handle` method must be implemented.  
    261261
    262262    The actual logic of the command. Subclasses must implement this method.
    263263
     264.. method:: BaseCommand.info(message)
     265
     266    Output a message on the console (stdout), unless the default
     267    'django.commands' logger has been customized.
     268
     269.. method:: BaseCommand.error(message)
     270
     271    Output an error message on the console (stderr), unless the default
     272    'django.commands' logger has been customized.
     273
    264274.. _ref-basecommand-subclasses:
    265275
    266276BaseCommand subclasses
  • docs/internals/deprecation.txt

    diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
    index f3ce5f8..7ddc368 100644
    a b these changes.  
    276276* The function ``django.utils.itercompat.product`` will be removed. The Python
    277277  builtin version should be used instead.
    278278
     279* The self.stdout and self.stderr attributes of management BaseCommand will be
     280  removed. They are replaced by the info() and error() methods, added in 1.5.
     281
    2792822.0
    280283---
    281284
  • docs/releases/1.4.txt

    diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
    index 51766dc..6425a03 100644
    a b Django 1.4 also includes several smaller improvements worth noting:  
    670670  useful in tests that don't need to hit a database. See
    671671  :ref:`testcase_hierarchy_diagram`.
    672672
     673
    673674Backwards incompatible changes in 1.4
    674675=====================================
    675676
  • docs/releases/1.5.txt

    diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
    index 5a92e7d..f86ad12 100644
    a b Django 1.5 also includes several smaller improvements worth noting:  
    4444* :mod:`django.utils.timezone` provides a helper for converting aware
    4545  datetimes between time zones. See :func:`~django.utils.timezone.localtime`.
    4646
     47* Management commands have now ``info()`` and ``error()`` methods for console
     48  output. Output directed to those methods can also be configured by customizing
     49  the 'django.commands' logger.
     50
    4751Backwards incompatible changes in 1.5
    4852=====================================
    4953
  • docs/topics/logging.txt

    diff --git a/docs/topics/logging.txt b/docs/topics/logging.txt
    index aa2afba..4ee2d9f 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 896dd66..c1e2bf9 100644
    a b class CommandTests(TestCase):  
    1111        out = StringIO()
    1212        management.call_command('dance', stdout=out)
    1313        self.assertEqual(out.getvalue(),
    14             "I don't feel like dancing Rock'n'Roll.")
     14            "I don't feel like dancing Rock'n'Roll.\n")
    1515
    1616    def test_command_style(self):
    1717        out = StringIO()
    1818        management.call_command('dance', style='Jive', stdout=out)
    1919        self.assertEqual(out.getvalue(),
    20             "I don't feel like dancing Jive.")
     20            "I don't feel like dancing Jive.\n")
    2121
    2222    def test_language_preserved(self):
    2323        out = StringIO()
  • tests/regressiontests/cache/tests.py

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

    diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py
    index ed8b404..5c1a70e 100644
    a b 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 1f38910..2cd02d5 100644
    a b  
    11import os
    2 try:
    3     from cStringIO import StringIO
    4 except ImportError:
    5     from StringIO import StringIO
     2from StringIO import StringIO
    63
    7 from django.core.management import CommandError
    8 from django.core.management.commands.compilemessages import compile_messages
     4from django.core.management import call_command, CommandError
    95from django.test import TestCase
    106from django.test.utils import override_settings
    117from django.utils import translation
    128
    139test_dir = os.path.abspath(os.path.dirname(__file__))
    1410
     11
    1512class MessageCompilationTests(TestCase):
    1613
    1714    def setUp(self):
    class PoFileTests(MessageCompilationTests):  
    2825
    2926    def test_bom_rejection(self):
    3027        os.chdir(test_dir)
    31         # We don't use the django.core.management infrastructure (call_command()
    32         # et al) because CommandError's cause exit(1) there. We test the
    33         # underlying compile_messages function instead
    3428        out = StringIO()
    35         self.assertRaises(CommandError, compile_messages, out, locale=self.LOCALE)
     29        self.assertRaises(CommandError, call_command, 'compilemessages',
     30                          locale=self.LOCALE, stdout=out, stderr=out)
    3631        self.assertFalse(os.path.exists(self.MO_FILE))
    3732
    3833
    class PoFileContentsTests(MessageCompilationTests):  
    4843
    4944    def test_percent_symbol_in_po_file(self):
    5045        os.chdir(test_dir)
    51         # We don't use the django.core.management infrastructure (call_command()
    52         # et al) because CommandError's cause exit(1) there. We test the
    53         # underlying compile_messages function instead
    54         out = StringIO()
    55         compile_messages(out, locale=self.LOCALE)
     46        call_command('compilemessages', locale=self.LOCALE, stdout=StringIO())
    5647        self.assertTrue(os.path.exists(self.MO_FILE))
    5748
    5849
    class PercentRenderingTests(MessageCompilationTests):  
    6758    def test_percent_symbol_escaping(self):
    6859        from django.template import Template, Context
    6960        os.chdir(test_dir)
    70         # We don't use the django.core.management infrastructure (call_command()
    71         # et al) because CommandError's cause exit(1) there. We test the
    72         # underlying compile_messages function instead
    73         out = StringIO()
    74         compile_messages(out, locale=self.LOCALE)
     61        call_command('compilemessages', locale=self.LOCALE, stdout=StringIO())
    7562        with translation.override(self.LOCALE):
    7663            t = Template('{% load i18n %}{% trans "Looks like a str fmt spec %% o but shouldn\'t be interpreted as such" %}')
    7764            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 7f30cb9..31a6c6f 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