Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: django/django
...
head fork: claudep/django
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 12 files changed
  • 0 commit comments
  • 1 contributor
View
105 django/core/management/base.py
@@ -75,6 +75,28 @@ def handle_default_options(options):
sys.path.insert(0, options.pythonpath)
+def run_as_locale(locale):
+ """
+ Decorator to force a command to run with a specific locale activated.
+ """
+ def inner(handle_func):
+ def wrapped(*args, **kwargs):
+ from django.utils import translation
+ saved_locale = translation.get_language()
+ if locale != saved_locale:
+ translation.activate(locale)
+ else:
+ saved_locale = None
+ try:
+ res = handle_func(*args, **kwargs)
+ finally:
+ if saved_locale is not None:
+ translation.activate(saved_locale)
+ return res
+ return wrapped
+ return inner
+
+
class OutputWrapper(object):
"""
Wrapper around stdout/stderr
@@ -145,12 +167,6 @@ class BaseCommand(object):
a list of application names might set this to '<app_label
app_label ...>'.
- ``can_import_settings``
- A boolean indicating whether the command needs to be able to
- import Django settings; if ``True``, ``execute()`` will verify
- that this is possible before proceeding. Default value is
- ``True``.
-
``help``
A short description of the command, which will be printed in
help messages.
@@ -186,24 +202,6 @@ class BaseCommand(object):
rather than all applications' models, call
``self.validate(app_config)`` from ``handle()``, where ``app_config``
is the application's configuration provided by the app registry.
-
- ``leave_locale_alone``
- A boolean indicating whether the locale set in settings should be
- preserved during the execution of the command instead of being
- forcibly set to 'en-us'.
-
- Default value is ``False``.
-
- Make sure you know what you are doing if you decide to change the value
- of this option in your custom command if it creates database content
- that is locale-sensitive and such content shouldn't contain any
- translations (like it happens e.g. with django.contrim.auth
- permissions) as making the locale differ from the de facto default
- 'en-us' might cause unintended effects.
-
- This option can't be False when the can_import_settings option is set
- to False too because attempting to set the locale needs access to
- settings. This condition will generate a CommandError.
"""
# Metadata about this command.
option_list = ()
@@ -212,9 +210,7 @@ class BaseCommand(object):
# Configuration shortcuts that alter various logic.
_called_from_command_line = False
- can_import_settings = True
output_transaction = False # Whether to wrap the output in a "BEGIN; COMMIT;"
- leave_locale_alone = False
# Uncomment the following line of code after deprecation plan for
# requires_model_validation comes to completion:
@@ -383,47 +379,22 @@ def execute(self, *args, **options):
else:
self.stderr = OutputWrapper(options.get('stderr', sys.stderr), self.style.ERROR)
- if self.can_import_settings:
- from django.conf import settings # NOQA
-
- saved_locale = None
- if not self.leave_locale_alone:
- # Only mess with locales if we can assume we have a working
- # settings file, because django.utils.translation requires settings
- # (The final saying about whether the i18n machinery is active will be
- # found in the value of the USE_I18N setting)
- if not self.can_import_settings:
- raise CommandError("Incompatible values of 'leave_locale_alone' "
- "(%s) and 'can_import_settings' (%s) command "
- "options." % (self.leave_locale_alone,
- self.can_import_settings))
- # Switch to US English, because django-admin.py creates database
- # content like permissions, and those shouldn't contain any
- # translations.
- from django.utils import translation
- saved_locale = translation.get_language()
- translation.activate('en-us')
-
- try:
- if (self.requires_system_checks and
- not options.get('skip_validation') and # This will be removed at the end of deprecation process for `skip_validation`.
- not options.get('skip_checks')):
- self.check()
- output = self.handle(*args, **options)
- if output:
- if self.output_transaction:
- # This needs to be imported here, because it relies on
- # settings.
- from django.db import connections, DEFAULT_DB_ALIAS
- connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
- if connection.ops.start_transaction_sql():
- self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()))
- self.stdout.write(output)
- if self.output_transaction:
- self.stdout.write('\n' + self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()))
- finally:
- if saved_locale is not None:
- translation.activate(saved_locale)
+ if (self.requires_system_checks and
+ not options.get('skip_validation') and # This will be removed at the end of deprecation process for `skip_validation`.
+ not options.get('skip_checks')):
+ self.check()
+ output = self.handle(*args, **options)
+ if output:
+ if self.output_transaction:
+ # This needs to be imported here, because it relies on
+ # settings.
+ from django.db import connections, DEFAULT_DB_ALIAS
+ connection = connections[options.get('database', DEFAULT_DB_ALIAS)]
+ if connection.ops.start_transaction_sql():
+ self.stdout.write(self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()))
+ self.stdout.write(output)
+ if self.output_transaction:
+ self.stdout.write('\n' + self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()))
def validate(self, app_config=None, display_num_errors=False):
""" Deprecated. Delegates to ``check``."""
View
1  django/core/management/commands/compilemessages.py
@@ -32,7 +32,6 @@ class Command(BaseCommand):
help = 'Compiles .po files to .mo files for use with builtin gettext support.'
requires_system_checks = False
- leave_locale_alone = True
program = 'msgfmt'
program_options = ['--check-format']
View
1  django/core/management/commands/makemessages.py
@@ -170,7 +170,6 @@ class Command(BaseCommand):
"--locale, --exclude or --all options.")
requires_system_checks = False
- leave_locale_alone = True
msgmerge_options = ['-q', '--previous']
msguniq_options = ['--to-code=utf-8']
View
3  django/core/management/commands/migrate.py
@@ -8,7 +8,7 @@
from django.apps import apps
from django.core.management import call_command
-from django.core.management.base import BaseCommand, CommandError
+from django.core.management.base import BaseCommand, CommandError, run_as_locale
from django.core.management.color import no_style
from django.core.management.sql import custom_sql_for_model, emit_post_migrate_signal, emit_pre_migrate_signal
from django.db import connections, router, transaction, DEFAULT_DB_ALIAS
@@ -39,6 +39,7 @@ def add_arguments(self, parser):
parser.add_argument('--list', '-l', action='store_true', dest='list', default=False,
help='Show a list of all known migrations and which are applied')
+ @run_as_locale('en-us')
def handle(self, *args, **options):
self.verbosity = options.get('verbosity')
View
3  django/core/management/commands/syncdb.py
@@ -4,7 +4,7 @@
from django.contrib.auth import get_user_model
from django.db import DEFAULT_DB_ALIAS
from django.core.management import call_command
-from django.core.management.base import BaseCommand
+from django.core.management.base import BaseCommand, run_as_locale
from django.utils.deprecation import RemovedInDjango19Warning
from django.utils.six.moves import input
@@ -20,6 +20,7 @@ def add_arguments(self, parser):
parser.add_argument('--database', default=DEFAULT_DB_ALIAS,
help='Nominates a database to synchronize. Defaults to the "default" database.')
+ @run_as_locale('en-us')
def handle(self, **options):
warnings.warn("The syncdb command will be removed in Django 1.9", RemovedInDjango19Warning)
call_command("migrate", **options)
View
6 django/core/management/templates.py
@@ -36,14 +36,8 @@ class TemplateCommand(BaseCommand):
:param options: The additional variables passed to project or app templates
"""
requires_system_checks = False
- # Can't import settings during this command, because they haven't
- # necessarily been created.
- can_import_settings = False
# The supported URL schemes
url_schemes = ['http', 'https', 'ftp']
- # Can't perform any active locale changes during this command, because
- # setting might not be available at all.
- leave_locale_alone = True
def add_arguments(self, parser):
parser.add_argument('name', help='Name of the application or project.')
View
76 docs/howto/custom-management-commands.txt
@@ -145,56 +145,29 @@ default options such as :djadminopt:`--verbosity` and :djadminopt:`--traceback`.
Management commands and locales
===============================
-By default, the :meth:`BaseCommand.execute` method sets the hardcoded 'en-us'
-locale because some commands shipped with Django perform several tasks
-(for example, user-facing content rendering and database population) that
-require a system-neutral string language (for which we use 'en-us').
+By default, management commands are executed with the current active locale.
If, for some reason, your custom management command needs to use a fixed locale
-different from 'en-us', you should manually activate and deactivate it in your
-:meth:`~BaseCommand.handle` method using the functions provided by the I18N
-support code:
+(for example 'en-us' to force untranslated content in the database) you can
+force a specific locale by using the ``run_as_locale`` decorator around your
+:meth:`~BaseCommand.handle` method. You should also ensure that settings can be
+imported, as changing the language will require functional settings.
.. code-block:: python
- from django.core.management.base import BaseCommand, CommandError
- from django.utils import translation
+ from django.core.management.base import BaseCommand, CommandError, run_as_locale
class Command(BaseCommand):
...
- can_import_settings = True
+ @run_as_locale('ru')
def handle(self, *args, **options):
+ ...
- # Activate a fixed locale, e.g. Russian
- translation.activate('ru')
-
- # Or you can activate the LANGUAGE_CODE # chosen in the settings:
- #
- #from django.conf import settings
- #translation.activate(settings.LANGUAGE_CODE)
-
- # Your command logic here
- # ...
-
- translation.deactivate()
-
-Another need might be that your command simply should use the locale set in
-settings and Django should be kept from forcing it to 'en-us'. You can achieve
-it by using the :data:`BaseCommand.leave_locale_alone` option.
-
-When working on the scenarios described above though, take into account that
-system management commands typically have to be very careful about running in
-non-uniform locales, so you might need to:
+.. versionchanged: 1.8
-* Make sure the :setting:`USE_I18N` setting is always ``True`` when running
- the command (this is a good example of the potential problems stemming
- from a dynamic runtime environment that Django commands avoid offhand by
- always using a fixed locale).
-
-* Review the code of your command and the code it calls for behavioral
- differences when locales are changed and evaluate its impact on
- predictable behavior of your command.
+ On previous versions, Django used to force the 'en-us' locale before running
+ any command.
Command objects
===============
@@ -230,13 +203,6 @@ All attributes can be set in your derived class and can be used in
method, by calling the ``parser.add_argument()`` method. See the
``closepoll`` example above.
-.. attribute:: BaseCommand.can_import_settings
-
- A boolean indicating whether the command needs to be able to
- import Django settings; if ``True``, ``execute()`` will verify
- that this is possible before proceeding. Default value is
- ``True``.
-
.. attribute:: BaseCommand.help
A short description of the command, which will be printed in the
@@ -292,24 +258,10 @@ All attributes can be set in your derived class and can be used in
rather than all applications' models, call
:meth:`~BaseCommand.validate` from :meth:`~BaseCommand.handle`.
-.. attribute:: BaseCommand.leave_locale_alone
-
- A boolean indicating whether the locale set in settings should be preserved
- during the execution of the command instead of being forcibly set to 'en-us'.
-
- Default value is ``False``.
-
- Make sure you know what you are doing if you decide to change the value of
- this option in your custom command if it creates database content that
- is locale-sensitive and such content shouldn't contain any translations (like
- it happens e.g. with django.contrib.auth permissions) as making the locale
- differ from the de facto default 'en-us' might cause unintended effects. See
- the `Management commands and locales`_ section above for further details.
+.. versionchanged: 1.8
- This option can't be ``False`` when the
- :data:`~BaseCommand.can_import_settings` option is set to ``False`` too
- because attempting to set the locale needs access to settings. This condition
- will generate a :class:`CommandError`.
+ The ``can_import_settings`` and ``leave_locale_alone`` attributes were
+ removed.
Methods
-------
View
6 docs/releases/1.8.txt
@@ -349,6 +349,12 @@ Miscellaneous
to work around a bug in IE6 and earlier. This behavior could affect
performance on IE7 and later. It was removed.
+* The current locale is not forced to 'en-us' any longer for management commands.
+ If your custom command does require the language to be set to a particular
+ locale (for example to insert untranslated content in the database), you can
+ make usage of the ``run_as_locale`` decorator to force the locale during the
+ command's execution.
+
* ``URLField.to_python`` no longer adds a trailing slash to pathless URLs.
* ``django.contrib.gis`` dropped support for GEOS 3.1 and GDAL 1.6.
View
5 tests/i18n/test_extraction.py
@@ -191,11 +191,6 @@ def test_blocktrans_trimmed(self):
self.assertMsgId("I'm on line 97", po_contents)
self.assertLocationCommentPresent(self.PO_FILE, 97, 'templates', 'test.html')
- def test_force_en_us_locale(self):
- """Value of locale-munging option used by the command is the right one"""
- from django.core.management.commands.makemessages import Command
- self.assertTrue(Command.leave_locale_alone)
-
def test_extraction_error(self):
os.chdir(self.test_dir)
self.assertRaises(SyntaxError, management.call_command, 'makemessages', locale=[LOCALE], extensions=['tpl'], verbosity=0)
View
11 tests/user_commands/management/commands/leave_locale_alone_false.py
@@ -1,11 +0,0 @@
-from django.core.management.base import BaseCommand
-from django.utils import translation
-
-
-class Command(BaseCommand):
-
- can_import_settings = True
- leave_locale_alone = False
-
- def handle(self, *args, **options):
- return translation.get_language()
View
11 tests/user_commands/management/commands/leave_locale_alone_true.py
@@ -1,11 +0,0 @@
-from django.core.management.base import BaseCommand
-from django.utils import translation
-
-
-class Command(BaseCommand):
-
- can_import_settings = True
- leave_locale_alone = True
-
- def handle(self, *args, **options):
- return translation.get_language()
View
14 tests/user_commands/tests.py
@@ -47,20 +47,6 @@ def test_system_exit(self):
sys.stderr = old_stderr
self.assertIn("CommandError", err.getvalue())
- def test_default_en_us_locale_set(self):
- # Forces en_us when set to true
- out = StringIO()
- with translation.override('pl'):
- management.call_command('leave_locale_alone_false', stdout=out)
- self.assertEqual(out.getvalue(), "en-us\n")
-
- def test_configured_locale_preserved(self):
- # Leaves locale from settings when set to false
- out = StringIO()
- with translation.override('pl'):
- management.call_command('leave_locale_alone_true', stdout=out)
- self.assertEqual(out.getvalue(), "pl\n")
-
def test_find_command_without_PATH(self):
"""
find_command should still work when the PATH environment variable

No commit comments for this range

Something went wrong with that request. Please try again.