Fixed #29817 -- Deprecated settings.FILE_CHARSET.

This commit is contained in:
Jon Dufresne 2018-10-02 20:45:19 -07:00 committed by Tim Graham
parent 99d4fc18bd
commit 0cd465b63a
8 changed files with 83 additions and 12 deletions

View File

@ -16,12 +16,18 @@ from pathlib import Path
import django import django
from django.conf import global_settings from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.utils.deprecation import RemovedInDjango30Warning from django.utils.deprecation import (
RemovedInDjango30Warning, RemovedInDjango31Warning,
)
from django.utils.functional import LazyObject, empty from django.utils.functional import LazyObject, empty
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE" ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
DEFAULT_CONTENT_TYPE_DEPRECATED_MSG = 'The DEFAULT_CONTENT_TYPE setting is deprecated.' DEFAULT_CONTENT_TYPE_DEPRECATED_MSG = 'The DEFAULT_CONTENT_TYPE setting is deprecated.'
FILE_CHARSET_DEPRECATED_MSG = (
'The FILE_CHARSET setting is deprecated. Starting with Django 3.1, all '
'files read from disk must be UTF-8 encoded.'
)
class LazySettings(LazyObject): class LazySettings(LazyObject):
@ -111,6 +117,20 @@ class LazySettings(LazyObject):
) )
return self.__getattr__('DEFAULT_CONTENT_TYPE') return self.__getattr__('DEFAULT_CONTENT_TYPE')
@property
def FILE_CHARSET(self):
stack = traceback.extract_stack()
# Show a warning if the setting is used outside of Django.
# Stack index: -1 this line, -2 the caller.
filename, _line_number, _function_name, _text = stack[-2]
if not filename.startswith(os.path.dirname(django.__file__)):
warnings.warn(
FILE_CHARSET_DEPRECATED_MSG,
RemovedInDjango31Warning,
stacklevel=2,
)
return self.__getattr__('FILE_CHARSET')
class Settings: class Settings:
def __init__(self, settings_module): def __init__(self, settings_module):
@ -145,6 +165,8 @@ class Settings:
if self.is_overridden('DEFAULT_CONTENT_TYPE'): if self.is_overridden('DEFAULT_CONTENT_TYPE'):
warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning) warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning)
if self.is_overridden('FILE_CHARSET'):
warnings.warn(FILE_CHARSET_DEPRECATED_MSG, RemovedInDjango31Warning)
if hasattr(time, 'tzset') and self.TIME_ZONE: if hasattr(time, 'tzset') and self.TIME_ZONE:
# When we can, attempt to validate the timezone. If we can't find # When we can, attempt to validate the timezone. If we can't find
@ -191,6 +213,8 @@ class UserSettingsHolder:
self._deleted.discard(name) self._deleted.discard(name)
if name == 'DEFAULT_CONTENT_TYPE': if name == 'DEFAULT_CONTENT_TYPE':
warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning) warnings.warn(DEFAULT_CONTENT_TYPE_DEPRECATED_MSG, RemovedInDjango30Warning)
elif name == 'FILE_CHARSET':
warnings.warn(FILE_CHARSET_DEPRECATED_MSG, RemovedInDjango31Warning)
super().__setattr__(name, value) super().__setattr__(name, value)
def __delattr__(self, name): def __delattr__(self, name):

View File

@ -24,6 +24,8 @@ details on these changes.
* ``django.contrib.postgres.fields.FloatRangeField`` and * ``django.contrib.postgres.fields.FloatRangeField`` and
``django.contrib.postgres.forms.FloatRangeField`` will be removed. ``django.contrib.postgres.forms.FloatRangeField`` will be removed.
* The ``FILE_CHARSET`` setting will be removed.
.. _deprecation-removed-in-3.0: .. _deprecation-removed-in-3.0:
3.0 3.0

View File

@ -613,8 +613,7 @@ the :ref:`i18n documentation <how-to-create-language-files>` for details.
This command doesn't require configured settings. However, when settings aren't This command doesn't require configured settings. However, when settings aren't
configured, the command can't ignore the :setting:`MEDIA_ROOT` and configured, the command can't ignore the :setting:`MEDIA_ROOT` and
:setting:`STATIC_ROOT` directories or include :setting:`LOCALE_PATHS`. It will :setting:`STATIC_ROOT` directories or include :setting:`LOCALE_PATHS`.
also write files in UTF-8 rather than in :setting:`FILE_CHARSET`.
.. django-admin-option:: --all, -a .. django-admin-option:: --all, -a

View File

@ -1424,7 +1424,12 @@ attempt.
Default: ``'utf-8'`` Default: ``'utf-8'``
The character encoding used to decode any files read from disk. This includes The character encoding used to decode any files read from disk. This includes
template files and initial SQL data files. template files, static files, and translation catalogs.
.. deprecated:: 2.2
This setting is deprecated. Starting with Django 3.1, files read from disk
must be UTF-8 encoded.
.. setting:: FILE_UPLOAD_HANDLERS .. setting:: FILE_UPLOAD_HANDLERS
@ -3374,7 +3379,6 @@ Error reporting
File uploads File uploads
------------ ------------
* :setting:`DEFAULT_FILE_STORAGE` * :setting:`DEFAULT_FILE_STORAGE`
* :setting:`FILE_CHARSET`
* :setting:`FILE_UPLOAD_HANDLERS` * :setting:`FILE_UPLOAD_HANDLERS`
* :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` * :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE`
* :setting:`FILE_UPLOAD_PERMISSIONS` * :setting:`FILE_UPLOAD_PERMISSIONS`

View File

@ -265,12 +265,11 @@ Use strings when creating templates manually::
from django.template import Template from django.template import Template
t2 = Template('This is a string template.') t2 = Template('This is a string template.')
But the common case is to read templates from the filesystem, and this creates But the common case is to read templates from the filesystem. If your template
a slight complication: not all filesystems store their data encoded as UTF-8. files are not stored with a UTF-8 encoding, adjust the :setting:`TEMPLATES`
If your template files are not stored with a UTF-8 encoding, set the :setting:`FILE_CHARSET` setting. The built-in :py:mod:`~django.template.backends.django` backend
setting to the encoding of the files on disk. When Django reads in a template provides the ``'file_charset'`` option to change the encoding used to read
file, it will convert the data from this encoding to Unicode. (:setting:`FILE_CHARSET` files from disk.
is set to ``'utf-8'`` by default.)
The :setting:`DEFAULT_CHARSET` setting controls the encoding of rendered templates. The :setting:`DEFAULT_CHARSET` setting controls the encoding of rendered templates.
This is set to UTF-8 by default. This is set to UTF-8 by default.

View File

@ -332,3 +332,6 @@ Miscellaneous
* The ``FloatRangeField`` model and form fields in ``django.contrib.postgres`` * The ``FloatRangeField`` model and form fields in ``django.contrib.postgres``
are deprecated in favor of a new name, ``DecimalRangeField``, to match the are deprecated in favor of a new name, ``DecimalRangeField``, to match the
underlying ``numrange`` data type used in the database. underlying ``numrange`` data type used in the database.
* The ``FILE_CHARSET`` setting is deprecated. Starting with Django 3.1, files
read from disk must be UTF-8 encoded.

View File

@ -351,7 +351,7 @@ applications. This generic name was kept for backwards-compatibility.
* ``'file_charset'``: the charset used to read template files on disk. * ``'file_charset'``: the charset used to read template files on disk.
It defaults to the value of :setting:`FILE_CHARSET`. It defaults to ``'utf-8'``.
* ``'libraries'``: A dictionary of labels and dotted Python paths of template * ``'libraries'``: A dictionary of labels and dotted Python paths of template
tag modules to register with the template engine. This can be used to add tag modules to register with the template engine. This can be used to add

View File

@ -0,0 +1,40 @@
import sys
from types import ModuleType
from django.conf import FILE_CHARSET_DEPRECATED_MSG, Settings, settings
from django.test import SimpleTestCase, ignore_warnings
from django.utils.deprecation import RemovedInDjango31Warning
class DeprecationTests(SimpleTestCase):
msg = FILE_CHARSET_DEPRECATED_MSG
def test_override_settings_warning(self):
with self.assertRaisesMessage(RemovedInDjango31Warning, self.msg):
with self.settings(FILE_CHARSET='latin1'):
pass
def test_settings_init_warning(self):
settings_module = ModuleType('fake_settings_module')
settings_module.FILE_CHARSET = 'latin1'
settings_module.SECRET_KEY = 'ABC'
sys.modules['fake_settings_module'] = settings_module
try:
with self.assertRaisesMessage(RemovedInDjango31Warning, self.msg):
Settings('fake_settings_module')
finally:
del sys.modules['fake_settings_module']
def test_access_warning(self):
with self.assertRaisesMessage(RemovedInDjango31Warning, self.msg):
settings.FILE_CHARSET
# Works a second time.
with self.assertRaisesMessage(RemovedInDjango31Warning, self.msg):
settings.FILE_CHARSET
@ignore_warnings(category=RemovedInDjango31Warning)
def test_access(self):
with self.settings(FILE_CHARSET='latin1'):
self.assertEqual(settings.FILE_CHARSET, 'latin1')
# Works a second time.
self.assertEqual(settings.FILE_CHARSET, 'latin1')