Skip to content

Commit

Permalink
Merge branch 'main' into bpo-21360-Maildir-leading-dot
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiy-storchaka committed Dec 15, 2023
2 parents 6e137a3 + 4a153a1 commit 44e5ea2
Show file tree
Hide file tree
Showing 24 changed files with 892 additions and 585 deletions.
19 changes: 15 additions & 4 deletions Doc/library/email.utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,18 @@ of the new API.
begins with angle brackets, they are stripped off.


.. function:: parseaddr(address)
.. function:: parseaddr(address, *, strict=True)

Parse address -- which should be the value of some address-containing field such
as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and
*email address* parts. Returns a tuple of that information, unless the parse
fails, in which case a 2-tuple of ``('', '')`` is returned.

If *strict* is true, use a strict parser which rejects malformed inputs.

.. versionchanged:: 3.13
Add *strict* optional parameter and reject malformed inputs by default.


.. function:: formataddr(pair, charset='utf-8')

Expand All @@ -82,12 +87,15 @@ of the new API.
Added the *charset* option.


.. function:: getaddresses(fieldvalues)
.. function:: getaddresses(fieldvalues, *, strict=True)

This method returns a list of 2-tuples of the form returned by ``parseaddr()``.
*fieldvalues* is a sequence of header field values as might be returned by
:meth:`Message.get_all <email.message.Message.get_all>`. Here's a simple
example that gets all the recipients of a message::
:meth:`Message.get_all <email.message.Message.get_all>`.

If *strict* is true, use a strict parser which rejects malformed inputs.

Here's a simple example that gets all the recipients of a message::

from email.utils import getaddresses

Expand All @@ -97,6 +105,9 @@ of the new API.
resent_ccs = msg.get_all('resent-cc', [])
all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)

.. versionchanged:: 3.13
Add *strict* optional parameter and reject malformed inputs by default.


.. function:: parsedate(date)

Expand Down
66 changes: 34 additions & 32 deletions Doc/library/itertools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,8 @@ which incur interpreter overhead.
"List unique elements, preserving order. Remember only the element just seen."
# unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
# unique_justseen('ABBcCAD', str.lower) --> A B c A D
if key is None:
return map(operator.itemgetter(0), groupby(iterable))
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))


Expand Down Expand Up @@ -1136,24 +1138,6 @@ The following recipes have a more mathematical flavor:
n = n // p * (p - 1)
return n

def nth_combination(iterable, r, index):
"Equivalent to list(combinations(iterable, r))[index]"
pool = tuple(iterable)
n = len(pool)
c = math.comb(n, r)
if index < 0:
index += c
if index < 0 or index >= c:
raise IndexError
result = []
while r:
c, n, r = c*r//n, n-1, r-1
while index >= c:
index -= c
c, n = c*(n-r)//n, n-1
result.append(pool[-1-n])
return tuple(result)


.. doctest::
:hide:
Expand Down Expand Up @@ -1577,20 +1561,6 @@ The following recipes have a more mathematical flavor:
>>> first_true('ABC0DEF1', '9', str.isdigit)
'0'

>>> population = 'ABCDEFGH'
>>> for r in range(len(population) + 1):
... seq = list(combinations(population, r))
... for i in range(len(seq)):
... assert nth_combination(population, r, i) == seq[i]
... for i in range(-len(seq), 0):
... assert nth_combination(population, r, i) == seq[i]

>>> iterable = 'abcde'
>>> r = 3
>>> combos = list(combinations(iterable, r))
>>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos))
True


.. testcode::
:hide:
Expand All @@ -1617,6 +1587,24 @@ The following recipes have a more mathematical flavor:
for (a, _), (b, c) in pairwise(pairwise(iterable)):
yield a, b, c

def nth_combination(iterable, r, index):
"Equivalent to list(combinations(iterable, r))[index]"
pool = tuple(iterable)
n = len(pool)
c = math.comb(n, r)
if index < 0:
index += c
if index < 0 or index >= c:
raise IndexError
result = []
while r:
c, n, r = c*r//n, n-1, r-1
while index >= c:
index -= c
c, n = c*(n-r)//n, n-1
result.append(pool[-1-n])
return tuple(result)


.. doctest::
:hide:
Expand All @@ -1632,3 +1620,17 @@ The following recipes have a more mathematical flavor:

>>> list(triplewise('ABCDEFG'))
[('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')]

>>> population = 'ABCDEFGH'
>>> for r in range(len(population) + 1):
... seq = list(combinations(population, r))
... for i in range(len(seq)):
... assert nth_combination(population, r, i) == seq[i]
... for i in range(-len(seq), 0):
... assert nth_combination(population, r, i) == seq[i]

>>> iterable = 'abcde'
>>> r = 3
>>> combos = list(combinations(iterable, r))
>>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos))
True
Loading

0 comments on commit 44e5ea2

Please sign in to comment.