mirror of https://github.com/django/django.git
Refs #31670 -- Renamed whitelist argument and attribute of EmailValidator.
This commit is contained in:
parent
26a413507a
commit
27c09043da
|
@ -1,10 +1,12 @@
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import re
|
import re
|
||||||
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from urllib.parse import urlsplit, urlunsplit
|
from urllib.parse import urlsplit, urlunsplit
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.utils.deconstruct import deconstructible
|
from django.utils.deconstruct import deconstructible
|
||||||
|
from django.utils.deprecation import RemovedInDjango41Warning
|
||||||
from django.utils.encoding import punycode
|
from django.utils.encoding import punycode
|
||||||
from django.utils.ipv6 import is_valid_ipv6_address
|
from django.utils.ipv6 import is_valid_ipv6_address
|
||||||
from django.utils.regex_helper import _lazy_re_compile
|
from django.utils.regex_helper import _lazy_re_compile
|
||||||
|
@ -167,15 +169,42 @@ class EmailValidator:
|
||||||
# literal form, ipv4 or ipv6 address (SMTP 4.1.3)
|
# literal form, ipv4 or ipv6 address (SMTP 4.1.3)
|
||||||
r'\[([A-f0-9:.]+)\]\Z',
|
r'\[([A-f0-9:.]+)\]\Z',
|
||||||
re.IGNORECASE)
|
re.IGNORECASE)
|
||||||
domain_whitelist = ['localhost']
|
domain_allowlist = ['localhost']
|
||||||
|
|
||||||
def __init__(self, message=None, code=None, whitelist=None):
|
@property
|
||||||
|
def domain_whitelist(self):
|
||||||
|
warnings.warn(
|
||||||
|
'The domain_whitelist attribute is deprecated in favor of '
|
||||||
|
'domain_allowlist.',
|
||||||
|
RemovedInDjango41Warning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
return self.domain_allowlist
|
||||||
|
|
||||||
|
@domain_whitelist.setter
|
||||||
|
def domain_whitelist(self, allowlist):
|
||||||
|
warnings.warn(
|
||||||
|
'The domain_whitelist attribute is deprecated in favor of '
|
||||||
|
'domain_allowlist.',
|
||||||
|
RemovedInDjango41Warning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
self.domain_allowlist = allowlist
|
||||||
|
|
||||||
|
def __init__(self, message=None, code=None, allowlist=None, *, whitelist=None):
|
||||||
|
if whitelist is not None:
|
||||||
|
allowlist = whitelist
|
||||||
|
warnings.warn(
|
||||||
|
'The whitelist argument is deprecated in favor of allowlist.',
|
||||||
|
RemovedInDjango41Warning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
if message is not None:
|
if message is not None:
|
||||||
self.message = message
|
self.message = message
|
||||||
if code is not None:
|
if code is not None:
|
||||||
self.code = code
|
self.code = code
|
||||||
if whitelist is not None:
|
if allowlist is not None:
|
||||||
self.domain_whitelist = whitelist
|
self.domain_allowlist = allowlist
|
||||||
|
|
||||||
def __call__(self, value):
|
def __call__(self, value):
|
||||||
if not value or '@' not in value:
|
if not value or '@' not in value:
|
||||||
|
@ -186,7 +215,7 @@ class EmailValidator:
|
||||||
if not self.user_regex.match(user_part):
|
if not self.user_regex.match(user_part):
|
||||||
raise ValidationError(self.message, code=self.code)
|
raise ValidationError(self.message, code=self.code)
|
||||||
|
|
||||||
if (domain_part not in self.domain_whitelist and
|
if (domain_part not in self.domain_allowlist and
|
||||||
not self.validate_domain_part(domain_part)):
|
not self.validate_domain_part(domain_part)):
|
||||||
# Try for possible IDN domain-part
|
# Try for possible IDN domain-part
|
||||||
try:
|
try:
|
||||||
|
@ -215,7 +244,7 @@ class EmailValidator:
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (
|
return (
|
||||||
isinstance(other, EmailValidator) and
|
isinstance(other, EmailValidator) and
|
||||||
(self.domain_whitelist == other.domain_whitelist) and
|
(self.domain_allowlist == other.domain_allowlist) and
|
||||||
(self.message == other.message) and
|
(self.message == other.message) and
|
||||||
(self.code == other.code)
|
(self.code == other.code)
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,6 +21,9 @@ details on these changes.
|
||||||
|
|
||||||
* ``BaseCommand.requires_system_checks`` won't support boolean values.
|
* ``BaseCommand.requires_system_checks`` won't support boolean values.
|
||||||
|
|
||||||
|
* The ``whitelist`` argument and ``domain_whitelist`` attribute of
|
||||||
|
``django.core.validators.EmailValidator`` will be removed.
|
||||||
|
|
||||||
.. _deprecation-removed-in-4.0:
|
.. _deprecation-removed-in-4.0:
|
||||||
|
|
||||||
4.0
|
4.0
|
||||||
|
|
|
@ -119,11 +119,11 @@ to, or in lieu of custom ``field.clean()`` methods.
|
||||||
``EmailValidator``
|
``EmailValidator``
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
.. class:: EmailValidator(message=None, code=None, whitelist=None)
|
.. class:: EmailValidator(message=None, code=None, allowlist=None)
|
||||||
|
|
||||||
:param message: If not ``None``, overrides :attr:`.message`.
|
:param message: If not ``None``, overrides :attr:`.message`.
|
||||||
:param code: If not ``None``, overrides :attr:`code`.
|
:param code: If not ``None``, overrides :attr:`code`.
|
||||||
:param whitelist: If not ``None``, overrides :attr:`whitelist`.
|
:param allowlist: If not ``None``, overrides :attr:`allowlist`.
|
||||||
|
|
||||||
.. attribute:: message
|
.. attribute:: message
|
||||||
|
|
||||||
|
@ -136,14 +136,22 @@ to, or in lieu of custom ``field.clean()`` methods.
|
||||||
The error code used by :exc:`~django.core.exceptions.ValidationError`
|
The error code used by :exc:`~django.core.exceptions.ValidationError`
|
||||||
if validation fails. Defaults to ``"invalid"``.
|
if validation fails. Defaults to ``"invalid"``.
|
||||||
|
|
||||||
.. attribute:: whitelist
|
.. attribute:: allowlist
|
||||||
|
|
||||||
Whitelist of email domains to allow. By default, a regular expression
|
Allowlist of email domains. By default, a regular expression (the
|
||||||
(the ``domain_regex`` attribute) is used to validate whatever appears
|
``domain_regex`` attribute) is used to validate whatever appears after
|
||||||
after the @ sign. However, if that string appears in the whitelist, this
|
the ``@`` sign. However, if that string appears in the ``allowlist``,
|
||||||
validation is bypassed. If not provided, the default whitelist is
|
this validation is bypassed. If not provided, the default ``allowlist``
|
||||||
``['localhost']``. Other domains that don't contain a dot won't pass
|
is ``['localhost']``. Other domains that don't contain a dot won't pass
|
||||||
validation, so you'd need to whitelist them as necessary.
|
validation, so you'd need to add them to the ``allowlist`` as
|
||||||
|
necessary.
|
||||||
|
|
||||||
|
.. deprecated:: 3.2
|
||||||
|
|
||||||
|
The ``whitelist`` parameter is deprecated. Use :attr:`allowlist`
|
||||||
|
instead.
|
||||||
|
The undocumented ``domain_whitelist`` attribute is deprecated. Use
|
||||||
|
``domain_allowlist`` instead.
|
||||||
|
|
||||||
``URLValidator``
|
``URLValidator``
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -351,3 +351,9 @@ Miscellaneous
|
||||||
* Using a boolean value in :attr:`.BaseCommand.requires_system_checks` is
|
* Using a boolean value in :attr:`.BaseCommand.requires_system_checks` is
|
||||||
deprecated. Use ``'__all__'`` instead of ``True``, and ``[]`` (an empty list)
|
deprecated. Use ``'__all__'`` instead of ``True``, and ``[]`` (an empty list)
|
||||||
instead of ``False``.
|
instead of ``False``.
|
||||||
|
|
||||||
|
* The ``whitelist`` argument and ``domain_whitelist`` attribute of
|
||||||
|
:class:`~django.core.validators.EmailValidator` are deprecated. Use
|
||||||
|
``allowlist`` instead of ``whitelist``, and ``domain_allowlist`` instead of
|
||||||
|
``domain_whitelist``. You may need to rename ``whitelist`` in existing
|
||||||
|
migrations.
|
||||||
|
|
|
@ -10,6 +10,7 @@ affordances
|
||||||
aggregator
|
aggregator
|
||||||
Ai
|
Ai
|
||||||
Alchin
|
Alchin
|
||||||
|
allowlist
|
||||||
alphanumerics
|
alphanumerics
|
||||||
amet
|
amet
|
||||||
analytics
|
analytics
|
||||||
|
@ -780,7 +781,6 @@ vertices
|
||||||
viewable
|
viewable
|
||||||
virtualized
|
virtualized
|
||||||
Weblog
|
Weblog
|
||||||
whitelist
|
|
||||||
whitespace
|
whitespace
|
||||||
whitespaces
|
whitespaces
|
||||||
whizbang
|
whizbang
|
||||||
|
|
|
@ -16,7 +16,8 @@ from django.core.validators import (
|
||||||
validate_ipv4_address, validate_ipv6_address, validate_ipv46_address,
|
validate_ipv4_address, validate_ipv6_address, validate_ipv46_address,
|
||||||
validate_slug, validate_unicode_slug,
|
validate_slug, validate_unicode_slug,
|
||||||
)
|
)
|
||||||
from django.test import SimpleTestCase
|
from django.test import SimpleTestCase, ignore_warnings
|
||||||
|
from django.utils.deprecation import RemovedInDjango41Warning
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import Image # noqa
|
from PIL import Image # noqa
|
||||||
|
@ -50,7 +51,7 @@ TEST_DATA = [
|
||||||
(validate_email, 'example@valid-with-hyphens.com', None),
|
(validate_email, 'example@valid-with-hyphens.com', None),
|
||||||
(validate_email, 'test@domain.with.idn.tld.उदाहरण.परीक्षा', None),
|
(validate_email, 'test@domain.with.idn.tld.उदाहरण.परीक्षा', None),
|
||||||
(validate_email, 'email@localhost', None),
|
(validate_email, 'email@localhost', None),
|
||||||
(EmailValidator(whitelist=['localdomain']), 'email@localdomain', None),
|
(EmailValidator(allowlist=['localdomain']), 'email@localdomain', None),
|
||||||
(validate_email, '"test@test"@example.com', None),
|
(validate_email, '"test@test"@example.com', None),
|
||||||
(validate_email, 'example@atm.%s' % ('a' * 63), None),
|
(validate_email, 'example@atm.%s' % ('a' * 63), None),
|
||||||
(validate_email, 'example@%s.atm' % ('a' * 63), None),
|
(validate_email, 'example@%s.atm' % ('a' * 63), None),
|
||||||
|
@ -510,3 +511,42 @@ class TestValidatorEquality(TestCase):
|
||||||
ProhibitNullCharactersValidator(message='message', code='code1'),
|
ProhibitNullCharactersValidator(message='message', code='code1'),
|
||||||
ProhibitNullCharactersValidator(message='message', code='code2')
|
ProhibitNullCharactersValidator(message='message', code='code2')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DeprecationTests(SimpleTestCase):
|
||||||
|
@ignore_warnings(category=RemovedInDjango41Warning)
|
||||||
|
def test_whitelist(self):
|
||||||
|
validator = EmailValidator(whitelist=['localdomain'])
|
||||||
|
self.assertEqual(validator.domain_allowlist, ['localdomain'])
|
||||||
|
self.assertIsNone(validator('email@localdomain'))
|
||||||
|
self.assertEqual(validator.domain_allowlist, validator.domain_whitelist)
|
||||||
|
|
||||||
|
def test_whitelist_warning(self):
|
||||||
|
msg = "The whitelist argument is deprecated in favor of allowlist."
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
|
||||||
|
EmailValidator(whitelist='localdomain')
|
||||||
|
|
||||||
|
@ignore_warnings(category=RemovedInDjango41Warning)
|
||||||
|
def test_domain_whitelist(self):
|
||||||
|
validator = EmailValidator()
|
||||||
|
validator.domain_whitelist = ['mydomain']
|
||||||
|
self.assertEqual(validator.domain_allowlist, ['mydomain'])
|
||||||
|
self.assertEqual(validator.domain_allowlist, validator.domain_whitelist)
|
||||||
|
|
||||||
|
def test_domain_whitelist_access_warning(self):
|
||||||
|
validator = EmailValidator()
|
||||||
|
msg = (
|
||||||
|
'The domain_whitelist attribute is deprecated in favor of '
|
||||||
|
'domain_allowlist.'
|
||||||
|
)
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
|
||||||
|
validator.domain_whitelist
|
||||||
|
|
||||||
|
def test_domain_whitelist_set_warning(self):
|
||||||
|
validator = EmailValidator()
|
||||||
|
msg = (
|
||||||
|
'The domain_whitelist attribute is deprecated in favor of '
|
||||||
|
'domain_allowlist.'
|
||||||
|
)
|
||||||
|
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
|
||||||
|
validator.domain_whitelist = ['mydomain']
|
||||||
|
|
Loading…
Reference in New Issue