summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/core/checks/messages.py3
-rw-r--r--django/core/checks/registry.py9
-rw-r--r--django/core/files/storage.py3
-rw-r--r--django/core/mail/message.py14
-rw-r--r--docs/releases/4.0.txt7
-rw-r--r--tests/check_framework/tests.py20
-rw-r--r--tests/file_storage/tests.py5
-rw-r--r--tests/mail/tests.py26
8 files changed, 76 insertions, 11 deletions
diff --git a/django/core/checks/messages.py b/django/core/checks/messages.py
index aacac632eb..0987c2d118 100644
--- a/django/core/checks/messages.py
+++ b/django/core/checks/messages.py
@@ -9,7 +9,8 @@ CRITICAL = 50
class CheckMessage:
def __init__(self, level, msg, hint=None, obj=None, id=None):
- assert isinstance(level, int), "The first argument should be level."
+ if not isinstance(level, int):
+ raise TypeError('The first argument should be level.')
self.level = level
self.msg = msg
self.hint = hint
diff --git a/django/core/checks/registry.py b/django/core/checks/registry.py
index d54538e367..d7bfa49548 100644
--- a/django/core/checks/registry.py
+++ b/django/core/checks/registry.py
@@ -75,9 +75,12 @@ class CheckRegistry:
for check in checks:
new_errors = check(app_configs=app_configs, databases=databases)
- assert is_iterable(new_errors), (
- "The function %r did not return a list. All functions registered "
- "with the checks registry must return a list." % check)
+ if not is_iterable(new_errors):
+ raise TypeError(
+ 'The function %r did not return a list. All functions '
+ 'registered with the checks registry must return a list.'
+ % check,
+ )
errors.extend(new_errors)
return errors
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index 16f9d4e27b..29b0e4c9ed 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -294,7 +294,8 @@ class FileSystemStorage(Storage):
return str(name).replace('\\', '/')
def delete(self, name):
- assert name, "The name argument is not allowed to be empty."
+ if not name:
+ raise ValueError('The name must be given to delete().')
name = self.path(name)
# If the file or directory exists, delete it from the filesystem.
try:
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index 963542cd62..ccc8a769ea 100644
--- a/django/core/mail/message.py
+++ b/django/core/mail/message.py
@@ -296,11 +296,15 @@ class EmailMessage:
mimetype to DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content.
"""
if isinstance(filename, MIMEBase):
- assert content is None
- assert mimetype is None
+ if content is not None or mimetype is not None:
+ raise ValueError(
+ 'content and mimetype must not be given when a MIMEBase '
+ 'instance is provided.'
+ )
self.attachments.append(filename)
+ elif content is None:
+ raise ValueError('content must be provided.')
else:
- assert content is not None
mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE
basetype, subtype = mimetype.split('/', 1)
@@ -428,8 +432,8 @@ class EmailMultiAlternatives(EmailMessage):
def attach_alternative(self, content, mimetype):
"""Attach an alternative content representation."""
- assert content is not None
- assert mimetype is not None
+ if content is None or mimetype is None:
+ raise ValueError('Both content and mimetype must be provided.')
self.alternatives.append((content, mimetype))
def _create_message(self, msg):
diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt
index 56197115c6..6f10124c0c 100644
--- a/docs/releases/4.0.txt
+++ b/docs/releases/4.0.txt
@@ -355,6 +355,13 @@ Miscellaneous
to ``reorder_tests()``. It now accepts an iterable of tests rather than a
test suite, and returns an iterator of tests.
+* Calling ``FileSystemStorage.delete()`` with an empty ``name`` now raises
+ ``ValueError`` instead of ``AssertionError``.
+
+* Calling ``EmailMultiAlternatives.attach_alternative()`` or
+ ``EmailMessage.attach()`` with an invalid ``content`` or ``mimetype``
+ arguments now raise ``ValueError`` instead of ``AssertionError``.
+
.. _deprecated-features-4.0:
Features deprecated in 4.0
diff --git a/tests/check_framework/tests.py b/tests/check_framework/tests.py
index e669b11c2b..9e461c5040 100644
--- a/tests/check_framework/tests.py
+++ b/tests/check_framework/tests.py
@@ -4,6 +4,7 @@ from io import StringIO
from django.apps import apps
from django.core import checks
from django.core.checks import Error, Warning
+from django.core.checks.messages import CheckMessage
from django.core.checks.registry import CheckRegistry
from django.core.management import call_command
from django.core.management.base import CommandError
@@ -74,6 +75,20 @@ class SystemCheckFrameworkTests(SimpleTestCase):
def no_kwargs(app_configs, databases):
pass
+ def test_register_run_checks_non_iterable(self):
+ registry = CheckRegistry()
+
+ @registry.register
+ def return_non_iterable(**kwargs):
+ return Error('Message')
+
+ msg = (
+ 'The function %r did not return a list. All functions registered '
+ 'with the checks registry must return a list.' % return_non_iterable
+ )
+ with self.assertRaisesMessage(TypeError, msg):
+ registry.run_checks()
+
class MessageTests(SimpleTestCase):
@@ -132,6 +147,11 @@ class MessageTests(SimpleTestCase):
e = Error("Error", obj=DummyObj())
self.assertNotEqual(e, 'a string')
+ def test_invalid_level(self):
+ msg = 'The first argument should be level.'
+ with self.assertRaisesMessage(TypeError, msg):
+ CheckMessage('ERROR', 'Message')
+
def simple_system_check(**kwargs):
simple_system_check.kwargs = kwargs
diff --git a/tests/file_storage/tests.py b/tests/file_storage/tests.py
index 6d17a7118b..381bc6b7b5 100644
--- a/tests/file_storage/tests.py
+++ b/tests/file_storage/tests.py
@@ -501,7 +501,10 @@ class FileStorageTests(SimpleTestCase):
Calling delete with an empty name should not try to remove the base
storage directory, but fail loudly (#20660).
"""
- with self.assertRaises(AssertionError):
+ msg = 'The name must be given to delete().'
+ with self.assertRaisesMessage(ValueError, msg):
+ self.storage.delete(None)
+ with self.assertRaisesMessage(ValueError, msg):
self.storage.delete('')
def test_delete_deletes_directories(self):
diff --git a/tests/mail/tests.py b/tests/mail/tests.py
index 475e204b32..de8ff159c0 100644
--- a/tests/mail/tests.py
+++ b/tests/mail/tests.py
@@ -529,6 +529,24 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
self.assertEqual(content, b'\xff')
self.assertEqual(mimetype, 'application/octet-stream')
+ def test_attach_mimetext_content_mimetype(self):
+ email_msg = EmailMessage()
+ txt = MIMEText('content')
+ msg = (
+ 'content and mimetype must not be given when a MIMEBase instance '
+ 'is provided.'
+ )
+ with self.assertRaisesMessage(ValueError, msg):
+ email_msg.attach(txt, content='content')
+ with self.assertRaisesMessage(ValueError, msg):
+ email_msg.attach(txt, mimetype='text/plain')
+
+ def test_attach_content_none(self):
+ email_msg = EmailMessage()
+ msg = 'content must be provided.'
+ with self.assertRaisesMessage(ValueError, msg):
+ email_msg.attach('file.txt', mimetype="application/pdf")
+
def test_dummy_backend(self):
"""
Make sure that dummy backends returns correct number of sent messages
@@ -835,6 +853,14 @@ class MailTests(HeadersCheckMixin, SimpleTestCase):
with self.assertRaisesMessage(ValueError, msg):
sanitize_address(email_address, encoding='utf-8')
+ def test_email_multi_alternatives_content_mimetype_none(self):
+ email_msg = EmailMultiAlternatives()
+ msg = 'Both content and mimetype must be provided.'
+ with self.assertRaisesMessage(ValueError, msg):
+ email_msg.attach_alternative(None, 'text/html')
+ with self.assertRaisesMessage(ValueError, msg):
+ email_msg.attach_alternative('<p>content</p>', None)
+
@requires_tz_support
class MailTimeZoneTests(SimpleTestCase):