-
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):
|
27 | 27 | except User.DoesNotExist: |
28 | 28 | raise CommandError("user '%s' does not exist" % username) |
29 | 29 | |
30 | | print "Changing password for user '%s'" % u.username |
| 30 | self.info("Changing password for user '%s'" % u.username) |
31 | 31 | |
32 | 32 | MAX_TRIES = 3 |
33 | 33 | count = 0 |
… |
… |
class Command(BaseCommand):
|
36 | 36 | p1 = self._get_pass() |
37 | 37 | p2 = self._get_pass("Password (again): ") |
38 | 38 | if p1 != p2: |
39 | | print "Passwords do not match. Please try again." |
| 39 | self.info("Passwords do not match. Please try again.") |
40 | 40 | count = count + 1 |
41 | 41 | |
42 | 42 | if count == MAX_TRIES: |
-
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):
|
73 | 73 | if default_username and username == '': |
74 | 74 | username = default_username |
75 | 75 | 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.") |
77 | 77 | username = None |
78 | 78 | continue |
79 | 79 | try: |
… |
… |
class Command(BaseCommand):
|
81 | 81 | except User.DoesNotExist: |
82 | 82 | break |
83 | 83 | else: |
84 | | sys.stderr.write("Error: That username is already taken.\n") |
| 84 | self.error("Error: That username is already taken.") |
85 | 85 | username = None |
86 | 86 | |
87 | 87 | # Get an email |
… |
… |
class Command(BaseCommand):
|
91 | 91 | try: |
92 | 92 | is_valid_email(email) |
93 | 93 | 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.") |
95 | 95 | email = None |
96 | 96 | else: |
97 | 97 | break |
… |
… |
class Command(BaseCommand):
|
102 | 102 | password = getpass.getpass() |
103 | 103 | password2 = getpass.getpass('Password (again): ') |
104 | 104 | if password != password2: |
105 | | sys.stderr.write("Error: Your passwords didn't match.\n") |
| 105 | self.error("Error: Your passwords didn't match.") |
106 | 106 | password = None |
107 | 107 | continue |
108 | 108 | if password.strip() == '': |
109 | | sys.stderr.write("Error: Blank passwords aren't allowed.\n") |
| 109 | self.error("Error: Blank passwords aren't allowed.") |
110 | 110 | password = None |
111 | 111 | continue |
112 | 112 | break |
113 | 113 | except KeyboardInterrupt: |
114 | | sys.stderr.write("\nOperation cancelled.\n") |
| 114 | self.error("\nOperation cancelled.") |
115 | 115 | sys.exit(1) |
116 | 116 | |
117 | 117 | User.objects.create_superuser(username, email, password) |
118 | 118 | if verbosity >= 1: |
119 | | self.stdout.write("Superuser created successfully.\n") |
120 | | |
| 119 | self.info("Superuser created successfully.") |
-
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: """
|
165 | 165 | |
166 | 166 | if self.verbosity >= 1: |
167 | 167 | 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.") |
169 | 169 | summary = template % { |
170 | 170 | 'modified_count': modified_count, |
171 | 171 | 'identifier': 'static file' + (modified_count != 1 and 's' or ''), |
… |
… |
Type 'yes' to continue, or 'no' to cancel: """
|
178 | 178 | ', %s post-processed' |
179 | 179 | % post_processed_count or ''), |
180 | 180 | } |
181 | | self.stdout.write(smart_str(summary)) |
| 181 | self.info(smart_str(summary)) |
182 | 182 | |
183 | 183 | def log(self, msg, level=2): |
184 | 184 | """ |
185 | 185 | Small log helper |
186 | 186 | """ |
187 | | msg = smart_str(msg) |
188 | | if not msg.endswith("\n"): |
189 | | msg += "\n" |
190 | 187 | if self.verbosity >= level: |
191 | | self.stdout.write(msg) |
| 188 | self.info(smart_str(msg)) |
192 | 189 | |
193 | 190 | def clear_dir(self, path): |
194 | 191 | """ |
-
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):
|
23 | 23 | result = [result] |
24 | 24 | output = u'\n '.join( |
25 | 25 | (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))) |
28 | 28 | else: |
29 | 29 | 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) |
-
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 8e83304..9dd72da 100644
a
|
b
|
import warnings
|
8 | 8 | from django.core.management.base import BaseCommand, CommandError, handle_default_options |
9 | 9 | from django.core.management.color import color_style |
10 | 10 | from django.utils.importlib import import_module |
| 11 | from django.utils.log import getLogger |
11 | 12 | |
12 | 13 | # For backwards compatibility: get_version() used to be in this module. |
13 | 14 | from django import get_version |
… |
… |
from django import get_version
|
15 | 16 | # A cache of loaded commands, so that call_command |
16 | 17 | # doesn't have to reload every time it's called. |
17 | 18 | _commands = None |
| 19 | logger = getLogger('django.commands') |
18 | 20 | |
19 | 21 | def find_commands(management_dir): |
20 | 22 | """ |
… |
… |
def call_command(name, *args, **options):
|
139 | 141 | # when the script runs from the command line, but since call_command can |
140 | 142 | # be called programatically, we need to simulate the loading and handling |
141 | 143 | # of defaults (see #10080 for details). |
142 | | defaults = {} |
| 144 | defaults = {'raise_on_error': True} |
143 | 145 | for opt in klass.option_list: |
144 | 146 | if opt.default is NO_DEFAULT: |
145 | 147 | defaults[opt.dest] = None |
… |
… |
def call_command(name, *args, **options):
|
149 | 151 | |
150 | 152 | return klass.execute(*args, **defaults) |
151 | 153 | |
| 154 | |
152 | 155 | class LaxOptionParser(OptionParser): |
153 | 156 | """ |
154 | 157 | An option parser that doesn't raise any errors on unknown options. |
… |
… |
class ManagementUtility(object):
|
251 | 254 | try: |
252 | 255 | app_name = get_commands()[subcommand] |
253 | 256 | 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." % \ |
255 | 258 | (subcommand, self.prog_name)) |
256 | 259 | sys.exit(1) |
257 | 260 | if isinstance(app_name, BaseCommand): |
… |
… |
class ManagementUtility(object):
|
363 | 366 | if subcommand == 'help': |
364 | 367 | if len(args) <= 2: |
365 | 368 | parser.print_lax_help() |
366 | | sys.stdout.write(self.main_help_text() + '\n') |
| 369 | logger.info(self.main_help_text()) |
367 | 370 | 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)) |
369 | 372 | else: |
370 | 373 | self.fetch_command(args[2]).print_help(self.prog_name, args[2]) |
371 | 374 | elif subcommand == 'version': |
372 | | sys.stdout.write(parser.get_version() + '\n') |
| 375 | logger.info(parser.get_version()) |
373 | 376 | # Special-cases: We want 'django-admin.py --version' and |
374 | 377 | # 'django-admin.py --help' to work, for backwards compatibility. |
375 | 378 | elif self.argv[1:] == ['--version']: |
… |
… |
class ManagementUtility(object):
|
377 | 380 | pass |
378 | 381 | elif self.argv[1:] in (['--help'], ['-h']): |
379 | 382 | parser.print_lax_help() |
380 | | sys.stdout.write(self.main_help_text() + '\n') |
| 383 | logger.info(self.main_help_text()) |
381 | 384 | else: |
382 | 385 | self.fetch_command(subcommand).run_from_argv(self.argv) |
383 | 386 | |
-
diff --git a/django/core/management/base.py b/django/core/management/base.py
index db855e1..d9bb9ce 100644
a
|
b
|
import sys
|
9 | 9 | |
10 | 10 | from optparse import make_option, OptionParser |
11 | 11 | import traceback |
| 12 | import warnings |
12 | 13 | |
13 | 14 | import django |
14 | 15 | from django.core.exceptions import ImproperlyConfigured |
15 | 16 | from django.core.management.color import color_style |
16 | 17 | from django.utils.encoding import smart_str |
| 18 | from django.utils.log import getLogger, setup_commands_logger |
17 | 19 | |
18 | 20 | |
19 | 21 | class CommandError(Exception): |
… |
… |
def handle_default_options(options):
|
45 | 47 | sys.path.insert(0, options.pythonpath) |
46 | 48 | |
47 | 49 | |
| 50 | class 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 | |
48 | 68 | class BaseCommand(object): |
49 | 69 | """ |
50 | 70 | The base class from which all management commands ultimately |
… |
… |
class BaseCommand(object):
|
142 | 162 | |
143 | 163 | def __init__(self): |
144 | 164 | self.style = color_style() |
| 165 | self._logger = getLogger('django.commands') |
145 | 166 | |
146 | 167 | def get_version(self): |
147 | 168 | """ |
… |
… |
class BaseCommand(object):
|
221 | 242 | if show_traceback: |
222 | 243 | traceback.print_exc() |
223 | 244 | else: |
224 | | sys.stderr.write(smart_str(self.style.ERROR('Error: %s\n' % e))) |
| 245 | self.error('Error: %s' % e) |
225 | 246 | sys.exit(1) |
226 | 247 | |
| 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) |
227 | 258 | try: |
228 | | self.stdout = options.get('stdout', sys.stdout) |
229 | | self.stderr = options.get('stderr', sys.stderr) |
230 | 259 | if self.requires_model_validation: |
231 | 260 | self.validate() |
232 | 261 | output = self.handle(*args, **options) |
… |
… |
class BaseCommand(object):
|
237 | 266 | from django.db import connections, DEFAULT_DB_ALIAS |
238 | 267 | connection = connections[options.get('database', DEFAULT_DB_ALIAS)] |
239 | 268 | 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) |
244 | 275 | except CommandError, e: |
245 | | if show_traceback: |
246 | | traceback.print_exc() |
| 276 | if options.get('raise_on_error', False): |
| 277 | raise |
247 | 278 | 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() |
250 | 288 | if saved_lang is not None: |
251 | 289 | translation.activate(saved_lang) |
252 | 290 | |
… |
… |
class BaseCommand(object):
|
269 | 307 | error_text = s.read() |
270 | 308 | raise CommandError("One or more models did not validate:\n%s" % error_text) |
271 | 309 | 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))) |
273 | 319 | |
274 | 320 | def handle(self, *args, **options): |
275 | 321 | """ |
-
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):
|
11 | 11 | sample.startswith(codecs.BOM_UTF16_LE) or \ |
12 | 12 | sample.startswith(codecs.BOM_UTF16_BE) |
13 | 13 | |
14 | | def compile_messages(stderr, locale=None): |
| 14 | def compile_messages(logger, locale=None): |
15 | 15 | basedirs = [os.path.join('conf', 'locale'), 'locale'] |
16 | 16 | if os.environ.get('DJANGO_SETTINGS_MODULE'): |
17 | 17 | from django.conf import settings |
… |
… |
def compile_messages(stderr, locale=None):
|
29 | 29 | for dirpath, dirnames, filenames in os.walk(basedir): |
30 | 30 | for f in filenames: |
31 | 31 | 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)) |
33 | 33 | fn = os.path.join(dirpath, f) |
34 | 34 | if has_bom(fn): |
35 | 35 | 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):
|
60 | 60 | |
61 | 61 | def handle(self, **options): |
62 | 62 | locale = options.get('locale') |
63 | | compile_messages(self.stderr, locale=locale) |
| 63 | compile_messages(self._logger, locale=locale) |
-
diff --git a/django/core/management/commands/createcachetable.py b/django/core/management/commands/createcachetable.py
index 08fa5f2..2a94b51 100644
a
|
b
|
|
1 | 1 | from optparse import make_option |
2 | 2 | |
3 | 3 | from django.core.cache.backends.db import BaseDatabaseCache |
4 | | from django.core.management.base import LabelCommand |
| 4 | from django.core.management.base import LabelCommand, CommandError |
5 | 5 | from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS |
6 | 6 | from django.db.utils import DatabaseError |
7 | 7 | |
… |
… |
class Command(LabelCommand):
|
55 | 55 | try: |
56 | 56 | curs.execute("\n".join(full_statement)) |
57 | 57 | 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))) |
61 | 58 | transaction.rollback_unless_managed(using=db) |
| 59 | raise CommandError("Cache table '%s' could not be created.\nThe error was: %s." % ( |
| 60 | tablename, e)) |
62 | 61 | else: |
63 | 62 | for statement in index_output: |
64 | 63 | curs.execute(statement) |
-
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):
|
28 | 28 | verbosity = int(options.get('verbosity')) |
29 | 29 | interactive = options.get('interactive') |
30 | 30 | |
31 | | self.style = no_style() |
32 | | |
33 | 31 | # Import the 'management' module within each installed app, to register |
34 | 32 | # dispatcher events. |
35 | 33 | for app_name in settings.INSTALLED_APPS: |
… |
… |
class Command(NoArgsCommand):
|
38 | 36 | except ImportError: |
39 | 37 | pass |
40 | 38 | |
41 | | sql_list = sql_flush(self.style, connection, only_django=True) |
| 39 | sql_list = sql_flush(no_style(), connection, only_django=True) |
42 | 40 | |
43 | 41 | if interactive: |
44 | 42 | confirm = raw_input("""You have requested a flush of the database. |
… |
… |
The full error: %s""" % (connection.settings_dict['NAME'], e))
|
82 | 80 | call_command('loaddata', 'initial_data', **kwargs) |
83 | 81 | |
84 | 82 | else: |
85 | | print "Flush cancelled." |
| 83 | return "Flush cancelled." |
-
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):
|
20 | 20 | def handle_noargs(self, **options): |
21 | 21 | try: |
22 | 22 | for line in self.handle_inspection(options): |
23 | | self.stdout.write("%s\n" % line) |
| 23 | self.info(line) |
24 | 24 | except NotImplementedError: |
25 | 25 | raise CommandError("Database inspection isn't supported for the currently selected database backend.") |
26 | 26 | |
-
diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
index 0c234fb..7824c8e 100644
a
|
b
|
import traceback
|
11 | 11 | |
12 | 12 | from django.conf import settings |
13 | 13 | from django.core import serializers |
14 | | from django.core.management.base import BaseCommand |
| 14 | from django.core.management.base import BaseCommand, CommandError |
15 | 15 | from django.core.management.color import no_style |
16 | 16 | from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS, |
17 | 17 | IntegrityError, DatabaseError) |
… |
… |
try:
|
24 | 24 | except ImportError: |
25 | 25 | has_bz2 = False |
26 | 26 | |
| 27 | |
27 | 28 | class Command(BaseCommand): |
28 | 29 | help = 'Installs the named fixture(s) in the database.' |
29 | 30 | args = "fixture [fixture ...]" |
… |
… |
class Command(BaseCommand):
|
38 | 39 | using = options.get('database') |
39 | 40 | |
40 | 41 | connection = connections[using] |
41 | | self.style = no_style() |
42 | 42 | |
43 | 43 | 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.") |
48 | 46 | |
49 | 47 | verbosity = int(options.get('verbosity')) |
50 | 48 | show_traceback = options.get('traceback') |
… |
… |
class Command(BaseCommand):
|
128 | 126 | |
129 | 127 | if formats: |
130 | 128 | if verbosity >= 2: |
131 | | self.stdout.write("Loading '%s' fixtures...\n" % fixture_name) |
| 129 | self.info("Loading '%s' fixtures..." % fixture_name) |
132 | 130 | 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)) |
140 | 133 | |
141 | 134 | if os.path.isabs(fixture_name): |
142 | 135 | fixture_dirs = [fixture_name] |
… |
… |
class Command(BaseCommand):
|
145 | 138 | |
146 | 139 | for fixture_dir in fixture_dirs: |
147 | 140 | 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)) |
149 | 142 | |
150 | 143 | label_found = False |
151 | 144 | for combo in product([using, None], formats, compression_formats): |
… |
… |
class Command(BaseCommand):
|
158 | 151 | ) |
159 | 152 | |
160 | 153 | 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)) |
163 | 156 | full_path = os.path.join(fixture_dir, file_name) |
164 | 157 | open_method = compression_types[compression_format] |
165 | 158 | try: |
166 | 159 | fixture = open_method(full_path, 'r') |
167 | 160 | except IOError: |
168 | 161 | 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))) |
171 | 164 | else: |
172 | 165 | try: |
173 | 166 | 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))) |
180 | 169 | |
181 | 170 | fixture_count += 1 |
182 | 171 | objects_in_fixture = 0 |
183 | 172 | loaded_objects_in_fixture = 0 |
184 | 173 | 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))) |
187 | 176 | |
188 | 177 | objects = serializers.deserialize(format, fixture, using=using) |
189 | 178 | |
… |
… |
class Command(BaseCommand):
|
212 | 201 | # If the fixture we loaded contains 0 objects, assume that an |
213 | 202 | # error was encountered during fixture loading. |
214 | 203 | 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)) |
222 | 206 | |
223 | 207 | # Since we disabled constraint checks, we must manually check for |
224 | 208 | # any invalid keys that might have been added |
… |
… |
class Command(BaseCommand):
|
227 | 211 | |
228 | 212 | except (SystemExit, KeyboardInterrupt): |
229 | 213 | raise |
| 214 | except CommandError: |
| 215 | if commit: |
| 216 | transaction.rollback(using=using) |
| 217 | transaction.leave_transaction_management(using=using) |
| 218 | raise |
230 | 219 | except Exception: |
231 | 220 | if commit: |
232 | 221 | transaction.rollback(using=using) |
… |
… |
class Command(BaseCommand):
|
234 | 223 | if show_traceback: |
235 | 224 | traceback.print_exc() |
236 | 225 | 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)))) |
241 | 229 | return |
242 | 230 | |
243 | 231 | |
244 | 232 | # If we found even one object in a fixture, we need to reset the |
245 | 233 | # database sequences. |
246 | 234 | 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) |
248 | 236 | if sequence_sql: |
249 | 237 | if verbosity >= 2: |
250 | | self.stdout.write("Resetting sequences\n") |
| 238 | self.info("Resetting sequences") |
251 | 239 | for line in sequence_sql: |
252 | 240 | cursor.execute(line) |
253 | 241 | |
… |
… |
class Command(BaseCommand):
|
257 | 245 | |
258 | 246 | if verbosity >= 1: |
259 | 247 | 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)" % ( |
261 | 249 | loaded_object_count, fixture_count)) |
262 | 250 | 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)" % ( |
264 | 252 | loaded_object_count, fixture_object_count, fixture_count)) |
265 | 253 | |
266 | 254 | # Close the DB connection. This is required as a workaround for an |
-
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):
|
46 | 46 | return p.communicate() |
47 | 47 | |
48 | 48 | def 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): |
50 | 50 | """ |
51 | 51 | A version of os.walk that can follow symlinks for Python < 2.6 |
52 | 52 | """ |
… |
… |
def walk(root, topdown=True, onerror=None, followlinks=False,
|
63 | 63 | for dirname in remove_dirs: |
64 | 64 | dirnames.remove(dirname) |
65 | 65 | if verbosity > 1: |
66 | | stdout.write('ignoring directory %s\n' % dirname) |
| 66 | logger.info('ignoring directory %s' % dirname) |
67 | 67 | yield (dirpath, dirnames, filenames) |
68 | 68 | if followlinks: |
69 | 69 | for d in dirnames: |
… |
… |
def is_ignored(path, ignore_patterns):
|
81 | 81 | return True |
82 | 82 | return False |
83 | 83 | |
84 | | def find_files(root, ignore_patterns, verbosity, stdout=sys.stdout, symlinks=False): |
| 84 | def find_files(root, ignore_patterns, verbosity, logger, symlinks=False): |
85 | 85 | """ |
86 | 86 | Helper function to get all files in the given root. |
87 | 87 | """ |
88 | 88 | all_files = [] |
89 | 89 | 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): |
91 | 91 | for filename in filenames: |
92 | 92 | norm_filepath = os.path.normpath(os.path.join(dirpath, filename)) |
93 | 93 | if is_ignored(norm_filepath, ignore_patterns): |
94 | 94 | if verbosity > 1: |
95 | | stdout.write('ignoring file %s in %s\n' % (filename, dirpath)) |
| 95 | logger.info('ignoring file %s in %s' % (filename, dirpath)) |
96 | 96 | else: |
97 | 97 | all_files.extend([(dirpath, filename)]) |
98 | 98 | all_files.sort() |
99 | 99 | return all_files |
100 | 100 | |
101 | | def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout): |
| 101 | def copy_plural_forms(msgs, locale, domain, verbosity, logger): |
102 | 102 | """ |
103 | 103 | Copies plural forms header contents from a Django catalog of locale to |
104 | 104 | the msgs string, inserting it at the right place. msgs should be the |
… |
… |
def copy_plural_forms(msgs, locale, domain, verbosity, stdout=sys.stdout):
|
115 | 115 | m = plural_forms_re.search(open(django_po, 'rU').read()) |
116 | 116 | if m: |
117 | 117 | if verbosity > 1: |
118 | | stdout.write("copying plural forms: %s\n" % m.group('value')) |
| 118 | logger.info("copying plural forms: %s" % m.group('value')) |
119 | 119 | lines = [] |
120 | 120 | seen = False |
121 | 121 | for line in msgs.split('\n'): |
… |
… |
def write_pot_file(potfile, msgs, file, work_file, is_templatized):
|
148 | 148 | f.close() |
149 | 149 | |
150 | 150 | def process_file(file, dirpath, potfile, domain, verbosity, |
151 | | extensions, wrap, location, stdout=sys.stdout): |
| 151 | extensions, wrap, location, logger): |
152 | 152 | """ |
153 | 153 | Extract translatable literals from :param file: for :param domain: |
154 | 154 | creating or updating the :param potfile: POT file. |
… |
… |
def process_file(file, dirpath, potfile, domain, verbosity,
|
159 | 159 | from django.utils.translation import templatize |
160 | 160 | |
161 | 161 | if verbosity > 1: |
162 | | stdout.write('processing file %s in %s\n' % (file, dirpath)) |
| 162 | logger.info('processing file %s in %s' % (file, dirpath)) |
163 | 163 | _, file_ext = os.path.splitext(file) |
164 | 164 | if domain == 'djangojs' and file_ext in extensions: |
165 | 165 | is_templatized = True |
… |
… |
def process_file(file, dirpath, potfile, domain, verbosity,
|
218 | 218 | if is_templatized: |
219 | 219 | os.unlink(work_file) |
220 | 220 | |
221 | | def write_po_file(pofile, potfile, domain, locale, verbosity, stdout, |
| 221 | def write_po_file(pofile, potfile, domain, locale, verbosity, logger, |
222 | 222 | copy_pforms, wrap, location, no_obsolete): |
223 | 223 | """ |
224 | 224 | Creates of updates the :param pofile: PO file for :param domain: and :param |
… |
… |
def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
|
244 | 244 | raise CommandError( |
245 | 245 | "errors happened while running msgmerge\n%s" % errors) |
246 | 246 | elif copy_pforms: |
247 | | msgs = copy_plural_forms(msgs, locale, domain, verbosity, stdout) |
| 247 | msgs = copy_plural_forms(msgs, locale, domain, verbosity, logger) |
248 | 248 | msgs = msgs.replace( |
249 | 249 | "#. #-#-#-#-# %s.pot (PACKAGE VERSION) #-#-#-#-#\n" % domain, "") |
250 | 250 | f = open(pofile, 'wb') |
… |
… |
def write_po_file(pofile, potfile, domain, locale, verbosity, stdout,
|
262 | 262 | |
263 | 263 | def make_messages(locale=None, domain='django', verbosity=1, all=False, |
264 | 264 | 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): |
266 | 266 | """ |
267 | 267 | Uses the ``locale/`` directory from the Django SVN tree or an |
268 | 268 | application/project to process all files with translatable literals for |
… |
… |
def make_messages(locale=None, domain='django', verbosity=1, all=False,
|
324 | 324 | |
325 | 325 | for locale in locales: |
326 | 326 | if verbosity > 0: |
327 | | stdout.write("processing language %s" % locale) |
| 327 | logger.info("processing language %s" % locale) |
328 | 328 | basedir = os.path.join(localedir, locale, 'LC_MESSAGES') |
329 | 329 | if not os.path.isdir(basedir): |
330 | 330 | os.makedirs(basedir) |
… |
… |
def make_messages(locale=None, domain='django', verbosity=1, all=False,
|
336 | 336 | os.unlink(potfile) |
337 | 337 | |
338 | 338 | for dirpath, file in find_files(".", ignore_patterns, verbosity, |
339 | | stdout, symlinks=symlinks): |
| 339 | logger, symlinks=symlinks): |
340 | 340 | process_file(file, dirpath, potfile, domain, verbosity, extensions, |
341 | | wrap, location, stdout) |
| 341 | wrap, location, logger) |
342 | 342 | |
343 | 343 | 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, |
345 | 345 | not invoked_for_django, wrap, location, no_obsolete) |
346 | 346 | |
347 | 347 | |
… |
… |
class Command(NoArgsCommand):
|
399 | 399 | extensions = handle_extensions(exts) |
400 | 400 | |
401 | 401 | 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')) |
404 | 404 | |
405 | 405 | 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) |
-
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
|
59 | 59 | The full error: %s""" % (app_name, app_name, e)) |
60 | 60 | transaction.commit_unless_managed() |
61 | 61 | else: |
62 | | print "Reset cancelled." |
| 62 | return "Reset cancelled." |
-
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):
|
87 | 87 | shutdown_message = options.get('shutdown_message', '') |
88 | 88 | quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' |
89 | 89 | |
90 | | self.stdout.write("Validating models...\n\n") |
| 90 | self.info("Validating models...\n") |
91 | 91 | self.validate(display_num_errors=True) |
92 | | self.stdout.write(( |
| 92 | self.info( |
93 | 93 | "Django version %(version)s, using settings %(settings)r\n" |
94 | 94 | "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 | ) |
103 | 103 | # django.core.management.base forces the locale to en-us. We should |
104 | 104 | # set it up correctly for the first request (particularly important |
105 | 105 | # in the "--noreload" case). |
… |
… |
class BaseRunserverCommand(BaseCommand):
|
120 | 120 | error_text = ERRORS[e.args[0].args[0]] |
121 | 121 | except (AttributeError, KeyError): |
122 | 122 | error_text = str(e) |
123 | | sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n') |
| 123 | self.error("Error: %s" % error_text) |
124 | 124 | # Need to use an OS exit because sys.exit doesn't work in a thread |
125 | 125 | os._exit(1) |
126 | 126 | except KeyboardInterrupt: |
127 | 127 | if shutdown_message: |
128 | | self.stdout.write("%s\n" % shutdown_message) |
| 128 | self.info(shutdown_message) |
129 | 129 | sys.exit(0) |
130 | 130 | |
131 | 131 | class Command(BaseRunserverCommand): |
-
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):
|
82 | 82 | |
83 | 83 | # Create the tables for each model |
84 | 84 | if verbosity >= 1: |
85 | | print "Creating tables ..." |
| 85 | self.info("Creating tables ...") |
86 | 86 | for app_name, model_list in manifest.items(): |
87 | 87 | for model in model_list: |
88 | 88 | # Create the model's database table, if it doesn't already exist. |
89 | 89 | 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)) |
91 | 91 | sql, references = connection.creation.sql_create_model(model, self.style, seen_models) |
92 | 92 | seen_models.add(model) |
93 | 93 | created_models.add(model) |
… |
… |
class Command(NoArgsCommand):
|
97 | 97 | sql.extend(connection.creation.sql_for_pending_references(refto, self.style, pending_references)) |
98 | 98 | sql.extend(connection.creation.sql_for_pending_references(model, self.style, pending_references)) |
99 | 99 | if verbosity >= 1 and sql: |
100 | | print "Creating table %s" % model._meta.db_table |
| 100 | self.info("Creating table %s" % model._meta.db_table) |
101 | 101 | for statement in sql: |
102 | 102 | cursor.execute(statement) |
103 | 103 | tables.append(connection.introspection.table_name_converter(model._meta.db_table)) |
… |
… |
class Command(NoArgsCommand):
|
115 | 115 | # Install custom SQL for the app (but only if this |
116 | 116 | # is a model we've just created) |
117 | 117 | if verbosity >= 1: |
118 | | print "Installing custom SQL ..." |
| 118 | self.info("Installing custom SQL ...") |
119 | 119 | for app_name, model_list in manifest.items(): |
120 | 120 | for model in model_list: |
121 | 121 | if model in created_models: |
122 | 122 | custom_sql = custom_sql_for_model(model, self.style, connection) |
123 | 123 | if custom_sql: |
124 | 124 | 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)) |
126 | 127 | try: |
127 | 128 | for sql in custom_sql: |
128 | 129 | cursor.execute(sql) |
129 | 130 | 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)) |
132 | 133 | if show_traceback: |
133 | 134 | traceback.print_exc() |
134 | 135 | transaction.rollback_unless_managed(using=db) |
… |
… |
class Command(NoArgsCommand):
|
136 | 137 | transaction.commit_unless_managed(using=db) |
137 | 138 | else: |
138 | 139 | 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)) |
140 | 142 | |
141 | 143 | if verbosity >= 1: |
142 | | print "Installing indexes ..." |
| 144 | self.info("Installing indexes ...") |
143 | 145 | # Install SQL indices for all newly created models |
144 | 146 | for app_name, model_list in manifest.items(): |
145 | 147 | for model in model_list: |
… |
… |
class Command(NoArgsCommand):
|
147 | 149 | index_sql = connection.creation.sql_indexes_for_model(model, self.style) |
148 | 150 | if index_sql: |
149 | 151 | 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)) |
151 | 154 | try: |
152 | 155 | for sql in index_sql: |
153 | 156 | cursor.execute(sql) |
154 | 157 | 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)) |
157 | 160 | transaction.rollback_unless_managed(using=db) |
158 | 161 | else: |
159 | 162 | transaction.commit_unless_managed(using=db) |
-
diff --git a/django/core/management/templates.py b/django/core/management/templates.py
index 1d26e97..196f65e 100644
a
|
b
|
class TemplateCommand(BaseCommand):
|
98 | 98 | for file in options.get('files'): |
99 | 99 | extra_files.extend(map(lambda x: x.strip(), file.split(','))) |
100 | 100 | 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))) |
107 | 105 | |
108 | 106 | base_name = '%s_name' % app_or_project |
109 | 107 | base_subdir = '%s_template' % app_or_project |
… |
… |
class TemplateCommand(BaseCommand):
|
160 | 158 | new_file.write(content) |
161 | 159 | |
162 | 160 | if self.verbosity >= 2: |
163 | | self.stdout.write("Creating %s\n" % new_path) |
| 161 | self.info("Creating %s" % new_path) |
164 | 162 | try: |
165 | 163 | shutil.copymode(old_path, new_path) |
166 | 164 | self.make_writeable(new_path) |
… |
… |
class TemplateCommand(BaseCommand):
|
168 | 166 | notice = self.style.NOTICE( |
169 | 167 | "Notice: Couldn't set permission bits on %s. You're " |
170 | 168 | "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) |
173 | 171 | |
174 | 172 | if self.paths_to_remove: |
175 | 173 | if self.verbosity >= 2: |
176 | | self.stdout.write("Cleaning up temporary files.\n") |
| 174 | self.info("Cleaning up temporary files.") |
177 | 175 | for path_to_remove in self.paths_to_remove: |
178 | 176 | if path.isfile(path_to_remove): |
179 | 177 | os.remove(path_to_remove) |
… |
… |
class TemplateCommand(BaseCommand):
|
226 | 224 | filename, display_url = cleanup_url(url) |
227 | 225 | |
228 | 226 | if self.verbosity >= 2: |
229 | | self.stdout.write("Downloading %s\n" % display_url) |
| 227 | self.info("Downloading %s" % display_url) |
230 | 228 | try: |
231 | 229 | the_path, info = urllib.urlretrieve(url, |
232 | 230 | path.join(tempdir, filename)) |
… |
… |
class TemplateCommand(BaseCommand):
|
281 | 279 | tempdir = tempfile.mkdtemp(prefix=prefix, suffix='_extract') |
282 | 280 | self.paths_to_remove.append(tempdir) |
283 | 281 | if self.verbosity >= 2: |
284 | | self.stdout.write("Extracting %s\n" % filename) |
| 282 | self.info("Extracting %s" % filename) |
285 | 283 | try: |
286 | 284 | archive.extract(filename, tempdir) |
287 | 285 | return tempdir |
-
diff --git a/django/utils/log.py b/django/utils/log.py
index df2089f..6ffa871 100644
a
|
b
|
|
1 | 1 | import logging |
| 2 | import sys |
2 | 3 | import traceback |
3 | 4 | |
4 | 5 | from django.conf import settings |
… |
… |
try:
|
21 | 22 | except ImportError: |
22 | 23 | from django.utils.dictconfig import dictConfig |
23 | 24 | |
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 | | |
33 | 25 | |
34 | 26 | class AdminEmailHandler(logging.Handler): |
35 | 27 | """An exception log handler that emails log entries to site admins. |
… |
… |
class CallbackFilter(logging.Filter):
|
103 | 95 | class RequireDebugFalse(logging.Filter): |
104 | 96 | def filter(self, record): |
105 | 97 | return not settings.DEBUG |
| 98 | |
| 99 | |
| 100 | class 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 | |
| 112 | def 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 | |
| 125 | getLogger = 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 |
| 130 | logger = getLogger('django') |
| 131 | if not logger.handlers: |
| 132 | logger.addHandler(NullHandler()) |
| 133 | |
| 134 | setup_commands_logger('django.commands', sys.stdout, sys.stderr) |
-
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:
|
62 | 62 | poll.opened = False |
63 | 63 | poll.save() |
64 | 64 | |
65 | | self.stdout.write('Successfully closed poll "%s"\n' % poll_id) |
| 65 | self.info('Successfully closed poll "%s"' % poll_id) |
66 | 66 | |
67 | 67 | .. note:: |
68 | 68 | 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. |
73 | 73 | |
74 | 74 | The new custom command can be called using ``python manage.py closepoll |
75 | 75 | <poll_id>``. |
… |
… |
the :meth:`~BaseCommand.handle` method must be implemented.
|
248 | 248 | |
249 | 249 | The actual logic of the command. Subclasses must implement this method. |
250 | 250 | |
| 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 | |
251 | 261 | .. _ref-basecommand-subclasses: |
252 | 262 | |
253 | 263 | BaseCommand subclasses |
-
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 16dbec8..9bac6e0 100644
a
|
b
|
these changes.
|
267 | 267 | in 1.4. The backward compatibility will be removed -- |
268 | 268 | ``HttpRequest.raw_post_data`` will no longer work. |
269 | 269 | |
| 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 | |
270 | 273 | 2.0 |
271 | 274 | --- |
272 | 275 | |
-
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:
|
599 | 599 | |
600 | 600 | .. _django/views/debug.py: http://code.djangoproject.com/browser/django/trunk/django/views/debug.py |
601 | 601 | |
| 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 | |
602 | 606 | |
603 | 607 | Backwards incompatible changes in 1.4 |
604 | 608 | ===================================== |
-
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:
|
608 | 608 | :attr:`Sitemap.protocol <django.contrib.sitemaps.Sitemap.protocol>` class |
609 | 609 | attribute. |
610 | 610 | |
| 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 | |
611 | 616 | Backwards incompatible changes in 1.4 |
612 | 617 | ===================================== |
613 | 618 | |
-
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
|
455 | 455 | ``settings.DEBUG`` is set to ``True``, regardless of the logging |
456 | 456 | level or handlers that are installed. |
457 | 457 | |
| 458 | ``django.commands`` |
| 459 | ~~~~~~~~~~~~~~~~~~~ |
| 460 | |
| 461 | Messages related to management commands. By default, this logger outputs |
| 462 | message on standard output (console). |
| 463 | |
458 | 464 | Handlers |
459 | 465 | -------- |
460 | 466 | |
-
diff --git a/tests/modeltests/fixtures/tests.py b/tests/modeltests/fixtures/tests.py
index d22010d..7174cea 100644
a
|
b
|
class FixtureLoadingTests(TestCase):
|
185 | 185 | exclude_list=['fixtures.Article', 'fixtures.Book', 'sites']) |
186 | 186 | |
187 | 187 | # 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']) |
193 | 191 | |
194 | 192 | # 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']) |
200 | 196 | |
201 | 197 | def test_dumpdata_with_filtering_manager(self): |
202 | 198 | spy1 = Spy.objects.create(name='Paul') |
… |
… |
class FixtureLoadingTests(TestCase):
|
233 | 229 | def test_ambiguous_compressed_fixture(self): |
234 | 230 | # The name "fixture5" is ambigous, so loading it will raise an error |
235 | 231 | 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) |
240 | 236 | |
241 | 237 | def test_db_loading(self): |
242 | 238 | # Load db fixtures 1 and 2. These will load using the 'default' database identifier implicitly |
… |
… |
class FixtureLoadingTests(TestCase):
|
261 | 257 | new_io = StringIO.StringIO() |
262 | 258 | management.call_command('loaddata', 'invalid.json', verbosity=0, stderr=new_io, commit=False) |
263 | 259 | 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:])) |
265 | 262 | |
266 | 263 | def test_loading_using(self): |
267 | 264 | # Load db fixtures 1 and 2. These will load using the 'default' database identifier explicitly |
… |
… |
class FixtureTransactionTests(TransactionTestCase):
|
317 | 314 | # Try to load fixture 2 using format discovery; this will fail |
318 | 315 | # because there are two fixture2's in the fixtures directory |
319 | 316 | 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) |
324 | 320 | |
325 | 321 | # object list is unaffected |
326 | 322 | self.assertQuerysetEqual(Article.objects.all(), [ |
-
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):
|
15 | 15 | |
16 | 16 | def handle(self, *args, **options): |
17 | 17 | 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"]) |
-
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):
|
13 | 13 | out = StringIO() |
14 | 14 | management.call_command('dance', stdout=out) |
15 | 15 | 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") |
17 | 17 | |
18 | 18 | def test_command_style(self): |
19 | 19 | out = StringIO() |
20 | 20 | management.call_command('dance', style='Jive', stdout=out) |
21 | 21 | self.assertEqual(out.getvalue(), |
22 | | "I don't feel like dancing Jive.") |
| 22 | "I don't feel like dancing Jive.\n") |
23 | 23 | |
24 | 24 | def test_language_preserved(self): |
25 | 25 | out = StringIO() |
-
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py
index bd29cde..3c6280d 100644
a
|
b
|
class DBCacheTests(BaseCacheTests, TransactionTestCase):
|
819 | 819 | self.perform_cull_test(50, 18) |
820 | 820 | |
821 | 821 | 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 | ) |
825 | 830 | |
826 | 831 | |
827 | 832 | DBCacheWithTimeZoneTests = override_settings(USE_TZ=True)(DBCacheTests) |
-
diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py
index ed8b404..305b349 100644
a
|
b
|
|
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 | # Unittests for fixtures. |
3 | | from __future__ import absolute_import |
| 3 | from __future__ import absolute_import, with_statement |
4 | 4 | |
5 | 5 | import os |
6 | 6 | import re |
… |
… |
class TestFixtures(TestCase):
|
119 | 119 | Test for ticket #4371 -- Loading data of an unknown format should fail |
120 | 120 | Validate that error conditions are caught correctly |
121 | 121 | """ |
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 | ) |
134 | 130 | |
135 | 131 | def test_invalid_data(self): |
136 | 132 | """ |
… |
… |
class TestFixtures(TestCase):
|
138 | 134 | using explicit filename. |
139 | 135 | Validate that error conditions are caught correctly |
140 | 136 | """ |
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 | ) |
153 | 145 | |
154 | 146 | def test_invalid_data_no_ext(self): |
155 | 147 | """ |
… |
… |
class TestFixtures(TestCase):
|
157 | 149 | without file extension. |
158 | 150 | Validate that error conditions are caught correctly |
159 | 151 | """ |
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 | ) |
172 | 160 | |
173 | 161 | def test_empty(self): |
174 | 162 | """ |
175 | 163 | Test for ticket #4371 -- Loading a fixture file with no data returns an error. |
176 | 164 | Validate that error conditions are caught correctly |
177 | 165 | """ |
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 | ) |
209 | 174 | |
210 | 175 | def test_error_message(self): |
211 | 176 | """ |
212 | 177 | (Regression for #9011 - error message is correct) |
213 | 178 | """ |
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 | ) |
227 | 188 | |
228 | 189 | def test_pg_sequence_resetting_checks(self): |
229 | 190 | """ |
… |
… |
class TestFixtures(TestCase):
|
337 | 298 | platypus_json = '{"pk": %d, "model": "fixtures_regress.animal", "fields": {"count": 2, "weight": 2.2, "name": "Platypus", "latin_name": "Ornithorhynchus anatinus"}}' |
338 | 299 | platypus_json = platypus_json % animal.pk |
339 | 300 | |
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]))) |
341 | 303 | self.assertTrue(lion_json in data) |
342 | 304 | self.assertTrue(emu_json in data) |
343 | 305 | self.assertTrue(platypus_json in data) |
… |
… |
class TestFixtures(TestCase):
|
358 | 320 | ) |
359 | 321 | self.assertEqual( |
360 | 322 | stdout.getvalue(), |
361 | | """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]""" |
| 323 | """[{"pk": %d, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]\n""" |
362 | 324 | % widget.pk |
363 | 325 | ) |
364 | 326 | |
… |
… |
class TestFixtures(TestCase):
|
387 | 349 | commit=False, |
388 | 350 | stderr=stderr, |
389 | 351 | ) |
390 | | self.assertTrue( |
391 | | stderr.getvalue().startswith('Problem installing fixture') |
392 | | ) |
| 352 | self.assertIn('Problem installing fixture', stderr.getvalue()) |
393 | 353 | |
394 | 354 | _cur_dir = os.path.dirname(os.path.abspath(__file__)) |
395 | 355 | |
… |
… |
class TestFixtures(TestCase):
|
414 | 374 | """ |
415 | 375 | Regression for #7043 - Error is quickly reported when no fixtures is provided in the command line. |
416 | 376 | """ |
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 | ) |
427 | 385 | |
428 | 386 | def test_loaddata_not_existant_fixture_file(self): |
429 | 387 | stdout_output = StringIO() |
… |
… |
class NaturalKeyFixtureTests(TestCase):
|
524 | 482 | ) |
525 | 483 | self.assertEqual( |
526 | 484 | 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""" |
528 | 486 | ) |
529 | 487 | |
530 | 488 | def test_dependency_sorting(self): |
-
diff --git a/tests/regressiontests/i18n/commands/compilation.py b/tests/regressiontests/i18n/commands/compilation.py
index ee558b2..0731b18 100644
a
|
b
|
|
1 | 1 | from __future__ import with_statement |
2 | 2 | |
3 | 3 | import os |
4 | | try: |
5 | | from cStringIO import StringIO |
6 | | except ImportError: |
7 | | from StringIO import StringIO |
| 4 | from StringIO import StringIO |
8 | 5 | |
9 | | from django.core.management import CommandError |
10 | | from django.core.management.commands.compilemessages import compile_messages |
| 6 | from django.core.management import call_command, CommandError |
11 | 7 | from django.test import TestCase |
12 | 8 | from django.test.utils import override_settings |
13 | 9 | from django.utils import translation |
14 | 10 | |
15 | 11 | test_dir = os.path.abspath(os.path.dirname(__file__)) |
16 | 12 | |
| 13 | |
17 | 14 | class MessageCompilationTests(TestCase): |
18 | 15 | |
19 | 16 | def setUp(self): |
… |
… |
class PoFileTests(MessageCompilationTests):
|
30 | 27 | |
31 | 28 | def test_bom_rejection(self): |
32 | 29 | 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 |
36 | 30 | 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) |
38 | 33 | self.assertFalse(os.path.exists(self.MO_FILE)) |
39 | 34 | |
40 | 35 | |
… |
… |
class PoFileContentsTests(MessageCompilationTests):
|
50 | 45 | |
51 | 46 | def test_percent_symbol_in_po_file(self): |
52 | 47 | 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()) |
58 | 49 | self.assertTrue(os.path.exists(self.MO_FILE)) |
59 | 50 | |
60 | 51 | |
… |
… |
class PercentRenderingTests(MessageCompilationTests):
|
69 | 60 | def test_percent_symbol_escaping(self): |
70 | 61 | from django.template import Template, Context |
71 | 62 | 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()) |
77 | 64 | with translation.override(self.LOCALE): |
78 | 65 | t = Template('{% load i18n %}{% trans "Looks like a str fmt spec %% o but shouldn\'t be interpreted as such" %}') |
79 | 66 | rendered = t.render(Context({})) |
-
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):
|
187 | 187 | Test ``findstatic`` management command. |
188 | 188 | """ |
189 | 189 | 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() |
200 | 195 | return contents |
201 | 196 | |
202 | 197 | def test_all_files(self): |
203 | 198 | """ |
204 | 199 | Test that findstatic returns all candidate files if run without --first. |
205 | 200 | """ |
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 != ''] |
214 | 204 | self.assertEqual(len(lines), 3) # three because there is also the "Found <file> here" line |
215 | 205 | self.assertIn('project', lines[1]) |
216 | 206 | self.assertIn('apps', lines[2]) |