Skip to content

Commit 41cb98f

Browse files
committed
Merge branch 'main' into specialize-load-attr
2 parents 6d9ef8d + 309ab61 commit 41cb98f

20 files changed

+550
-295
lines changed

Doc/library/enum.rst

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ An enumeration:
2828

2929
* is a set of symbolic names (members) bound to unique values
3030
* can be iterated over to return its members in definition order
31-
* uses :meth:`call` syntax to return members by value
32-
* uses :meth:`index` syntax to return members by name
31+
* uses *call* syntax to return members by value
32+
* uses *index* syntax to return members by name
3333

3434
Enumerations are created either by using the :keyword:`class` syntax, or by
3535
using function-call syntax::
@@ -91,6 +91,12 @@ Module Contents
9191
the bitwise operators without losing their :class:`IntFlag` membership.
9292
:class:`IntFlag` members are also subclasses of :class:`int`.
9393

94+
:class:`EnumCheck`
95+
96+
An enumeration with the values ``CONTINUOUS``, ``NAMED_FLAGS``, and
97+
``UNIQUE``, for use with :func:`verify` to ensure various constraints
98+
are met by a given enumeration.
99+
94100
:class:`FlagBoundary`
95101

96102
An enumeration with the values ``STRICT``, ``CONFORM``, ``EJECT``, and
@@ -117,9 +123,14 @@ Module Contents
117123

118124
Enum class decorator that ensures only one name is bound to any one value.
119125

126+
:func:`verify`
127+
128+
Enum class decorator that checks user-selectable constraints on an
129+
enumeration.
130+
120131

121132
.. versionadded:: 3.6 ``Flag``, ``IntFlag``, ``auto``
122-
.. versionadded:: 3.10 ``StrEnum``
133+
.. versionadded:: 3.10 ``StrEnum``, ``EnumCheck``, ``FlagBoundary``
123134

124135

125136
Data Types
@@ -514,6 +525,65 @@ Data Types
514525
Using :class:`auto` with :class:`IntFlag` results in integers that are powers
515526
of two, starting with ``1``.
516527

528+
.. class:: EnumCheck
529+
530+
*EnumCheck* contains the options used by the :func:`verify` decorator to ensure
531+
various constraints; failed constraints result in a :exc:`TypeError`.
532+
533+
.. attribute:: UNIQUE
534+
535+
Ensure that each value has only one name::
536+
537+
>>> from enum import Enum, verify, UNIQUE
538+
>>> @verify(UNIQUE)
539+
... class Color(Enum):
540+
... RED = 1
541+
... GREEN = 2
542+
... BLUE = 3
543+
... CRIMSON = 1
544+
Traceback (most recent call last):
545+
...
546+
ValueError: aliases found in <enum 'Color'>: CRIMSON -> RED
547+
548+
549+
.. attribute:: CONTINUOUS
550+
551+
Ensure that there are no missing values between the lowest-valued member
552+
and the highest-valued member::
553+
554+
>>> from enum import Enum, verify, CONTINUOUS
555+
>>> @verify(CONTINUOUS)
556+
... class Color(Enum):
557+
... RED = 1
558+
... GREEN = 2
559+
... BLUE = 5
560+
Traceback (most recent call last):
561+
...
562+
ValueError: invalid enum 'Color': missing values 3, 4
563+
564+
.. attribute:: NAMED_FLAGS
565+
566+
Ensure that any flag groups/masks contain only named flags -- useful when
567+
values are specified instead of being generated by :func:`auto`
568+
569+
>>> from enum import Flag, verify, NAMED_FLAGS
570+
>>> @verify(NAMED_FLAGS)
571+
... class Color(Flag):
572+
... RED = 1
573+
... GREEN = 2
574+
... BLUE = 4
575+
... WHITE = 15
576+
... NEON = 31
577+
Traceback (most recent call last):
578+
...
579+
ValueError: invalid Flag 'Color': 'WHITE' is missing a named flag for value 8; 'NEON' is missing named flags for values 8, 16
580+
581+
.. note::
582+
583+
CONTINUOUS and NAMED_FLAGS are designed to work with integer-valued members.
584+
585+
.. versionadded:: 3.10
586+
517587
.. class:: FlagBoundary
518588

519589
*FlagBoundary* controls how out-of-range values are handled in *Flag* and its
@@ -575,7 +645,7 @@ Data Types
575645
>>> KeepFlag(2**2 + 2**4)
576646
KeepFlag.BLUE|0x10
577647

578-
.. versionadded:: 3.10 ``FlagBoundary``
648+
.. versionadded:: 3.10
579649

580650

581651
Utilites and Decorators
@@ -632,3 +702,11 @@ Utilites and Decorators
632702
Traceback (most recent call last):
633703
...
634704
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
705+
706+
.. decorator:: verify
707+
708+
A :keyword:`class` decorator specifically for enumerations. Members from
709+
:class:`EnumCheck` are used to specify which constraints should be checked
710+
on the decorated enumeration.
711+
712+
.. versionadded:: 3.10

Doc/library/smtpd.rst

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -142,24 +142,6 @@ PureProxy Objects
142142
chance to make you into an open relay, so please be careful.
143143

144144

145-
MailmanProxy Objects
146-
--------------------
147-
148-
149-
.. class:: MailmanProxy(localaddr, remoteaddr)
150-
151-
.. deprecated-removed:: 3.9 3.11
152-
153-
:class:`MailmanProxy` is deprecated, it depends on a ``Mailman``
154-
module which no longer exists and therefore is already broken.
155-
156-
157-
Create a new pure proxy server. Arguments are as per :class:`SMTPServer`.
158-
Everything will be relayed to *remoteaddr*, unless local mailman configurations
159-
knows about an address, in which case it will be handled via mailman. Note that
160-
running this has a good chance to make you into an open relay, so please be
161-
careful.
162-
163145
SMTPChannel Objects
164146
-------------------
165147

Doc/reference/import.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,9 +603,14 @@ the module.
603603
.. attribute:: __file__
604604
.. attribute:: __cached__
605605

606-
``__file__`` is optional. If set, this attribute's value must be a
607-
string. The import system may opt to leave ``__file__`` unset if it
608-
has no semantic meaning (e.g. a module loaded from a database).
606+
``__file__`` is optional (if set, value must be a string). It indicates
607+
the pathname of the file from which the module was loaded (if
608+
loaded from a file), or the pathname of the shared libray file
609+
for extension modules loaded dynamically from a shared library.
610+
It might be missing for certain types of modules, such as C
611+
modules that are statically linked into the interpreter, and the
612+
import system may opt to leave it unset if it has no semantic
613+
meaning (e.g. a module loaded from a database).
609614

610615
If ``__file__`` is set, it may also be appropriate to set the
611616
``__cached__`` attribute which is the path to any compiled version of

Doc/whatsnew/3.11.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ fractions
9292
Support :PEP:`515`-style initialization of :class:`~fractions.Fraction` from
9393
string. (Contributed by Sergey B Kirpichev in :issue:`44258`.)
9494

95+
96+
Removed
97+
=======
98+
* :class:`smtpd.MailmanProxy` is now removed as it is unusable without
99+
an external module, ``mailman``. (Contributed by Dong-hee Na in :issue:`35800`.)
100+
101+
95102
Optimizations
96103
=============
97104

Lib/enum.py

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
__all__ = [
77
'EnumType', 'EnumMeta',
88
'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag',
9-
'auto', 'unique',
10-
'property',
9+
'auto', 'unique', 'property', 'verify',
1110
'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP',
1211
'global_flag_repr', 'global_enum_repr', 'global_enum',
12+
'EnumCheck', 'CONTINUOUS', 'NAMED_FLAGS', 'UNIQUE',
1313
]
1414

1515

@@ -89,6 +89,9 @@ def _break_on_call_reduce(self, proto):
8989
setattr(obj, '__module__', '<unknown>')
9090

9191
def _iter_bits_lsb(num):
92+
# num must be an integer
93+
if isinstance(num, Enum):
94+
num = num.value
9295
while num:
9396
b = num & (~num + 1)
9497
yield b
@@ -538,13 +541,6 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
538541
else:
539542
# multi-bit flags are considered aliases
540543
multi_bit_total |= flag_value
541-
if enum_class._boundary_ is not KEEP:
542-
missed = list(_iter_bits_lsb(multi_bit_total & ~single_bit_total))
543-
if missed:
544-
raise TypeError(
545-
'invalid Flag %r -- missing values: %s'
546-
% (cls, ', '.join((str(i) for i in missed)))
547-
)
548544
enum_class._flag_mask_ = single_bit_total
549545
#
550546
# set correct __iter__
@@ -688,7 +684,10 @@ def __members__(cls):
688684
return MappingProxyType(cls._member_map_)
689685

690686
def __repr__(cls):
691-
return "<enum %r>" % cls.__name__
687+
if Flag is not None and issubclass(cls, Flag):
688+
return "<flag %r>" % cls.__name__
689+
else:
690+
return "<enum %r>" % cls.__name__
692691

693692
def __reversed__(cls):
694693
"""
@@ -1303,7 +1302,8 @@ def __invert__(self):
13031302
else:
13041303
# calculate flags not in this member
13051304
self._inverted_ = self.__class__(self._flag_mask_ ^ self._value_)
1306-
self._inverted_._inverted_ = self
1305+
if isinstance(self._inverted_, self.__class__):
1306+
self._inverted_._inverted_ = self
13071307
return self._inverted_
13081308

13091309

@@ -1561,6 +1561,91 @@ def convert_class(cls):
15611561
return enum_class
15621562
return convert_class
15631563

1564+
@_simple_enum(StrEnum)
1565+
class EnumCheck:
1566+
"""
1567+
various conditions to check an enumeration for
1568+
"""
1569+
CONTINUOUS = "no skipped integer values"
1570+
NAMED_FLAGS = "multi-flag aliases may not contain unnamed flags"
1571+
UNIQUE = "one name per value"
1572+
CONTINUOUS, NAMED_FLAGS, UNIQUE = EnumCheck
1573+
1574+
1575+
class verify:
1576+
"""
1577+
Check an enumeration for various constraints. (see EnumCheck)
1578+
"""
1579+
def __init__(self, *checks):
1580+
self.checks = checks
1581+
def __call__(self, enumeration):
1582+
checks = self.checks
1583+
cls_name = enumeration.__name__
1584+
if Flag is not None and issubclass(enumeration, Flag):
1585+
enum_type = 'flag'
1586+
elif issubclass(enumeration, Enum):
1587+
enum_type = 'enum'
1588+
else:
1589+
raise TypeError("the 'verify' decorator only works with Enum and Flag")
1590+
for check in checks:
1591+
if check is UNIQUE:
1592+
# check for duplicate names
1593+
duplicates = []
1594+
for name, member in enumeration.__members__.items():
1595+
if name != member.name:
1596+
duplicates.append((name, member.name))
1597+
if duplicates:
1598+
alias_details = ', '.join(
1599+
["%s -> %s" % (alias, name) for (alias, name) in duplicates])
1600+
raise ValueError('aliases found in %r: %s' %
1601+
(enumeration, alias_details))
1602+
elif check is CONTINUOUS:
1603+
values = set(e.value for e in enumeration)
1604+
if len(values) < 2:
1605+
continue
1606+
low, high = min(values), max(values)
1607+
missing = []
1608+
if enum_type == 'flag':
1609+
# check for powers of two
1610+
for i in range(_high_bit(low)+1, _high_bit(high)):
1611+
if 2**i not in values:
1612+
missing.append(2**i)
1613+
elif enum_type == 'enum':
1614+
# check for powers of one
1615+
for i in range(low+1, high):
1616+
if i not in values:
1617+
missing.append(i)
1618+
else:
1619+
raise Exception('verify: unknown type %r' % enum_type)
1620+
if missing:
1621+
raise ValueError('invalid %s %r: missing values %s' % (
1622+
enum_type, cls_name, ', '.join((str(m) for m in missing)))
1623+
)
1624+
elif check is NAMED_FLAGS:
1625+
# examine each alias and check for unnamed flags
1626+
member_names = enumeration._member_names_
1627+
member_values = [m.value for m in enumeration]
1628+
missing = []
1629+
for name, alias in enumeration._member_map_.items():
1630+
if name in member_names:
1631+
# not an alias
1632+
continue
1633+
values = list(_iter_bits_lsb(alias.value))
1634+
missed = [v for v in values if v not in member_values]
1635+
if missed:
1636+
plural = ('', 's')[len(missed) > 1]
1637+
a = ('a ', '')[len(missed) > 1]
1638+
missing.append('%r is missing %snamed flag%s for value%s %s' % (
1639+
name, a, plural, plural,
1640+
', '.join(str(v) for v in missed)
1641+
))
1642+
if missing:
1643+
raise ValueError(
1644+
'invalid Flag %r: %s'
1645+
% (cls_name, '; '.join(missing))
1646+
)
1647+
return enumeration
1648+
15641649
def _test_simple_enum(checked_enum, simple_enum):
15651650
"""
15661651
A function that can be used to test an enum created with :func:`_simple_enum`

0 commit comments

Comments
 (0)