Skip to content

Commit

Permalink
Fixed #20477: Allowed list of modules for FORMAT_MODULE_PATH
Browse files Browse the repository at this point in the history
Previously the FORMAT_MODULE_PATH setting only accepted one string (dotted
module path). A feature has been added to also allow a list of strings.

This is useful when using several reusable third party apps that define new
formats. We can now use them all and we can even override some of the formats
by providing a project-wide format module.
  • Loading branch information
mbrochh authored and timgraham committed May 21, 2014
1 parent dfeef8e commit bb0a9a0
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 24 deletions.
38 changes: 23 additions & 15 deletions django/utils/formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,29 @@ def iter_format_modules(lang, format_module_path=None):
"""
Does the heavy lifting of finding format modules.
"""
if check_for_language(lang):
format_locations = ['django.conf.locale.%s']
if format_module_path:
format_locations.append(format_module_path + '.%s')
format_locations.reverse()
locale = to_locale(lang)
locales = [locale]
if '_' in locale:
locales.append(locale.split('_')[0])
for location in format_locations:
for loc in locales:
try:
yield import_module('%s.formats' % (location % loc))
except ImportError:
pass
if not check_for_language(lang):
return

if format_module_path is None:
format_module_path = settings.FORMAT_MODULE_PATH

format_locations = []
if format_module_path:
if isinstance(format_module_path, six.string_types):
format_module_path = [format_module_path]
for path in format_module_path:
format_locations.append(path + '.%s')
format_locations.append('django.conf.locale.%s')
locale = to_locale(lang)
locales = [locale]
if '_' in locale:
locales.append(locale.split('_')[0])
for location in format_locations:
for loc in locales:
try:
yield import_module('%s.formats' % (location % loc))
except ImportError:
pass


def get_format_modules(lang=None, reverse=False):
Expand Down
14 changes: 14 additions & 0 deletions docs/ref/settings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,20 @@ like::
__init__.py
formats.py

.. versionchanged:: 1.8

You can also set this setting to a list of Python paths, for example::

FORMAT_MODULE_PATH = [
'mysite.formats',
'some_app.formats',
]

When Django searches for a certain format, it will go through all given
Python paths until it finds a module that actually defines the given
format. This means that formats defined in packages farther up in the list
will take precendence over the same formats in packages farther down.

Available formats are :setting:`DATE_FORMAT`, :setting:`TIME_FORMAT`,
:setting:`DATETIME_FORMAT`, :setting:`YEAR_MONTH_FORMAT`,
:setting:`MONTH_DAY_FORMAT`, :setting:`SHORT_DATE_FORMAT`,
Expand Down
5 changes: 4 additions & 1 deletion docs/releases/1.8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ Forms
Internationalization
^^^^^^^^^^^^^^^^^^^^

* ...
* :setting:`FORMAT_MODULE_PATH` can now be a list of strings representing
module paths. This allows importing several format modules from different
reusable apps. It also allows overriding those custom formats in your main
Django project.

Management Commands
^^^^^^^^^^^^^^^^^^^
Expand Down
17 changes: 13 additions & 4 deletions docs/topics/i18n/formatting.txt
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,20 @@ Django provides format definitions for many locales, but sometimes you might
want to create your own, because a format files doesn't exist for your locale,
or because you want to overwrite some of the values.

To use custom formats, specify the path where you'll place format files first.
To do that, just set your :setting:`FORMAT_MODULE_PATH` setting to the package
where format files will exist, for instance::

FORMAT_MODULE_PATH = 'mysite.formats'
.. versionchanged:: 1.8

The ability to specify :setting:`FORMAT_MODULE_PATH` as a list was added.
Previously, only a single string value was supported.

To use custom formats, specify the path where you'll place format files
first. To do that, just set your :setting:`FORMAT_MODULE_PATH` setting to
the package where format files will exist, for instance::

FORMAT_MODULE_PATH = [
'mysite.formats',
'some_app.formats',
]

Files are not placed directly in this directory, but in a directory named as
the locale, and must be named ``formats.py``.
Expand Down
Empty file added tests/i18n/other2/__init__.py
Empty file.
Empty file.
Empty file.
Empty file.
24 changes: 20 additions & 4 deletions tests/i18n/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,27 @@ def test_iter_format_modules(self):
"""
Tests the iter_format_modules function.
"""
# Importing some format modules so that we can compare the returned
# modules with these expected modules
default_mod = import_module('django.conf.locale.de.formats')
test_mod = import_module('i18n.other.locale.de.formats')
test_mod2 = import_module('i18n.other2.locale.de.formats')

with translation.override('de-at', deactivate=True):
de_format_mod = import_module('django.conf.locale.de.formats')
self.assertEqual(list(iter_format_modules('de')), [de_format_mod])
test_de_format_mod = import_module('i18n.other.locale.de.formats')
self.assertEqual(list(iter_format_modules('de', 'i18n.other.locale')), [test_de_format_mod, de_format_mod])
# Should return the correct default module when no setting is set
self.assertEqual(list(iter_format_modules('de')), [default_mod])

# When the setting is a string, should return the given module and
# the default module
self.assertEqual(
list(iter_format_modules('de', 'i18n.other.locale')),
[test_mod, default_mod])

# When setting is a list of strings, should return the given
# modules and the default module
self.assertEqual(
list(iter_format_modules('de', ['i18n.other.locale', 'i18n.other2.locale'])),
[test_mod, test_mod2, default_mod])

def test_iter_format_modules_stability(self):
"""
Expand Down

0 comments on commit bb0a9a0

Please sign in to comment.