Refs #32873 -- Removed settings.USE_L10N per deprecation timeline.

This commit is contained in:
Mariusz Felisiak 2023-01-06 14:46:33 +01:00
parent 0be8095b25
commit 8d98f99a4a
19 changed files with 136 additions and 573 deletions

View File

@ -30,12 +30,6 @@ USE_DEPRECATED_PYTZ_DEPRECATED_MSG = (
"code to use zoneinfo and remove the USE_DEPRECATED_PYTZ setting."
)
USE_L10N_DEPRECATED_MSG = (
"The USE_L10N setting is deprecated. Starting with Django 5.0, localized "
"formatting of data will always be enabled. For example Django will "
"display numbers and dates using the format of the current locale."
)
CSRF_COOKIE_MASKED_DEPRECATED_MSG = (
"The CSRF_COOKIE_MASKED transitional setting is deprecated. Support for "
"it will be removed in Django 5.0."
@ -173,20 +167,6 @@ class LazySettings(LazyObject):
if not filename.startswith(os.path.dirname(django.__file__)):
warnings.warn(message, category, stacklevel=2)
@property
def USE_L10N(self):
self._show_deprecation_warning(
USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning
)
return self.__getattr__("USE_L10N")
# RemovedInDjango50Warning.
@property
def _USE_L10N_INTERNAL(self):
# Special hook to avoid checking a traceback in internal use on hot
# paths.
return self.__getattr__("USE_L10N")
# RemovedInDjango51Warning.
@property
def DEFAULT_FILE_STORAGE(self):
@ -255,9 +235,6 @@ class Settings:
os.environ["TZ"] = self.TIME_ZONE
time.tzset()
if self.is_overridden("USE_L10N"):
warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
if self.is_overridden("DEFAULT_FILE_STORAGE"):
if self.is_overridden("STORAGES"):
raise ImproperlyConfigured(
@ -304,8 +281,6 @@ class UserSettingsHolder:
def __setattr__(self, name, value):
self._deleted.discard(name)
if name == "USE_L10N":
warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
if name == "CSRF_COOKIE_MASKED":
warnings.warn(CSRF_COOKIE_MASKED_DEPRECATED_MSG, RemovedInDjango50Warning)
if name == "DEFAULT_FILE_STORAGE":

View File

@ -171,11 +171,6 @@ LANGUAGE_COOKIE_SECURE = False
LANGUAGE_COOKIE_HTTPONLY = False
LANGUAGE_COOKIE_SAMESITE = None
# If you set this to True, Django will format dates, numbers and calendars
# according to user current locale.
USE_L10N = True
# Not-necessarily-technical managers of the site. They get broken link
# notifications and other various emails.
MANAGERS = ADMINS

View File

@ -7,8 +7,7 @@ register = Library()
@register.filter(is_safe=False)
def localize(value):
"""
Force a value to be rendered as a localized value,
regardless of the value of ``settings.USE_L10N``.
Force a value to be rendered as a localized value.
"""
return str(formats.localize(value, use_l10n=True))
@ -16,8 +15,7 @@ def localize(value):
@register.filter(is_safe=False)
def unlocalize(value):
"""
Force a value to be rendered as a non-localized value,
regardless of the value of ``settings.USE_L10N``.
Force a value to be rendered as a non-localized value.
"""
return str(formats.localize(value, use_l10n=False))
@ -41,8 +39,7 @@ class LocalizeNode(Node):
@register.tag("localize")
def localize_tag(parser, token):
"""
Force or prevents localization of values, regardless of the value of
`settings.USE_L10N`.
Force or prevents localization of values.
Sample usage::

View File

@ -104,13 +104,10 @@ def get_format(format_type, lang=None, use_l10n=None):
format_type is the name of the format, e.g. 'DATE_FORMAT'.
If use_l10n is provided and is not None, it forces the value to
be localized (or not), overriding the value of settings.USE_L10N.
be localized (or not), otherwise it's always localized.
"""
if use_l10n is None:
try:
use_l10n = settings._USE_L10N_INTERNAL
except AttributeError:
use_l10n = settings.USE_L10N
use_l10n = True
if use_l10n and lang is None:
lang = get_language()
format_type = str(format_type) # format_type may be lazy.
@ -153,7 +150,7 @@ def date_format(value, format=None, use_l10n=None):
localizable format.
If use_l10n is provided and is not None, that will force the value to
be localized (or not), overriding the value of settings.USE_L10N.
be localized (or not), otherwise it's always localized.
"""
return dateformat.format(
value, get_format(format or "DATE_FORMAT", use_l10n=use_l10n)
@ -165,7 +162,7 @@ def time_format(value, format=None, use_l10n=None):
Format a datetime.time object using a localizable format.
If use_l10n is provided and is not None, it forces the value to
be localized (or not), overriding the value of settings.USE_L10N.
be localized (or not), otherwise it's always localized.
"""
return dateformat.time_format(
value, get_format(format or "TIME_FORMAT", use_l10n=use_l10n)
@ -177,13 +174,10 @@ def number_format(value, decimal_pos=None, use_l10n=None, force_grouping=False):
Format a numeric value using localization settings.
If use_l10n is provided and is not None, it forces the value to
be localized (or not), overriding the value of settings.USE_L10N.
be localized (or not), otherwise it's always localized.
"""
if use_l10n is None:
try:
use_l10n = settings._USE_L10N_INTERNAL
except AttributeError:
use_l10n = settings.USE_L10N
use_l10n = True
lang = get_language() if use_l10n else None
return numberformat.format(
value,
@ -202,7 +196,7 @@ def localize(value, use_l10n=None):
formatted as a string using current locale format.
If use_l10n is provided and is not None, it forces the value to
be localized (or not), overriding the value of settings.USE_L10N.
be localized (or not), otherwise it's always localized.
"""
if isinstance(value, str): # Handle strings first for performance reasons.
return value

View File

@ -27,9 +27,9 @@ def format(
"""
if number is None or number == "":
return mark_safe(number)
use_grouping = (
use_l10n or (use_l10n is None and settings.USE_L10N)
) and settings.USE_THOUSAND_SEPARATOR
if use_l10n is None:
use_l10n = True
use_grouping = use_l10n and settings.USE_THOUSAND_SEPARATOR
use_grouping = use_grouping or force_grouping
use_grouping = use_grouping and grouping != 0
# Make the common case fast

View File

@ -438,10 +438,9 @@ For each field, we describe the default widget used if you don't specify
``datetime.date`` object.
If no ``input_formats`` argument is provided, the default input formats are
taken from :setting:`DATE_INPUT_FORMATS` if :setting:`USE_L10N` is
``False``, or from the active locale format ``DATE_INPUT_FORMATS`` key if
localization is enabled. See also :doc:`format localization
</topics/i18n/formatting>`.
taken from the active locale format ``DATE_INPUT_FORMATS`` key, or from
:setting:`DATE_INPUT_FORMATS` if localization is disabled. See also
:doc:`format localization </topics/i18n/formatting>`.
``DateTimeField``
-----------------
@ -475,10 +474,9 @@ For each field, we describe the default widget used if you don't specify
* '2006-10-25'
If no ``input_formats`` argument is provided, the default input formats are
taken from :setting:`DATETIME_INPUT_FORMATS` and
:setting:`DATE_INPUT_FORMATS` if :setting:`USE_L10N` is ``False``, or from
the active locale format ``DATETIME_INPUT_FORMATS`` and
``DATE_INPUT_FORMATS`` keys if localization is enabled. See also
taken from the active locale format ``DATETIME_INPUT_FORMATS`` and
``DATE_INPUT_FORMATS`` keys, or from :setting:`DATETIME_INPUT_FORMATS` and
:setting:`DATE_INPUT_FORMATS` if localization is disabled. See also
:doc:`format localization </topics/i18n/formatting>`.
``DecimalField``
@ -960,10 +958,9 @@ For each field, we describe the default widget used if you don't specify
``datetime.time`` object.
If no ``input_formats`` argument is provided, the default input formats are
taken from :setting:`TIME_INPUT_FORMATS` if :setting:`USE_L10N` is
``False``, or from the active locale format ``TIME_INPUT_FORMATS`` key if
localization is enabled. See also :doc:`format localization
</topics/i18n/formatting>`.
taken from the active locale format ``TIME_INPUT_FORMATS`` key, or from
:setting:`TIME_INPUT_FORMATS` if localization is disabled. See also
:doc:`format localization </topics/i18n/formatting>`.
``TypedChoiceField``
--------------------

View File

@ -1097,9 +1097,8 @@ database configurations <topics-db-multi-db-routing>`.
Default: ``'N j, Y'`` (e.g. ``Feb. 4, 2003``)
The default formatting to use for displaying date fields in any part of the
system. Note that if :setting:`USE_L10N` is set to ``True``, then the
locale-dictated format has higher precedence and will be applied instead. See
:tfilter:`allowed date format strings <date>`.
system. Note that the locale-dictated format has higher precedence and will be
applied instead. See :tfilter:`allowed date format strings <date>`.
See also :setting:`DATETIME_FORMAT`, :setting:`TIME_FORMAT` and :setting:`SHORT_DATE_FORMAT`.
@ -1130,8 +1129,7 @@ format strings use Python's :ref:`datetime module syntax
<strftime-strptime-behavior>`, not the format strings from the :tfilter:`date`
template filter.
When :setting:`USE_L10N` is ``True``, the locale-dictated format has higher
precedence and will be applied instead.
The locale-dictated format has higher precedence and will be applied instead.
See also :setting:`DATETIME_INPUT_FORMATS` and :setting:`TIME_INPUT_FORMATS`.
@ -1143,9 +1141,8 @@ See also :setting:`DATETIME_INPUT_FORMATS` and :setting:`TIME_INPUT_FORMATS`.
Default: ``'N j, Y, P'`` (e.g. ``Feb. 4, 2003, 4 p.m.``)
The default formatting to use for displaying datetime fields in any part of the
system. Note that if :setting:`USE_L10N` is set to ``True``, then the
locale-dictated format has higher precedence and will be applied instead. See
:tfilter:`allowed date format strings <date>`.
system. Note that the locale-dictated format has higher precedence and will be
applied instead. See :tfilter:`allowed date format strings <date>`.
See also :setting:`DATE_FORMAT`, :setting:`TIME_FORMAT` and :setting:`SHORT_DATETIME_FORMAT`.
@ -1175,8 +1172,7 @@ these format strings use Python's :ref:`datetime module syntax
template filter. Date-only formats are not included as datetime fields will
automatically try :setting:`DATE_INPUT_FORMATS` in last resort.
When :setting:`USE_L10N` is ``True``, the locale-dictated format has higher
precedence and will be applied instead.
The locale-dictated format has higher precedence and will be applied instead.
See also :setting:`DATE_INPUT_FORMATS` and :setting:`TIME_INPUT_FORMATS`.
@ -1254,8 +1250,8 @@ Default: ``'.'`` (Dot)
Default decimal separator used when formatting decimal numbers.
Note that if :setting:`USE_L10N` is set to ``True``, then the locale-dictated
format has higher precedence and will be applied instead.
Note that the locale-dictated format has higher precedence and will be applied
instead.
See also :setting:`NUMBER_GROUPING`, :setting:`THOUSAND_SEPARATOR` and
:setting:`USE_THOUSAND_SEPARATOR`.
@ -2170,8 +2166,8 @@ drilldown, the header for a given day displays the day and month. Different
locales have different formats. For example, U.S. English would say
"January 1," whereas Spanish might say "1 Enero."
Note that if :setting:`USE_L10N` is set to ``True``, then the corresponding
locale-dictated format has higher precedence and will be applied.
Note that the corresponding locale-dictated format has higher precedence and
will be applied instead.
See :tfilter:`allowed date format strings <date>`. See also
:setting:`DATE_FORMAT`, :setting:`DATETIME_FORMAT`,
@ -2203,8 +2199,8 @@ Example tuple for ``en_IN``::
NUMBER_GROUPING = (3, 2, 0)
Note that if :setting:`USE_L10N` is set to ``True``, then the locale-dictated
format has higher precedence and will be applied instead.
Note that the locale-dictated format has higher precedence and will be applied
instead.
See also :setting:`DECIMAL_SEPARATOR`, :setting:`THOUSAND_SEPARATOR` and
:setting:`USE_THOUSAND_SEPARATOR`.
@ -2542,9 +2538,9 @@ The email address that error messages come from, such as those sent to
Default: ``'m/d/Y'`` (e.g. ``12/31/2003``)
An available formatting that can be used for displaying date fields on
templates. Note that if :setting:`USE_L10N` is set to ``True``, then the
corresponding locale-dictated format has higher precedence and will be applied.
See :tfilter:`allowed date format strings <date>`.
templates. Note that the corresponding locale-dictated format has higher
precedence and will be applied instead. See
:tfilter:`allowed date format strings <date>`.
See also :setting:`DATE_FORMAT` and :setting:`SHORT_DATETIME_FORMAT`.
@ -2556,9 +2552,9 @@ See also :setting:`DATE_FORMAT` and :setting:`SHORT_DATETIME_FORMAT`.
Default: ``'m/d/Y P'`` (e.g. ``12/31/2003 4 p.m.``)
An available formatting that can be used for displaying datetime fields on
templates. Note that if :setting:`USE_L10N` is set to ``True``, then the
corresponding locale-dictated format has higher precedence and will be applied.
See :tfilter:`allowed date format strings <date>`.
templates. Note that the corresponding locale-dictated format has higher
precedence and will be applied instead. See
:tfilter:`allowed date format strings <date>`.
See also :setting:`DATE_FORMAT` and :setting:`SHORT_DATE_FORMAT`.
@ -2769,8 +2765,8 @@ Default thousand separator used when formatting numbers. This setting is
used only when :setting:`USE_THOUSAND_SEPARATOR` is ``True`` and
:setting:`NUMBER_GROUPING` is greater than ``0``.
Note that if :setting:`USE_L10N` is set to ``True``, then the locale-dictated
format has higher precedence and will be applied instead.
Note that the locale-dictated format has higher precedence and will be applied
instead.
See also :setting:`NUMBER_GROUPING`, :setting:`DECIMAL_SEPARATOR` and
:setting:`USE_THOUSAND_SEPARATOR`.
@ -2783,9 +2779,8 @@ See also :setting:`NUMBER_GROUPING`, :setting:`DECIMAL_SEPARATOR` and
Default: ``'P'`` (e.g. ``4 p.m.``)
The default formatting to use for displaying time fields in any part of the
system. Note that if :setting:`USE_L10N` is set to ``True``, then the
locale-dictated format has higher precedence and will be applied instead. See
:tfilter:`allowed date format strings <date>`.
system. Note that the locale-dictated format has higher precedence and will be
applied instead. See :tfilter:`allowed date format strings <date>`.
See also :setting:`DATE_FORMAT` and :setting:`DATETIME_FORMAT`.
@ -2808,8 +2803,7 @@ format strings use Python's :ref:`datetime module syntax
<strftime-strptime-behavior>`, not the format strings from the :tfilter:`date`
template filter.
When :setting:`USE_L10N` is ``True``, the locale-dictated format has higher
precedence and will be applied instead.
The locale-dictated format has higher precedence and will be applied instead.
See also :setting:`DATE_INPUT_FORMATS` and :setting:`DATETIME_INPUT_FORMATS`.
@ -2882,32 +2876,13 @@ This provides a way to turn it off, for performance. If this is set to
``False``, Django will make some optimizations so as not to load the
translation machinery.
See also :setting:`LANGUAGE_CODE`, :setting:`USE_L10N` and :setting:`USE_TZ`.
See also :setting:`LANGUAGE_CODE` and :setting:`USE_TZ`.
.. note::
The default :file:`settings.py` file created by :djadmin:`django-admin
startproject <startproject>` includes ``USE_I18N = True`` for convenience.
.. setting:: USE_L10N
``USE_L10N``
------------
Default: ``True``
A boolean that specifies if localized formatting of data will be enabled by
default or not. If this is set to ``True``, e.g. Django will display numbers and
dates using the format of the current locale.
See also :setting:`LANGUAGE_CODE`, :setting:`USE_I18N` and :setting:`USE_TZ`.
.. deprecated:: 4.0
This setting is deprecated. Starting with Django 5.0, localized formatting
of data will always be enabled. For example Django will display numbers and
dates using the format of the current locale.
.. setting:: USE_THOUSAND_SEPARATOR
``USE_THOUSAND_SEPARATOR``
@ -2916,10 +2891,9 @@ See also :setting:`LANGUAGE_CODE`, :setting:`USE_I18N` and :setting:`USE_TZ`.
Default: ``False``
A boolean that specifies whether to display numbers using a thousand separator.
When set to ``True`` and :setting:`USE_L10N` is also ``True``, Django will
format numbers using the :setting:`NUMBER_GROUPING` and
:setting:`THOUSAND_SEPARATOR` settings. The latter two settings may also be
dictated by the locale, which takes precedence.
When set to ``True``, Django will format numbers using the
:setting:`NUMBER_GROUPING` and :setting:`THOUSAND_SEPARATOR` settings. The
latter two settings may also be dictated by the locale, which takes precedence.
See also :setting:`DECIMAL_SEPARATOR`, :setting:`NUMBER_GROUPING` and
:setting:`THOUSAND_SEPARATOR`.
@ -2938,7 +2912,7 @@ When ``USE_TZ`` is False, Django will use naive datetimes in local time, except
when parsing ISO 8601 formatted strings, where timezone information will always
be retained if present.
See also :setting:`TIME_ZONE`, :setting:`USE_I18N` and :setting:`USE_L10N`.
See also :setting:`TIME_ZONE` and :setting:`USE_I18N`.
.. versionchanged:: 5.0
@ -3005,8 +2979,8 @@ drilldown, the header for a given month displays the month and the year.
Different locales have different formats. For example, U.S. English would say
"January 2006," whereas another locale might say "2006/January."
Note that if :setting:`USE_L10N` is set to ``True``, then the corresponding
locale-dictated format has higher precedence and will be applied.
Note that the corresponding locale-dictated format has higher precedence and
will be applied instead.
See :tfilter:`allowed date format strings <date>`. See also
:setting:`DATE_FORMAT`, :setting:`DATETIME_FORMAT`, :setting:`TIME_FORMAT`
@ -3730,7 +3704,6 @@ Globalization (``i18n``/``l10n``)
* :setting:`TIME_INPUT_FORMATS`
* :setting:`TIME_ZONE`
* :setting:`USE_I18N`
* :setting:`USE_L10N`
* :setting:`USE_THOUSAND_SEPARATOR`
* :setting:`USE_TZ`
* :setting:`YEAR_MONTH_FORMAT`

View File

@ -1445,8 +1445,7 @@ The format passed can be one of the predefined ones :setting:`DATE_FORMAT`,
specifiers shown in the table above. Note that predefined formats may vary
depending on the current locale.
Assuming that :setting:`USE_L10N` is ``True`` and :setting:`LANGUAGE_CODE` is,
for example, ``"es"``, then for::
Assuming that :setting:`LANGUAGE_CODE` is, for example, ``"es"``, then for::
{{ value|date:"SHORT_DATE_FORMAT" }}
@ -2226,8 +2225,7 @@ This would display as "01h 23m".
Another example:
Assuming that :setting:`USE_L10N` is ``True`` and :setting:`LANGUAGE_CODE` is,
for example, ``"de"``, then for::
Assuming that :setting:`LANGUAGE_CODE` is, for example, ``"de"``, then for::
{{ value|time:"TIME_FORMAT" }}
@ -2586,8 +2584,7 @@ See :ref:`specifying-translation-strings-in-template-code`.
--------
This library provides control over the localization of values in templates.
You only need to load the library using ``{% load l10n %}``, but you'll often
set :setting:`USE_L10N` to ``True`` so that localization is active by default.
You only need to load the library using ``{% load l10n %}``.
See :ref:`topic-l10n-templates`.

View File

@ -274,6 +274,8 @@ to remove usage of these features.
``StringAgg`` aggregates no longer return ``[]``, ``[]``, and ``''``,
respectively, when there are no rows.
* The ``USE_L10N`` setting is removed.
See :ref:`deprecated-features-4.1` for details on these changes, including how
to remove usage of these features.

View File

@ -9,12 +9,8 @@ Django's formatting system is capable of displaying dates, times and numbers in
templates using the format specified for the current
:term:`locale <locale name>`. It also handles localized input in forms.
When it's enabled, two users accessing the same content may see dates, times and
numbers formatted in different ways, depending on the formats for their current
locale.
The formatting system is enabled by default. To disable it, it's
necessary to set :setting:`USE_L10N = False <USE_L10N>` in your settings file.
Two users accessing the same content may see dates, times and numbers formatted
in different ways, depending on the formats for their current locale.
.. note::
@ -55,9 +51,8 @@ argument::
Controlling localization in templates
=====================================
When you have enabled formatting with :setting:`USE_L10N`, Django
will try to use a locale specific format whenever it outputs a value
in a template.
Django tries to use a locale specific format whenever it outputs a value in a
template.
However, it may not always be appropriate to use localized values --
for example, if you're outputting JavaScript or XML that is designed
@ -80,9 +75,6 @@ Template tags
Enables or disables localization of template variables in the
contained block.
This tag allows a more fine grained control of localization than
:setting:`USE_L10N`.
To activate or deactivate localization for a template block, use::
{% load l10n %}
@ -95,11 +87,6 @@ To activate or deactivate localization for a template block, use::
{{ value }}
{% endlocalize %}
.. note::
The value of :setting:`USE_L10N` isn't respected inside of a
``{% localize %}`` block.
See :tfilter:`localize` and :tfilter:`unlocalize` for template filters that will
do the same job on a per-variable basis.

View File

@ -54,10 +54,9 @@ More details can be found in the `W3C Web Internationalization FAQ`_, the `Wikip
.. warning::
Translation and formatting are controlled by :setting:`USE_I18N` and
:setting:`USE_L10N` settings respectively. However, both features involve
internationalization and localization. The names of the settings are an
unfortunate result of Django's history.
Translation is controlled by the :setting:`USE_I18N` setting. However, it
involves internationalization and localization. The name of the setting is
an unfortunate result of Django's history.
Here are some other terms that will help us to handle a common language:

View File

@ -1,43 +0,0 @@
import sys
from types import ModuleType
from django.conf import USE_L10N_DEPRECATED_MSG, Settings, settings
from django.test import TestCase, ignore_warnings
from django.utils.deprecation import RemovedInDjango50Warning
class DeprecationTests(TestCase):
msg = USE_L10N_DEPRECATED_MSG
def test_override_settings_warning(self):
# Warning is raised when USE_L10N is set in UserSettingsHolder (used by
# the @override_settings decorator).
with self.assertRaisesMessage(RemovedInDjango50Warning, self.msg):
with self.settings(USE_L10N=True):
pass
def test_settings_init_warning(self):
settings_module = ModuleType("fake_settings_module")
settings_module.SECRET_KEY = "foo"
settings_module.USE_TZ = True
settings_module.USE_L10N = False
sys.modules["fake_settings_module"] = settings_module
try:
with self.assertRaisesMessage(RemovedInDjango50Warning, self.msg):
Settings("fake_settings_module")
finally:
del sys.modules["fake_settings_module"]
def test_access_warning(self):
with self.assertRaisesMessage(RemovedInDjango50Warning, self.msg):
settings.USE_L10N
# Works a second time.
with self.assertRaisesMessage(RemovedInDjango50Warning, self.msg):
settings.USE_L10N
@ignore_warnings(category=RemovedInDjango50Warning)
def test_access(self):
with self.settings(USE_L10N=False):
self.assertIs(settings.USE_L10N, False)
# Works a second time.
self.assertIs(settings.USE_L10N, False)

View File

@ -2,9 +2,8 @@ import decimal
from django.core.exceptions import ValidationError
from django.forms import DecimalField, NumberInput, Widget
from django.test import SimpleTestCase, ignore_warnings, override_settings
from django.test import SimpleTestCase, override_settings
from django.utils import formats, translation
from django.utils.deprecation import RemovedInDjango50Warning
from . import FormFieldAssertionsMixin
@ -195,31 +194,22 @@ class DecimalFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
localized_d = formats.localize_input(d) # -> '0,1' in French
self.assertFalse(f.has_changed(d, localized_d))
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The test should remain because
# format-related settings will take precedence over locale-dictated
# formats.
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(USE_L10N=False, DECIMAL_SEPARATOR=",")
@override_settings(DECIMAL_SEPARATOR=",")
def test_decimalfield_support_decimal_separator(self):
f = DecimalField(localize=True)
self.assertEqual(f.clean("1001,10"), decimal.Decimal("1001.10"))
self.assertEqual(f.clean("1001.10"), decimal.Decimal("1001.10"))
with translation.override(None):
f = DecimalField(localize=True)
self.assertEqual(f.clean("1001,10"), decimal.Decimal("1001.10"))
self.assertEqual(f.clean("1001.10"), decimal.Decimal("1001.10"))
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The test should remain because
# format-related settings will take precedence over locale-dictated
# formats.
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(
USE_L10N=False,
DECIMAL_SEPARATOR=",",
USE_THOUSAND_SEPARATOR=True,
THOUSAND_SEPARATOR=".",
)
def test_decimalfield_support_thousands_separator(self):
f = DecimalField(localize=True)
self.assertEqual(f.clean("1.001,10"), decimal.Decimal("1001.10"))
msg = "'Enter a number.'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean("1,001.1")
with translation.override(None):
f = DecimalField(localize=True)
self.assertEqual(f.clean("1.001,10"), decimal.Decimal("1001.10"))
msg = "'Enter a number.'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean("1,001.1")

View File

@ -2,10 +2,9 @@ from django.core.exceptions import ValidationError
from django.forms import FloatField, NumberInput
from django.test import SimpleTestCase
from django.test.selenium import SeleniumTestCase
from django.test.utils import ignore_warnings, override_settings
from django.test.utils import override_settings
from django.urls import reverse
from django.utils import formats, translation
from django.utils.deprecation import RemovedInDjango50Warning
from . import FormFieldAssertionsMixin
@ -111,34 +110,25 @@ class FloatFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
localized_n = formats.localize_input(n) # -> '4,35' in French
self.assertFalse(f.has_changed(n, localized_n))
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The test should remain because
# format-related settings will take precedence over locale-dictated
# formats.
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(USE_L10N=False, DECIMAL_SEPARATOR=",")
def test_decimalfield_support_decimal_separator(self):
f = FloatField(localize=True)
self.assertEqual(f.clean("1001,10"), 1001.10)
self.assertEqual(f.clean("1001.10"), 1001.10)
@override_settings(DECIMAL_SEPARATOR=",")
def test_floatfield_support_decimal_separator(self):
with translation.override(None):
f = FloatField(localize=True)
self.assertEqual(f.clean("1001,10"), 1001.10)
self.assertEqual(f.clean("1001.10"), 1001.10)
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The test should remain because
# format-related settings will take precedence over locale-dictated
# formats.
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(
USE_L10N=False,
DECIMAL_SEPARATOR=",",
USE_THOUSAND_SEPARATOR=True,
THOUSAND_SEPARATOR=".",
)
def test_decimalfield_support_thousands_separator(self):
f = FloatField(localize=True)
self.assertEqual(f.clean("1.001,10"), 1001.10)
msg = "'Enter a number.'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean("1,001.1")
def test_floatfield_support_thousands_separator(self):
with translation.override(None):
f = FloatField(localize=True)
self.assertEqual(f.clean("1.001,10"), 1001.10)
msg = "'Enter a number.'"
with self.assertRaisesMessage(ValidationError, msg):
f.clean("1,001.1")
@override_settings(ROOT_URLCONF="forms_tests.urls")

View File

@ -120,7 +120,7 @@ class LocalizedTimeTests(SimpleTestCase):
self.assertEqual(text, "13:30:00")
@translation.override(None) # RemovedInDjango50Warning.
@translation.override(None)
@override_settings(TIME_INPUT_FORMATS=["%I:%M:%S %p", "%I:%M %p"])
class CustomTimeInputFormatsTests(SimpleTestCase):
def test_timeField(self):
@ -434,7 +434,7 @@ class LocalizedDateTests(SimpleTestCase):
self.assertEqual(text, "21.12.2010")
@translation.override(None) # RemovedInDjango50Warning.
@translation.override(None)
@override_settings(DATE_INPUT_FORMATS=["%d.%m.%Y", "%d-%m-%Y"])
class CustomDateInputFormatsTests(SimpleTestCase):
def test_dateField(self):
@ -756,7 +756,7 @@ class LocalizedDateTimeTests(SimpleTestCase):
self.assertEqual(text, "21.12.2010 13:30:00")
@translation.override(None) # RemovedInDjango50Warning.
@translation.override(None)
@override_settings(DATETIME_INPUT_FORMATS=["%I:%M:%S %p %d/%m/%Y", "%I:%M %p %d-%m-%Y"])
class CustomDateTimeInputFormatsTests(SimpleTestCase):
def test_dateTimeField(self):

View File

@ -1,9 +1,7 @@
from datetime import datetime
from django.forms import CharField, DateTimeInput, Form
from django.test import ignore_warnings
from django.utils import translation
from django.utils.deprecation import RemovedInDjango50Warning
from .base import WidgetTest
@ -65,39 +63,6 @@ class DateTimeInputTest(WidgetTest):
html=('<input type="text" name="date" value="17.09.2007 12:51:34">'),
)
@translation.override("de-at")
def test_locale_aware(self):
d = datetime(2007, 9, 17, 12, 51, 34, 482548)
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The assertion should remain
# because format-related settings will take precedence over
# locale-dictated formats.
with ignore_warnings(category=RemovedInDjango50Warning):
with self.settings(USE_L10N=False):
with self.settings(
DATETIME_INPUT_FORMATS=[
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M:%S.%f",
"%Y-%m-%d %H:%M",
]
):
self.check_html(
self.widget,
"date",
d,
html=(
'<input type="text" name="date" '
'value="2007-09-17 12:51:34">'
),
)
with translation.override("es"):
self.check_html(
self.widget,
"date",
d,
html='<input type="text" name="date" value="17/09/2007 12:51:34">',
)
def test_fieldset(self):
class TestForm(Form):
template_name = "forms_tests/use_fieldset.html"

View File

@ -1,10 +1,9 @@
from datetime import date
from django.forms import DateField, Form, SelectDateWidget
from django.test import ignore_warnings, override_settings
from django.test import override_settings
from django.utils import translation
from django.utils.dates import MONTHS_AP
from django.utils.deprecation import RemovedInDjango50Warning
from .base import WidgetTest
@ -542,32 +541,28 @@ class SelectDateWidgetTest(WidgetTest):
"13-08-0001",
)
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The test should remain because
# format-related settings will take precedence over locale-dictated
# formats.
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(USE_L10N=False, DATE_INPUT_FORMATS=["%d.%m.%Y"])
@override_settings(DATE_INPUT_FORMATS=["%d.%m.%Y"])
def test_custom_input_format(self):
w = SelectDateWidget(years=("0001", "1899", "2009", "2010"))
for values, expected_value in (
(("0001", "8", "13"), "13.08.0001"),
(("1899", "7", "11"), "11.07.1899"),
(("2009", "3", "7"), "07.03.2009"),
):
with self.subTest(values=values):
data = {
"field_%s" % field: value
for field, value in zip(("year", "month", "day"), values)
}
self.assertEqual(
w.value_from_datadict(data, {}, "field"), expected_value
)
expected_dict = {
field: int(value)
for field, value in zip(("year", "month", "day"), values)
}
self.assertEqual(w.format_value(expected_value), expected_dict)
with translation.override(None):
for values, expected_value in (
(("0001", "8", "13"), "13.08.0001"),
(("1899", "7", "11"), "11.07.1899"),
(("2009", "3", "7"), "07.03.2009"),
):
with self.subTest(values=values):
data = {
"field_%s" % field: value
for field, value in zip(("year", "month", "day"), values)
}
self.assertEqual(
w.value_from_datadict(data, {}, "field"), expected_value
)
expected_dict = {
field: int(value)
for field, value in zip(("year", "month", "day"), values)
}
self.assertEqual(w.format_value(expected_value), expected_dict)
def test_format_value(self):
valid_formats = [

View File

@ -18,15 +18,8 @@ from django.conf import settings
from django.conf.locale import LANG_INFO
from django.conf.urls.i18n import i18n_patterns
from django.template import Context, Template
from django.test import (
RequestFactory,
SimpleTestCase,
TestCase,
ignore_warnings,
override_settings,
)
from django.test import RequestFactory, SimpleTestCase, TestCase, override_settings
from django.utils import translation
from django.utils.deprecation import RemovedInDjango50Warning
from django.utils.formats import (
date_format,
get_format,
@ -656,181 +649,6 @@ class FormattingTests(SimpleTestCase):
"⌚ 10:15", Template('{{ t|time:"⌚ H:i" }}').render(self.ctxt)
)
@ignore_warnings(category=RemovedInDjango50Warning)
@override_settings(USE_L10N=False)
def test_l10n_disabled(self):
"""
Catalan locale with format i18n disabled translations will be used,
but not formats
"""
with translation.override("ca", deactivate=True):
self.maxDiff = 3000
self.assertEqual("N j, Y", get_format("DATE_FORMAT"))
self.assertEqual(0, get_format("FIRST_DAY_OF_WEEK"))
self.assertEqual(".", get_format("DECIMAL_SEPARATOR"))
self.assertEqual("10:15 a.m.", time_format(self.t))
self.assertEqual("Des. 31, 2009", date_format(self.d))
self.assertEqual("desembre 2009", date_format(self.d, "YEAR_MONTH_FORMAT"))
self.assertEqual(
"12/31/2009 8:50 p.m.", date_format(self.dt, "SHORT_DATETIME_FORMAT")
)
self.assertEqual("No localizable", localize("No localizable"))
self.assertEqual("66666.666", localize(self.n))
self.assertEqual("99999.999", localize(self.f))
self.assertEqual("10000", localize(self.long))
self.assertEqual("Des. 31, 2009", localize(self.d))
self.assertEqual("Des. 31, 2009, 8:50 p.m.", localize(self.dt))
self.assertEqual("66666.666", Template("{{ n }}").render(self.ctxt))
self.assertEqual("99999.999", Template("{{ f }}").render(self.ctxt))
self.assertEqual("Des. 31, 2009", Template("{{ d }}").render(self.ctxt))
self.assertEqual(
"Des. 31, 2009, 8:50 p.m.", Template("{{ dt }}").render(self.ctxt)
)
self.assertEqual(
"66666.67", Template('{{ n|floatformat:"2u" }}').render(self.ctxt)
)
self.assertEqual(
"100000.0", Template('{{ f|floatformat:"u" }}').render(self.ctxt)
)
self.assertEqual(
"66666.67",
Template('{{ n|floatformat:"2gu" }}').render(self.ctxt),
)
self.assertEqual(
"100000.0",
Template('{{ f|floatformat:"ug" }}').render(self.ctxt),
)
self.assertEqual(
"10:15 a.m.", Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt)
)
self.assertEqual(
"12/31/2009",
Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt),
)
self.assertEqual(
"12/31/2009 8:50 p.m.",
Template('{{ dt|date:"SHORT_DATETIME_FORMAT" }}').render(self.ctxt),
)
form = I18nForm(
{
"decimal_field": "66666,666",
"float_field": "99999,999",
"date_field": "31/12/2009",
"datetime_field": "31/12/2009 20:50",
"time_field": "20:50",
"integer_field": "1.234",
}
)
self.assertFalse(form.is_valid())
self.assertEqual(["Introdu\xefu un n\xfamero."], form.errors["float_field"])
self.assertEqual(
["Introdu\xefu un n\xfamero."], form.errors["decimal_field"]
)
self.assertEqual(
["Introdu\xefu una data v\xe0lida."], form.errors["date_field"]
)
self.assertEqual(
["Introdu\xefu una data/hora v\xe0lides."],
form.errors["datetime_field"],
)
self.assertEqual(
["Introdu\xefu un n\xfamero enter."], form.errors["integer_field"]
)
form2 = SelectDateForm(
{
"date_field_month": "12",
"date_field_day": "31",
"date_field_year": "2009",
}
)
self.assertTrue(form2.is_valid())
self.assertEqual(
datetime.date(2009, 12, 31), form2.cleaned_data["date_field"]
)
self.assertHTMLEqual(
'<select name="mydate_month" id="id_mydate_month">'
'<option value="">---</option>'
'<option value="1">gener</option>'
'<option value="2">febrer</option>'
'<option value="3">mar\xe7</option>'
'<option value="4">abril</option>'
'<option value="5">maig</option>'
'<option value="6">juny</option>'
'<option value="7">juliol</option>'
'<option value="8">agost</option>'
'<option value="9">setembre</option>'
'<option value="10">octubre</option>'
'<option value="11">novembre</option>'
'<option value="12" selected>desembre</option>'
"</select>"
'<select name="mydate_day" id="id_mydate_day">'
'<option value="">---</option>'
'<option value="1">1</option>'
'<option value="2">2</option>'
'<option value="3">3</option>'
'<option value="4">4</option>'
'<option value="5">5</option>'
'<option value="6">6</option>'
'<option value="7">7</option>'
'<option value="8">8</option>'
'<option value="9">9</option>'
'<option value="10">10</option>'
'<option value="11">11</option>'
'<option value="12">12</option>'
'<option value="13">13</option>'
'<option value="14">14</option>'
'<option value="15">15</option>'
'<option value="16">16</option>'
'<option value="17">17</option>'
'<option value="18">18</option>'
'<option value="19">19</option>'
'<option value="20">20</option>'
'<option value="21">21</option>'
'<option value="22">22</option>'
'<option value="23">23</option>'
'<option value="24">24</option>'
'<option value="25">25</option>'
'<option value="26">26</option>'
'<option value="27">27</option>'
'<option value="28">28</option>'
'<option value="29">29</option>'
'<option value="30">30</option>'
'<option value="31" selected>31</option>'
"</select>"
'<select name="mydate_year" id="id_mydate_year">'
'<option value="">---</option>'
'<option value="2009" selected>2009</option>'
'<option value="2010">2010</option>'
'<option value="2011">2011</option>'
'<option value="2012">2012</option>'
'<option value="2013">2013</option>'
'<option value="2014">2014</option>'
'<option value="2015">2015</option>'
'<option value="2016">2016</option>'
'<option value="2017">2017</option>'
'<option value="2018">2018</option>'
"</select>",
forms.SelectDateWidget(years=range(2009, 2019)).render(
"mydate", datetime.date(2009, 12, 31)
),
)
# We shouldn't change the behavior of the floatformat filter re:
# thousand separator and grouping when localization is disabled
# even if the USE_THOUSAND_SEPARATOR, NUMBER_GROUPING and
# THOUSAND_SEPARATOR settings are specified.
with self.settings(
USE_THOUSAND_SEPARATOR=True, NUMBER_GROUPING=1, THOUSAND_SEPARATOR="!"
):
self.assertEqual(
"66666.67", Template('{{ n|floatformat:"2u" }}').render(self.ctxt)
)
self.assertEqual(
"100000.0", Template('{{ f|floatformat:"u" }}').render(self.ctxt)
)
def test_false_like_locale_formats(self):
"""
The active locale's formats take precedence over the default settings
@ -1422,7 +1240,7 @@ class FormattingTests(SimpleTestCase):
self.assertEqual(sanitize_separators("77\xa0777,777"), "77777.777")
self.assertEqual(sanitize_separators("12 345"), "12345")
self.assertEqual(sanitize_separators("77 777,777"), "77777.777")
with translation.override(None): # RemovedInDjango50Warning
with translation.override(None):
with self.settings(USE_THOUSAND_SEPARATOR=True, THOUSAND_SEPARATOR="."):
self.assertEqual(sanitize_separators("12\xa0345"), "12\xa0345")
@ -1434,25 +1252,20 @@ class FormattingTests(SimpleTestCase):
# Suspicion that user entered dot as decimal separator (#22171)
self.assertEqual(sanitize_separators("10.10"), "10.10")
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The assertions should remain
# because format-related settings will take precedence over
# locale-dictated formats.
with ignore_warnings(category=RemovedInDjango50Warning):
with self.settings(USE_L10N=False):
with self.settings(DECIMAL_SEPARATOR=","):
self.assertEqual(sanitize_separators("1001,10"), "1001.10")
self.assertEqual(sanitize_separators("1001.10"), "1001.10")
with self.settings(
DECIMAL_SEPARATOR=",",
THOUSAND_SEPARATOR=".",
USE_THOUSAND_SEPARATOR=True,
):
self.assertEqual(sanitize_separators("1.001,10"), "1001.10")
self.assertEqual(sanitize_separators("1001,10"), "1001.10")
self.assertEqual(sanitize_separators("1001.10"), "1001.10")
# Invalid output.
self.assertEqual(sanitize_separators("1,001.10"), "1.001.10")
with translation.override(None):
with self.settings(DECIMAL_SEPARATOR=","):
self.assertEqual(sanitize_separators("1001,10"), "1001.10")
self.assertEqual(sanitize_separators("1001.10"), "1001.10")
with self.settings(
DECIMAL_SEPARATOR=",",
THOUSAND_SEPARATOR=".",
USE_THOUSAND_SEPARATOR=True,
):
self.assertEqual(sanitize_separators("1.001,10"), "1001.10")
self.assertEqual(sanitize_separators("1001,10"), "1001.10")
self.assertEqual(sanitize_separators("1001.10"), "1001.10")
# Invalid output.
self.assertEqual(sanitize_separators("1,001.10"), "1.001.10")
def test_iter_format_modules(self):
"""
@ -1525,10 +1338,6 @@ class FormattingTests(SimpleTestCase):
"{% load l10n %}{{ int }}/{{ float }}/{{ date }}; "
"{{ int|unlocalize }}/{{ float|unlocalize }}/{{ date|unlocalize }}"
)
template4 = Template(
"{% load l10n %}{{ int }}/{{ float }}/{{ date }}; "
"{{ int|localize }}/{{ float|localize }}/{{ date|localize }}"
)
expected_localized = "1.455/3,14/31. Dezember 2016"
expected_unlocalized = "1455/3.14/Dez. 31, 2016"
output1 = "; ".join([expected_localized, expected_localized])
@ -1536,22 +1345,7 @@ class FormattingTests(SimpleTestCase):
[expected_localized, expected_unlocalized, expected_localized]
)
output3 = "; ".join([expected_localized, expected_unlocalized])
output4 = "; ".join([expected_unlocalized, expected_localized])
with translation.override("de", deactivate=True):
# RemovedInDjango50Warning: When the deprecation ends, remove
# @ignore_warnings and USE_L10N=False. The assertions should remain
# because format-related settings will take precedence over
# locale-dictated formats.
with ignore_warnings(category=RemovedInDjango50Warning):
with self.settings(
USE_L10N=False,
DATE_FORMAT="N j, Y",
DECIMAL_SEPARATOR=".",
NUMBER_GROUPING=0,
USE_THOUSAND_SEPARATOR=True,
):
self.assertEqual(template1.render(context), output1)
self.assertEqual(template4.render(context), output4)
with self.settings(USE_THOUSAND_SEPARATOR=True):
self.assertEqual(template1.render(context), output1)
self.assertEqual(template2.render(context), output2)
@ -1573,16 +1367,6 @@ class FormattingTests(SimpleTestCase):
NUMBER_GROUPING=2,
):
self.assertEqual(template.render(context), "1455/3.14/24.1567")
# RemovedInDjango50Warning.
with ignore_warnings(category=RemovedInDjango50Warning):
with self.settings(
USE_L10N=False,
DECIMAL_SEPARATOR=",",
USE_THOUSAND_SEPARATOR=True,
THOUSAND_SEPARATOR="°",
NUMBER_GROUPING=2,
):
self.assertEqual(template.render(context), "1455/3.14/24.1567")
def test_localized_as_text_as_hidden_input(self):
"""

View File

@ -38,7 +38,7 @@ from django.test import (
)
from django.test.utils import requires_tz_support
from django.urls import reverse
from django.utils import timezone
from django.utils import timezone, translation
from django.utils.deprecation import RemovedInDjango50Warning
from django.utils.timezone import timedelta
@ -968,18 +968,9 @@ class SerializationTests(SimpleTestCase):
self.assertEqual(obj.dt, dt)
# RemovedInDjango50Warning: When the deprecation ends, remove setUpClass() and
# USE_L10N=False. The tests should remain because format-related settings will
# take precedence over locale-dictated formats.
@override_settings(
DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_L10N=False, USE_TZ=True
)
@translation.override(None)
@override_settings(DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_TZ=True)
class TemplateTests(SimpleTestCase):
@classmethod
def setUpClass(cls):
with ignore_warnings(category=RemovedInDjango50Warning):
super().setUpClass()
@requires_tz_support
def test_localtime_templatetag_and_filters(self):
"""
@ -1280,18 +1271,8 @@ class TemplateTests(SimpleTestCase):
self.assertEqual(tpl.render(Context({})), "+0700")
# RemovedInDjango50Warning: When the deprecation ends, remove setUpClass() and
# USE_L10N=False. The tests should remain because format-related settings will
# take precedence over locale-dictated formats.
@override_settings(
DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_L10N=False, USE_TZ=False
)
@override_settings(DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_TZ=False)
class LegacyFormsTests(TestCase):
@classmethod
def setUpClass(cls):
with ignore_warnings(category=RemovedInDjango50Warning):
super().setUpClass()
def test_form(self):
form = EventForm({"dt": "2011-09-01 13:20:30"})
self.assertTrue(form.is_valid())
@ -1336,18 +1317,8 @@ class LegacyFormsTests(TestCase):
self.assertEqual(e.dt, datetime.datetime(2011, 9, 1, 13, 20, 30))
# RemovedInDjango50Warning: When the deprecation ends, remove setUpClass() and
# USE_L10N=False. The tests should remain because format-related settings will
# take precedence over locale-dictated formats.
@override_settings(
DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_L10N=False, USE_TZ=True
)
@override_settings(DATETIME_FORMAT="c", TIME_ZONE="Africa/Nairobi", USE_TZ=True)
class NewFormsTests(TestCase):
@classmethod
def setUpClass(cls):
with ignore_warnings(category=RemovedInDjango50Warning):
super().setUpClass()
@requires_tz_support
def test_form(self):
form = EventForm({"dt": "2011-09-01 13:20:30"})
@ -1426,19 +1397,14 @@ class NewFormsTests(TestCase):
self.assertIn("2011-09-01 17:20:30", str(form))
@translation.override(None)
@override_settings(
DATETIME_FORMAT="c",
TIME_ZONE="Africa/Nairobi",
USE_L10N=False,
USE_TZ=True,
ROOT_URLCONF="timezones.urls",
)
class AdminTests(TestCase):
@classmethod
def setUpClass(cls):
with ignore_warnings(category=RemovedInDjango50Warning):
super().setUpClass()
@classmethod
def setUpTestData(cls):
cls.u1 = User.objects.create_user(