Reformat code with automated tools

Apply standardized code style
This commit is contained in:
medmunds
2023-02-06 12:27:43 -08:00
committed by Mike Edmunds
parent 40891fcb4a
commit b4e22c63b3
94 changed files with 12936 additions and 7443 deletions

View File

@@ -7,18 +7,28 @@ from email.mime.image import MIMEImage
from email.mime.text import MIMEText
from django.http import QueryDict
from django.test import SimpleTestCase, RequestFactory, override_settings
from django.test import RequestFactory, SimpleTestCase, override_settings
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy
from anymail.exceptions import AnymailInvalidAddress, _LazyError
from anymail.utils import (
parse_address_list, parse_single_address, EmailAddress,
UNSET,
Attachment,
is_lazy, force_non_lazy, force_non_lazy_dict, force_non_lazy_list,
update_deep, UNSET,
get_request_uri, get_request_basic_auth, parse_rfc2822date, querydict_getfirst,
CaseInsensitiveCasePreservingDict)
CaseInsensitiveCasePreservingDict,
EmailAddress,
force_non_lazy,
force_non_lazy_dict,
force_non_lazy_list,
get_request_basic_auth,
get_request_uri,
is_lazy,
parse_address_list,
parse_rfc2822date,
parse_single_address,
querydict_getfirst,
update_deep,
)
class ParseAddressListTests(SimpleTestCase):
@@ -48,36 +58,46 @@ class ParseAddressListTests(SimpleTestCase):
def test_obsolete_display_name(self):
# you can get away without the quotes if there are no commas or parens
# (but it's not recommended)
parsed_list = parse_address_list(['Display Name <test@example.com>'])
parsed_list = parse_address_list(["Display Name <test@example.com>"])
self.assertEqual(len(parsed_list), 1)
parsed = parsed_list[0]
self.assertEqual(parsed.addr_spec, "test@example.com")
self.assertEqual(parsed.display_name, "Display Name")
self.assertEqual(parsed.address, 'Display Name <test@example.com>')
self.assertEqual(parsed.address, "Display Name <test@example.com>")
def test_unicode_display_name(self):
parsed_list = parse_address_list(['"Unicode \N{HEAVY BLACK HEART}" <test@example.com>'])
parsed_list = parse_address_list(
['"Unicode \N{HEAVY BLACK HEART}" <test@example.com>']
)
self.assertEqual(len(parsed_list), 1)
parsed = parsed_list[0]
self.assertEqual(parsed.addr_spec, "test@example.com")
self.assertEqual(parsed.display_name, "Unicode \N{HEAVY BLACK HEART}")
# formatted display-name automatically shifts to quoted-printable/base64 for non-ascii chars:
self.assertEqual(parsed.address, '=?utf-8?b?VW5pY29kZSDinaQ=?= <test@example.com>')
# formatted display-name automatically shifts
# to quoted-printable/base64 for non-ascii chars:
self.assertEqual(
parsed.address, "=?utf-8?b?VW5pY29kZSDinaQ=?= <test@example.com>"
)
def test_invalid_display_name(self):
with self.assertRaisesMessage(AnymailInvalidAddress, "Invalid email address 'webmaster'"):
parse_address_list(['webmaster'])
with self.assertRaisesMessage(
AnymailInvalidAddress, "Invalid email address 'webmaster'"
):
parse_address_list(["webmaster"])
with self.assertRaisesMessage(AnymailInvalidAddress, "Maybe missing quotes around a display-name?"):
with self.assertRaisesMessage(
AnymailInvalidAddress, "Maybe missing quotes around a display-name?"
):
# this parses as multiple email addresses, because of the comma:
parse_address_list(['Display Name, Inc. <test@example.com>'])
parse_address_list(["Display Name, Inc. <test@example.com>"])
def test_idn(self):
parsed_list = parse_address_list(["idn@\N{ENVELOPE}.example.com"])
self.assertEqual(len(parsed_list), 1)
parsed = parsed_list[0]
self.assertEqual(parsed.addr_spec, "idn@\N{ENVELOPE}.example.com")
self.assertEqual(parsed.address, "idn@xn--4bi.example.com") # punycode-encoded domain
# punycode-encoded domain:
self.assertEqual(parsed.address, "idn@xn--4bi.example.com")
self.assertEqual(parsed.username, "idn")
self.assertEqual(parsed.domain, "\N{ENVELOPE}.example.com")
@@ -88,23 +108,23 @@ class ParseAddressListTests(SimpleTestCase):
def test_empty_address(self):
with self.assertRaises(AnymailInvalidAddress):
parse_address_list([''])
parse_address_list([""])
def test_whitespace_only_address(self):
with self.assertRaises(AnymailInvalidAddress):
parse_address_list([' '])
parse_address_list([" "])
def test_invalid_address(self):
with self.assertRaises(AnymailInvalidAddress):
parse_address_list(['localonly'])
parse_address_list(["localonly"])
with self.assertRaises(AnymailInvalidAddress):
parse_address_list(['localonly@'])
parse_address_list(["localonly@"])
with self.assertRaises(AnymailInvalidAddress):
parse_address_list(['@domainonly'])
parse_address_list(["@domainonly"])
with self.assertRaises(AnymailInvalidAddress):
parse_address_list(['<localonly@>'])
parse_address_list(["<localonly@>"])
with self.assertRaises(AnymailInvalidAddress):
parse_address_list(['<@domainonly>'])
parse_address_list(["<@domainonly>"])
def test_email_list(self):
parsed_list = parse_address_list(["first@example.com", "second@example.com"])
@@ -126,11 +146,12 @@ class ParseAddressListTests(SimpleTestCase):
# the bare "Display Name" below should *not* get merged with
# the email in the second item
with self.assertRaisesMessage(AnymailInvalidAddress, "Display Name"):
parse_address_list(['"Display Name"', '<valid@example.com>'])
parse_address_list(['"Display Name"', "<valid@example.com>"])
def test_invalid_with_unicode(self):
with self.assertRaisesMessage(AnymailInvalidAddress,
"Invalid email address '\N{ENVELOPE}'"):
with self.assertRaisesMessage(
AnymailInvalidAddress, "Invalid email address '\N{ENVELOPE}'"
):
parse_address_list(["\N{ENVELOPE}"])
def test_single_string(self):
@@ -140,7 +161,9 @@ class ParseAddressListTests(SimpleTestCase):
self.assertEqual(parsed_list[0].addr_spec, "one@example.com")
def test_lazy_strings(self):
parsed_list = parse_address_list([gettext_lazy('"Example, Inc." <one@example.com>')])
parsed_list = parse_address_list(
[gettext_lazy('"Example, Inc." <one@example.com>')]
)
self.assertEqual(len(parsed_list), 1)
self.assertEqual(parsed_list[0].display_name, "Example, Inc.")
self.assertEqual(parsed_list[0].addr_spec, "one@example.com")
@@ -154,7 +177,9 @@ class ParseAddressListTests(SimpleTestCase):
parsed = parse_single_address("one@example.com")
self.assertEqual(parsed.address, "one@example.com")
with self.assertRaisesMessage(AnymailInvalidAddress, "Only one email address is allowed; found 2"):
with self.assertRaisesMessage(
AnymailInvalidAddress, "Only one email address is allowed; found 2"
):
parse_single_address("one@example.com, two@example.com")
with self.assertRaisesMessage(AnymailInvalidAddress, "Invalid email address"):
@@ -174,8 +199,10 @@ class ParseAddressListTests(SimpleTestCase):
_ = EmailAddress(name, addr)
def test_email_address_repr(self):
self.assertEqual("EmailAddress('Name', 'addr@example.com')",
repr(EmailAddress('Name', 'addr@example.com')))
self.assertEqual(
"EmailAddress('Name', 'addr@example.com')",
repr(EmailAddress("Name", "addr@example.com")),
)
class NormalizedAttachmentTests(SimpleTestCase):
@@ -192,25 +219,32 @@ class NormalizedAttachmentTests(SimpleTestCase):
self.assertFalse(att.inline)
self.assertIsNone(att.content_id)
self.assertEqual(att.cid, "")
self.assertEqual(repr(att), "Attachment<image/x-emoticon, len=3, name='emoticon.txt'>")
self.assertEqual(
repr(att), "Attachment<image/x-emoticon, len=3, name='emoticon.txt'>"
)
def test_content_disposition_inline(self):
image = MIMEImage(b";-)", "x-emoticon")
image["Content-Disposition"] = 'inline'
image["Content-Disposition"] = "inline"
att = Attachment(image, "ascii")
self.assertIsNone(att.name)
self.assertEqual(att.content, b";-)")
self.assertTrue(att.inline) # even without the Content-ID
self.assertIsNone(att.content_id)
self.assertEqual(att.cid, "")
self.assertEqual(repr(att), "Attachment<inline, image/x-emoticon, len=3, content_id=None>")
self.assertEqual(
repr(att), "Attachment<inline, image/x-emoticon, len=3, content_id=None>"
)
image["Content-ID"] = "<abc123@example.net>"
att = Attachment(image, "ascii")
self.assertEqual(att.content_id, "<abc123@example.net>")
self.assertEqual(att.cid, "abc123@example.net")
self.assertEqual(repr(att),
"Attachment<inline, image/x-emoticon, len=3, content_id='<abc123@example.net>'>")
self.assertEqual(
repr(att),
"Attachment<inline, image/x-emoticon, len=3,"
" content_id='<abc123@example.net>'>",
)
def test_content_id_implies_inline(self):
"""A MIME object with a Content-ID should be assumed to be inline"""
@@ -219,8 +253,11 @@ class NormalizedAttachmentTests(SimpleTestCase):
att = Attachment(image, "ascii")
self.assertTrue(att.inline)
self.assertEqual(att.content_id, "<abc123@example.net>")
self.assertEqual(repr(att),
"Attachment<inline, image/x-emoticon, len=3, content_id='<abc123@example.net>'>")
self.assertEqual(
repr(att),
"Attachment<inline, image/x-emoticon, len=3,"
" content_id='<abc123@example.net>'>",
)
# ... but not if explicit Content-Disposition says otherwise
image["Content-Disposition"] = "attachment"
@@ -246,7 +283,7 @@ class LazyCoercionTests(SimpleTestCase):
self.assertFalse(is_lazy("text not lazy"))
self.assertFalse(is_lazy(b"bytes not lazy"))
self.assertFalse(is_lazy(None))
self.assertFalse(is_lazy({'dict': "not lazy"}))
self.assertFalse(is_lazy({"dict": "not lazy"}))
self.assertFalse(is_lazy(["list", "not lazy"]))
self.assertFalse(is_lazy(object()))
self.assertFalse(is_lazy([gettext_lazy("doesn't recurse")]))
@@ -257,10 +294,20 @@ class LazyCoercionTests(SimpleTestCase):
self.assertEqual(result, "text")
def test_format_lazy(self):
self.assertTrue(is_lazy(format_lazy("{0}{1}",
gettext_lazy("concatenation"), gettext_lazy("is lazy"))))
result = force_non_lazy(format_lazy("{first}/{second}",
first=gettext_lazy("text"), second=gettext_lazy("format")))
self.assertTrue(
is_lazy(
format_lazy(
"{0}{1}", gettext_lazy("concatenation"), gettext_lazy("is lazy")
)
)
)
result = force_non_lazy(
format_lazy(
"{first}/{second}",
first=gettext_lazy("text"),
second=gettext_lazy("format"),
)
)
self.assertIsInstance(result, str)
self.assertEqual(result, "text/format")
@@ -279,11 +326,12 @@ class LazyCoercionTests(SimpleTestCase):
self.assertIsNone(result)
def test_force_dict(self):
result = force_non_lazy_dict({'a': 1, 'b': gettext_lazy("b"),
'c': {'c1': gettext_lazy("c1")}})
self.assertEqual(result, {'a': 1, 'b': "b", 'c': {'c1': "c1"}})
self.assertIsInstance(result['b'], str)
self.assertIsInstance(result['c']['c1'], str)
result = force_non_lazy_dict(
{"a": 1, "b": gettext_lazy("b"), "c": {"c1": gettext_lazy("c1")}}
)
self.assertEqual(result, {"a": 1, "b": "b", "c": {"c1": "c1"}})
self.assertIsInstance(result["b"], str)
self.assertIsInstance(result["c"]["c1"], str)
def test_force_list(self):
result = force_non_lazy_list([0, gettext_lazy("b"), "c"])
@@ -295,26 +343,28 @@ class UpdateDeepTests(SimpleTestCase):
"""Test utils.update_deep"""
def test_updates_recursively(self):
first = {'a': {'a1': 1, 'aa': {}}, 'b': "B"}
second = {'a': {'a2': 2, 'aa': {'aa1': 11}}}
first = {"a": {"a1": 1, "aa": {}}, "b": "B"}
second = {"a": {"a2": 2, "aa": {"aa1": 11}}}
result = update_deep(first, second)
self.assertEqual(first, {'a': {'a1': 1, 'a2': 2, 'aa': {'aa1': 11}}, 'b': "B"})
self.assertIsNone(result) # modifies first in place; doesn't return it (same as dict.update())
self.assertEqual(first, {"a": {"a1": 1, "a2": 2, "aa": {"aa1": 11}}, "b": "B"})
# modifies first in place; doesn't return it (same as dict.update()):
self.assertIsNone(result)
def test_overwrites_sequences(self):
"""Only mappings are handled recursively; sequences are considered atomic"""
first = {'a': [1, 2]}
second = {'a': [3]}
first = {"a": [1, 2]}
second = {"a": [3]}
update_deep(first, second)
self.assertEqual(first, {'a': [3]})
self.assertEqual(first, {"a": [3]})
def test_handles_non_dict_mappings(self):
"""Mapping types in general are supported"""
from collections import OrderedDict, defaultdict
first = OrderedDict(a=OrderedDict(a1=1), c={'c1': 1})
first = OrderedDict(a=OrderedDict(a1=1), c={"c1": 1})
second = defaultdict(None, a=dict(a2=2))
update_deep(first, second)
self.assertEqual(first, {'a': {'a1': 1, 'a2': 2}, 'c': {'c1': 1}})
self.assertEqual(first, {"a": {"a1": 1, "a2": 2}, "c": {"c1": 1}})
@override_settings(ALLOWED_HOSTS=[".example.com"])
@@ -327,68 +377,89 @@ class RequestUtilsTests(SimpleTestCase):
@staticmethod
def basic_auth(username, password):
"""Return HTTP_AUTHORIZATION header value for basic auth with username, password"""
credentials = base64.b64encode("{}:{}".format(username, password).encode('utf-8')).decode('utf-8')
"""
Return HTTP_AUTHORIZATION header value for basic auth with username, password
"""
credentials = base64.b64encode(
"{}:{}".format(username, password).encode("utf-8")
).decode("utf-8")
return "Basic {}".format(credentials)
def test_get_request_basic_auth(self):
# without auth:
request = self.request_factory.post('/path/to/?query',
HTTP_HOST='www.example.com',
HTTP_SCHEME='https')
request = self.request_factory.post(
"/path/to/?query", HTTP_HOST="www.example.com", HTTP_SCHEME="https"
)
self.assertIsNone(get_request_basic_auth(request))
# with basic auth:
request = self.request_factory.post('/path/to/?query',
HTTP_HOST='www.example.com',
HTTP_AUTHORIZATION=self.basic_auth('user', 'pass'))
request = self.request_factory.post(
"/path/to/?query",
HTTP_HOST="www.example.com",
HTTP_AUTHORIZATION=self.basic_auth("user", "pass"),
)
self.assertEqual(get_request_basic_auth(request), "user:pass")
# with some other auth
request = self.request_factory.post('/path/to/?query',
HTTP_HOST='www.example.com',
HTTP_AUTHORIZATION="Bearer abcde12345")
request = self.request_factory.post(
"/path/to/?query",
HTTP_HOST="www.example.com",
HTTP_AUTHORIZATION="Bearer abcde12345",
)
self.assertIsNone(get_request_basic_auth(request))
def test_get_request_uri(self):
# without auth:
request = self.request_factory.post('/path/to/?query', secure=True,
HTTP_HOST='www.example.com')
self.assertEqual(get_request_uri(request),
"https://www.example.com/path/to/?query")
request = self.request_factory.post(
"/path/to/?query", secure=True, HTTP_HOST="www.example.com"
)
self.assertEqual(
get_request_uri(request), "https://www.example.com/path/to/?query"
)
# with basic auth:
request = self.request_factory.post('/path/to/?query', secure=True,
HTTP_HOST='www.example.com',
HTTP_AUTHORIZATION=self.basic_auth('user', 'pass'))
self.assertEqual(get_request_uri(request),
"https://user:pass@www.example.com/path/to/?query")
request = self.request_factory.post(
"/path/to/?query",
secure=True,
HTTP_HOST="www.example.com",
HTTP_AUTHORIZATION=self.basic_auth("user", "pass"),
)
self.assertEqual(
get_request_uri(request), "https://user:pass@www.example.com/path/to/?query"
)
@override_settings(SECURE_PROXY_SSL_HEADER=('HTTP_X_FORWARDED_PROTO', 'https'),
USE_X_FORWARDED_HOST=True)
@override_settings(
SECURE_PROXY_SSL_HEADER=("HTTP_X_FORWARDED_PROTO", "https"),
USE_X_FORWARDED_HOST=True,
)
def test_get_request_uri_with_proxy(self):
request = self.request_factory.post('/path/to/?query', secure=False,
HTTP_HOST='web1.internal',
HTTP_X_FORWARDED_PROTO='https',
HTTP_X_FORWARDED_HOST='secret.example.com:8989',
HTTP_AUTHORIZATION=self.basic_auth('user', 'pass'))
self.assertEqual(get_request_uri(request),
"https://user:pass@secret.example.com:8989/path/to/?query")
request = self.request_factory.post(
"/path/to/?query",
secure=False,
HTTP_HOST="web1.internal",
HTTP_X_FORWARDED_PROTO="https",
HTTP_X_FORWARDED_HOST="secret.example.com:8989",
HTTP_AUTHORIZATION=self.basic_auth("user", "pass"),
)
self.assertEqual(
get_request_uri(request),
"https://user:pass@secret.example.com:8989/path/to/?query",
)
class QueryDictUtilsTests(SimpleTestCase):
def test_querydict_getfirst(self):
q = QueryDict("a=one&a=two&a=three")
q.getfirst = querydict_getfirst.__get__(q)
self.assertEqual(q.getfirst('a'), "one")
self.assertEqual(q.getfirst("a"), "one")
# missing key exception:
with self.assertRaisesMessage(KeyError, "not a key"):
q.getfirst("not a key")
# defaults:
self.assertEqual(q.getfirst('not a key', "beta"), "beta")
self.assertIsNone(q.getfirst('not a key', None))
self.assertEqual(q.getfirst("not a key", "beta"), "beta")
self.assertIsNone(q.getfirst("not a key", None))
class ParseRFC2822DateTests(SimpleTestCase):
@@ -406,9 +477,11 @@ class ParseRFC2822DateTests(SimpleTestCase):
self.assertIsNotNone(dt.tzinfo) # aware
def test_without_timezones(self):
dt = parse_rfc2822date("Tue, 24 Oct 2017 10:11:35 -0000") # "no timezone information"
# "no timezone information":
dt = parse_rfc2822date("Tue, 24 Oct 2017 10:11:35 -0000")
self.assertEqual(dt.isoformat(), "2017-10-24T10:11:35")
self.assertIsNone(dt.tzinfo) # naive (compare with +0000 version in previous test)
# naive (compare with +0000 version in previous test):
self.assertIsNone(dt.tzinfo)
dt = parse_rfc2822date("Tue, 24 Oct 2017 10:11:35")
self.assertEqual(dt.isoformat(), "2017-10-24T10:11:35")