mirror of
https://github.com/python/cpython
synced 2024-09-16 00:37:36 +00:00
bpo-40066: Enum: modify repr()
and str()
(GH-22392)
* Enum: streamline repr() and str(); improve docs - repr() is now ``enum_class.member_name`` - stdlib global enums are ``module_name.member_name`` - str() is now ``member_name`` - add HOW-TO section for ``Enum`` - change main documentation to be an API reference
This commit is contained in:
parent
51a85ddce8
commit
b775106d94
1416
Doc/howto/enum.rst
Normal file
1416
Doc/howto/enum.rst
Normal file
File diff suppressed because it is too large
Load diff
|
@ -17,6 +17,7 @@ Currently, the HOWTOs are:
|
|||
cporting.rst
|
||||
curses.rst
|
||||
descriptor.rst
|
||||
enum.rst
|
||||
functional.rst
|
||||
logging.rst
|
||||
logging-cookbook.rst
|
||||
|
|
1874
Doc/library/enum.rst
1874
Doc/library/enum.rst
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,7 @@ associated messages through the :class:`http.HTTPStatus` enum:
|
|||
|
||||
>>> from http import HTTPStatus
|
||||
>>> HTTPStatus.OK
|
||||
<HTTPStatus.OK: 200>
|
||||
HTTPStatus.OK
|
||||
>>> HTTPStatus.OK == 200
|
||||
True
|
||||
>>> HTTPStatus.OK.value
|
||||
|
@ -45,7 +45,7 @@ associated messages through the :class:`http.HTTPStatus` enum:
|
|||
>>> HTTPStatus.OK.description
|
||||
'Request fulfilled, document follows'
|
||||
>>> list(HTTPStatus)
|
||||
[<HTTPStatus.CONTINUE: 100>, <HTTPStatus.SWITCHING_PROTOCOLS: 101>, ...]
|
||||
[HTTPStatus.CONTINUE, HTTPStatus.SWITCHING_PROTOCOLS, ...]
|
||||
|
||||
.. _http-status-codes:
|
||||
|
||||
|
|
|
@ -785,9 +785,9 @@ The :mod:`socket` module also offers various network-related services:
|
|||
system if IPv6 isn't enabled)::
|
||||
|
||||
>>> socket.getaddrinfo("example.org", 80, proto=socket.IPPROTO_TCP)
|
||||
[(<AddressFamily.AF_INET6: 10>, <SocketType.SOCK_STREAM: 1>,
|
||||
[(socket.AF_INET6, socket.SOCK_STREAM,
|
||||
6, '', ('2606:2800:220:1:248:1893:25c8:1946', 80, 0, 0)),
|
||||
(<AddressFamily.AF_INET: 2>, <SocketType.SOCK_STREAM: 1>,
|
||||
(socket.AF_INET, socket.SOCK_STREAM,
|
||||
6, '', ('93.184.216.34', 80))]
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
|
|
|
@ -2062,7 +2062,7 @@ to speed up repeated connections from the same clients.
|
|||
:attr:`SSLContext.verify_flags` returns :class:`VerifyFlags` flags:
|
||||
|
||||
>>> ssl.create_default_context().verify_flags # doctest: +SKIP
|
||||
<VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768>
|
||||
ssl.VERIFY_X509_TRUSTED_FIRST
|
||||
|
||||
.. attribute:: SSLContext.verify_mode
|
||||
|
||||
|
@ -2074,7 +2074,7 @@ to speed up repeated connections from the same clients.
|
|||
:attr:`SSLContext.verify_mode` returns :class:`VerifyMode` enum:
|
||||
|
||||
>>> ssl.create_default_context().verify_mode
|
||||
<VerifyMode.CERT_REQUIRED: 2>
|
||||
ssl.CERT_REQUIRED
|
||||
|
||||
.. index:: single: certificates
|
||||
|
||||
|
|
|
@ -716,6 +716,14 @@ encodings
|
|||
:func:`encodings.normalize_encoding` now ignores non-ASCII characters.
|
||||
(Contributed by Hai Shi in :issue:`39337`.)
|
||||
|
||||
enum
|
||||
----
|
||||
|
||||
:class:`Enum` :func:`__repr__` now returns ``enum_name.member_name`` and
|
||||
:func:`__str__` now returns ``member_name``. Stdlib enums available as
|
||||
module constants have a :func:`repr` of ``module_name.member_name``.
|
||||
(Contributed by Ethan Furman in :issue:`40066`.)
|
||||
|
||||
gc
|
||||
--
|
||||
|
||||
|
|
86
Lib/enum.py
86
Lib/enum.py
|
@ -4,17 +4,18 @@
|
|||
|
||||
|
||||
__all__ = [
|
||||
'EnumMeta',
|
||||
'EnumType', 'EnumMeta',
|
||||
'Enum', 'IntEnum', 'StrEnum', 'Flag', 'IntFlag',
|
||||
'auto', 'unique',
|
||||
'property',
|
||||
'FlagBoundary', 'STRICT', 'CONFORM', 'EJECT', 'KEEP',
|
||||
'global_flag_repr', 'global_enum_repr', 'global_enum',
|
||||
]
|
||||
|
||||
|
||||
# Dummy value for Enum and Flag as there are explicit checks for them
|
||||
# before they have been created.
|
||||
# This is also why there are checks in EnumMeta like `if Enum is not None`
|
||||
# This is also why there are checks in EnumType like `if Enum is not None`
|
||||
Enum = Flag = EJECT = None
|
||||
|
||||
def _is_descriptor(obj):
|
||||
|
@ -285,7 +286,7 @@ class _EnumDict(dict):
|
|||
"""
|
||||
Track enum member order and ensure member names are not reused.
|
||||
|
||||
EnumMeta will use the names found in self._member_names as the
|
||||
EnumType will use the names found in self._member_names as the
|
||||
enumeration member names.
|
||||
"""
|
||||
def __init__(self):
|
||||
|
@ -321,7 +322,8 @@ def __setitem__(self, key, value):
|
|||
# check if members already defined as auto()
|
||||
if self._auto_called:
|
||||
raise TypeError("_generate_next_value_ must be defined before members")
|
||||
setattr(self, '_generate_next_value', value)
|
||||
_gnv = value.__func__ if isinstance(value, staticmethod) else value
|
||||
setattr(self, '_generate_next_value', _gnv)
|
||||
elif key == '_ignore_':
|
||||
if isinstance(value, str):
|
||||
value = value.replace(',',' ').split()
|
||||
|
@ -368,7 +370,7 @@ def update(self, members, **more_members):
|
|||
self[name] = value
|
||||
|
||||
|
||||
class EnumMeta(type):
|
||||
class EnumType(type):
|
||||
"""
|
||||
Metaclass for Enum
|
||||
"""
|
||||
|
@ -756,9 +758,9 @@ def _convert_(cls, name, module, filter, source=None, boundary=None):
|
|||
# module;
|
||||
# also, replace the __reduce_ex__ method so unpickling works in
|
||||
# previous Python versions
|
||||
module_globals = vars(sys.modules[module])
|
||||
module_globals = sys.modules[module].__dict__
|
||||
if source:
|
||||
source = vars(source)
|
||||
source = source.__dict__
|
||||
else:
|
||||
source = module_globals
|
||||
# _value2member_map_ is populated in the same order every time
|
||||
|
@ -776,7 +778,7 @@ def _convert_(cls, name, module, filter, source=None, boundary=None):
|
|||
members.sort(key=lambda t: t[0])
|
||||
cls = cls(name, members, module=module, boundary=boundary or KEEP)
|
||||
cls.__reduce_ex__ = _reduce_ex_by_name
|
||||
module_globals.update(cls.__members__)
|
||||
global_enum(cls)
|
||||
module_globals[name] = cls
|
||||
return cls
|
||||
|
||||
|
@ -881,9 +883,10 @@ def _find_new_(classdict, member_type, first_enum):
|
|||
else:
|
||||
use_args = True
|
||||
return __new__, save_new, use_args
|
||||
EnumMeta = EnumType
|
||||
|
||||
|
||||
class Enum(metaclass=EnumMeta):
|
||||
class Enum(metaclass=EnumType):
|
||||
"""
|
||||
Generic enumeration.
|
||||
|
||||
|
@ -958,11 +961,10 @@ def _missing_(cls, value):
|
|||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s.%s: %r>" % (
|
||||
self.__class__.__name__, self._name_, self._value_)
|
||||
return "%s.%s" % ( self.__class__.__name__, self._name_)
|
||||
|
||||
def __str__(self):
|
||||
return "%s.%s" % (self.__class__.__name__, self._name_)
|
||||
return "%s" % (self._name_, )
|
||||
|
||||
def __dir__(self):
|
||||
"""
|
||||
|
@ -1220,19 +1222,28 @@ def __len__(self):
|
|||
return self._value_.bit_count()
|
||||
|
||||
def __repr__(self):
|
||||
cls = self.__class__
|
||||
if self._name_ is not None:
|
||||
return '<%s.%s: %r>' % (cls.__name__, self._name_, self._value_)
|
||||
cls_name = self.__class__.__name__
|
||||
if self._name_ is None:
|
||||
return "0x%x" % (self._value_, )
|
||||
if _is_single_bit(self._value_):
|
||||
return '%s.%s' % (cls_name, self._name_)
|
||||
if self._boundary_ is not FlagBoundary.KEEP:
|
||||
return '%s.' % cls_name + ('|%s.' % cls_name).join(self.name.split('|'))
|
||||
else:
|
||||
# only zero is unnamed by default
|
||||
return '<%s: %r>' % (cls.__name__, self._value_)
|
||||
name = []
|
||||
for n in self._name_.split('|'):
|
||||
if n.startswith('0'):
|
||||
name.append(n)
|
||||
else:
|
||||
name.append('%s.%s' % (cls_name, n))
|
||||
return '|'.join(name)
|
||||
|
||||
def __str__(self):
|
||||
cls = self.__class__
|
||||
if self._name_ is not None:
|
||||
return '%s.%s' % (cls.__name__, self._name_)
|
||||
if self._name_ is None:
|
||||
return '%s(%x)' % (cls.__name__, self._value_)
|
||||
else:
|
||||
return '%s(%s)' % (cls.__name__, self._value_)
|
||||
return self._name_
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self._value_)
|
||||
|
@ -1329,3 +1340,38 @@ def _power_of_two(value):
|
|||
if value < 1:
|
||||
return False
|
||||
return value == 2 ** _high_bit(value)
|
||||
|
||||
def global_enum_repr(self):
|
||||
return '%s.%s' % (self.__class__.__module__, self._name_)
|
||||
|
||||
def global_flag_repr(self):
|
||||
module = self.__class__.__module__
|
||||
cls_name = self.__class__.__name__
|
||||
if self._name_ is None:
|
||||
return "%x" % (module, cls_name, self._value_)
|
||||
if _is_single_bit(self):
|
||||
return '%s.%s' % (module, self._name_)
|
||||
if self._boundary_ is not FlagBoundary.KEEP:
|
||||
return module + module.join(self.name.split('|'))
|
||||
else:
|
||||
name = []
|
||||
for n in self._name_.split('|'):
|
||||
if n.startswith('0'):
|
||||
name.append(n)
|
||||
else:
|
||||
name.append('%s.%s' % (module, n))
|
||||
return '|'.join(name)
|
||||
|
||||
|
||||
def global_enum(cls):
|
||||
"""
|
||||
decorator that makes the repr() of an enum member reference its module
|
||||
instead of its class; also exports all members to the enum's module's
|
||||
global namespace
|
||||
"""
|
||||
if issubclass(cls, Flag):
|
||||
cls.__repr__ = global_flag_repr
|
||||
else:
|
||||
cls.__repr__ = global_enum_repr
|
||||
sys.modules[cls.__module__].__dict__.update(cls.__members__)
|
||||
return cls
|
||||
|
|
|
@ -2455,9 +2455,6 @@ class _ParameterKind(enum.IntEnum):
|
|||
KEYWORD_ONLY = 3
|
||||
VAR_KEYWORD = 4
|
||||
|
||||
def __str__(self):
|
||||
return self._name_
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return _PARAM_NAME_MAPPING[self]
|
||||
|
|
|
@ -61,8 +61,7 @@
|
|||
from xml.parsers.expat import ParserCreate
|
||||
|
||||
|
||||
PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
|
||||
globals().update(PlistFormat.__members__)
|
||||
PlistFormat = enum.global_enum(enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__))
|
||||
|
||||
|
||||
class UID:
|
||||
|
|
17
Lib/re.py
17
Lib/re.py
|
@ -142,6 +142,7 @@
|
|||
|
||||
__version__ = "2.2.1"
|
||||
|
||||
@enum.global_enum
|
||||
class RegexFlag(enum.IntFlag, boundary=enum.KEEP):
|
||||
ASCII = A = sre_compile.SRE_FLAG_ASCII # assume ascii "locale"
|
||||
IGNORECASE = I = sre_compile.SRE_FLAG_IGNORECASE # ignore case
|
||||
|
@ -154,22 +155,6 @@ class RegexFlag(enum.IntFlag, boundary=enum.KEEP):
|
|||
TEMPLATE = T = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking
|
||||
DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation
|
||||
|
||||
def __repr__(self):
|
||||
res = ''
|
||||
if self._name_:
|
||||
member_names = self._name_.split('|')
|
||||
constant = None
|
||||
if member_names[-1].startswith('0x'):
|
||||
constant = member_names.pop()
|
||||
res = 're.' + '|re.'.join(member_names)
|
||||
if constant:
|
||||
res += '|%s' % constant
|
||||
return res
|
||||
|
||||
__str__ = object.__str__
|
||||
|
||||
globals().update(RegexFlag.__members__)
|
||||
|
||||
# sre exception
|
||||
error = sre_compile.error
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import unittest
|
||||
import threading
|
||||
from collections import OrderedDict
|
||||
from enum import Enum, IntEnum, StrEnum, EnumMeta, Flag, IntFlag, unique, auto
|
||||
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
|
||||
from enum import STRICT, CONFORM, EJECT, KEEP
|
||||
from io import StringIO
|
||||
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
|
||||
|
@ -262,11 +262,8 @@ def test_enum(self):
|
|||
self.assertIn(e, Season)
|
||||
self.assertIs(type(e), Season)
|
||||
self.assertIsInstance(e, Season)
|
||||
self.assertEqual(str(e), 'Season.' + season)
|
||||
self.assertEqual(
|
||||
repr(e),
|
||||
'<Season.{0}: {1}>'.format(season, i),
|
||||
)
|
||||
self.assertEqual(str(e), season)
|
||||
self.assertEqual(repr(e), 'Season.{0}'.format(season))
|
||||
|
||||
def test_value_name(self):
|
||||
Season = self.Season
|
||||
|
@ -440,7 +437,7 @@ def red(self):
|
|||
def test_reserved__sunder_(self):
|
||||
with self.assertRaisesRegex(
|
||||
ValueError,
|
||||
"_sunder_ names, such as '_bad_', are reserved",
|
||||
'_sunder_ names, such as ._bad_., are reserved',
|
||||
):
|
||||
class Bad(Enum):
|
||||
_bad_ = 1
|
||||
|
@ -488,7 +485,7 @@ class EnumWithFormatOverride(Enum):
|
|||
two = 2.0
|
||||
def __format__(self, spec):
|
||||
return 'Format!!'
|
||||
self.assertEqual(str(EnumWithFormatOverride.one), 'EnumWithFormatOverride.one')
|
||||
self.assertEqual(str(EnumWithFormatOverride.one), 'one')
|
||||
self.assertEqual('{}'.format(EnumWithFormatOverride.one), 'Format!!')
|
||||
|
||||
def test_str_and_format_override_enum(self):
|
||||
|
@ -528,7 +525,7 @@ class TestFloat(float, Enum):
|
|||
two = 2.0
|
||||
def __format__(self, spec):
|
||||
return 'TestFloat success!'
|
||||
self.assertEqual(str(TestFloat.one), 'TestFloat.one')
|
||||
self.assertEqual(str(TestFloat.one), 'one')
|
||||
self.assertEqual('{}'.format(TestFloat.one), 'TestFloat success!')
|
||||
|
||||
def assertFormatIsValue(self, spec, member):
|
||||
|
@ -614,6 +611,8 @@ class MyEnum(HexInt, enum.Enum):
|
|||
A = 1
|
||||
B = 2
|
||||
C = 3
|
||||
def __repr__(self):
|
||||
return '<%s.%s: %r>' % (self.__class__.__name__, self._name_, self._value_)
|
||||
self.assertEqual(repr(MyEnum.A), '<MyEnum.A: 0x1>')
|
||||
|
||||
def test_too_many_data_types(self):
|
||||
|
@ -1959,7 +1958,7 @@ class Color(MaxMixin, Enum):
|
|||
self.assertEqual(Color.GREEN.value, 2)
|
||||
self.assertEqual(Color.BLUE.value, 3)
|
||||
self.assertEqual(Color.MAX, 3)
|
||||
self.assertEqual(str(Color.BLUE), 'Color.BLUE')
|
||||
self.assertEqual(str(Color.BLUE), 'BLUE')
|
||||
class Color(MaxMixin, StrMixin, Enum):
|
||||
RED = auto()
|
||||
GREEN = auto()
|
||||
|
@ -2330,64 +2329,62 @@ class Color(Flag):
|
|||
|
||||
def test_str(self):
|
||||
Perm = self.Perm
|
||||
self.assertEqual(str(Perm.R), 'Perm.R')
|
||||
self.assertEqual(str(Perm.W), 'Perm.W')
|
||||
self.assertEqual(str(Perm.X), 'Perm.X')
|
||||
self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
|
||||
self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
|
||||
self.assertEqual(str(Perm.R), 'R')
|
||||
self.assertEqual(str(Perm.W), 'W')
|
||||
self.assertEqual(str(Perm.X), 'X')
|
||||
self.assertEqual(str(Perm.R | Perm.W), 'R|W')
|
||||
self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
|
||||
self.assertEqual(str(Perm(0)), 'Perm(0)')
|
||||
self.assertEqual(str(~Perm.R), 'Perm.W|X')
|
||||
self.assertEqual(str(~Perm.W), 'Perm.R|X')
|
||||
self.assertEqual(str(~Perm.X), 'Perm.R|W')
|
||||
self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
|
||||
self.assertEqual(str(~Perm.R), 'W|X')
|
||||
self.assertEqual(str(~Perm.W), 'R|X')
|
||||
self.assertEqual(str(~Perm.X), 'R|W')
|
||||
self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
|
||||
self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
|
||||
self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
|
||||
self.assertEqual(str(Perm(~0)), 'R|W|X')
|
||||
|
||||
Open = self.Open
|
||||
self.assertEqual(str(Open.RO), 'Open.RO')
|
||||
self.assertEqual(str(Open.WO), 'Open.WO')
|
||||
self.assertEqual(str(Open.AC), 'Open.AC')
|
||||
self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
|
||||
self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
|
||||
self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
|
||||
self.assertEqual(str(~Open.WO), 'Open.RW|CE')
|
||||
self.assertEqual(str(~Open.AC), 'Open.CE')
|
||||
self.assertEqual(str(~Open.CE), 'Open.AC')
|
||||
self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
|
||||
self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
|
||||
self.assertEqual(str(Open.RO), 'RO')
|
||||
self.assertEqual(str(Open.WO), 'WO')
|
||||
self.assertEqual(str(Open.AC), 'AC')
|
||||
self.assertEqual(str(Open.RO | Open.CE), 'CE')
|
||||
self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
|
||||
self.assertEqual(str(~Open.RO), 'WO|RW|CE')
|
||||
self.assertEqual(str(~Open.WO), 'RW|CE')
|
||||
self.assertEqual(str(~Open.AC), 'CE')
|
||||
self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
|
||||
self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
|
||||
|
||||
def test_repr(self):
|
||||
Perm = self.Perm
|
||||
self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
|
||||
self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
|
||||
self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
|
||||
self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
|
||||
self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
|
||||
self.assertEqual(repr(Perm(0)), '<Perm: 0>')
|
||||
self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
|
||||
self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
|
||||
self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
|
||||
self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
|
||||
self.assertEqual(repr(Perm.R), 'Perm.R')
|
||||
self.assertEqual(repr(Perm.W), 'Perm.W')
|
||||
self.assertEqual(repr(Perm.X), 'Perm.X')
|
||||
self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
|
||||
self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
|
||||
self.assertEqual(repr(Perm(0)), '0x0')
|
||||
self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
|
||||
self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
|
||||
self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
|
||||
self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
|
||||
|
||||
Open = self.Open
|
||||
self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
|
||||
self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
|
||||
self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
|
||||
self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
|
||||
self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
|
||||
self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
|
||||
self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
|
||||
self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
|
||||
self.assertEqual(repr(~Open.CE), '<Open.AC: 3>')
|
||||
self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
|
||||
self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
|
||||
self.assertEqual(repr(Open.RO), 'Open.RO')
|
||||
self.assertEqual(repr(Open.WO), 'Open.WO')
|
||||
self.assertEqual(repr(Open.AC), 'Open.AC')
|
||||
self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
|
||||
self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
|
||||
self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
|
||||
self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
|
||||
self.assertEqual(repr(~Open.AC), 'Open.CE')
|
||||
self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
|
||||
self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
|
||||
|
||||
def test_format(self):
|
||||
Perm = self.Perm
|
||||
self.assertEqual(format(Perm.R, ''), 'Perm.R')
|
||||
self.assertEqual(format(Perm.R | Perm.X, ''), 'Perm.R|X')
|
||||
self.assertEqual(format(Perm.R, ''), 'R')
|
||||
self.assertEqual(format(Perm.R | Perm.X, ''), 'R|X')
|
||||
|
||||
def test_or(self):
|
||||
Perm = self.Perm
|
||||
|
@ -2707,7 +2704,7 @@ class Color(AllMixin, Flag):
|
|||
self.assertEqual(Color.GREEN.value, 2)
|
||||
self.assertEqual(Color.BLUE.value, 4)
|
||||
self.assertEqual(Color.ALL.value, 7)
|
||||
self.assertEqual(str(Color.BLUE), 'Color.BLUE')
|
||||
self.assertEqual(str(Color.BLUE), 'BLUE')
|
||||
class Color(AllMixin, StrMixin, Flag):
|
||||
RED = auto()
|
||||
GREEN = auto()
|
||||
|
@ -2850,77 +2847,70 @@ def test_type(self):
|
|||
|
||||
def test_str(self):
|
||||
Perm = self.Perm
|
||||
self.assertEqual(str(Perm.R), 'Perm.R')
|
||||
self.assertEqual(str(Perm.W), 'Perm.W')
|
||||
self.assertEqual(str(Perm.X), 'Perm.X')
|
||||
self.assertEqual(str(Perm.R | Perm.W), 'Perm.R|W')
|
||||
self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'Perm.R|W|X')
|
||||
self.assertEqual(str(Perm.R), 'R')
|
||||
self.assertEqual(str(Perm.W), 'W')
|
||||
self.assertEqual(str(Perm.X), 'X')
|
||||
self.assertEqual(str(Perm.R | Perm.W), 'R|W')
|
||||
self.assertEqual(str(Perm.R | Perm.W | Perm.X), 'R|W|X')
|
||||
self.assertEqual(str(Perm.R | 8), '12')
|
||||
self.assertEqual(str(Perm(0)), 'Perm(0)')
|
||||
self.assertEqual(str(Perm(8)), '8')
|
||||
self.assertEqual(str(~Perm.R), 'Perm.W|X')
|
||||
self.assertEqual(str(~Perm.W), 'Perm.R|X')
|
||||
self.assertEqual(str(~Perm.X), 'Perm.R|W')
|
||||
self.assertEqual(str(~(Perm.R | Perm.W)), 'Perm.X')
|
||||
self.assertEqual(str(~Perm.R), 'W|X')
|
||||
self.assertEqual(str(~Perm.W), 'R|X')
|
||||
self.assertEqual(str(~Perm.X), 'R|W')
|
||||
self.assertEqual(str(~(Perm.R | Perm.W)), 'X')
|
||||
self.assertEqual(str(~(Perm.R | Perm.W | Perm.X)), 'Perm(0)')
|
||||
self.assertEqual(str(~(Perm.R | 8)), '-13')
|
||||
self.assertEqual(str(Perm(~0)), 'Perm.R|W|X')
|
||||
self.assertEqual(str(Perm(~0)), 'R|W|X')
|
||||
self.assertEqual(str(Perm(~8)), '-9')
|
||||
|
||||
Open = self.Open
|
||||
self.assertEqual(str(Open.RO), 'Open.RO')
|
||||
self.assertEqual(str(Open.WO), 'Open.WO')
|
||||
self.assertEqual(str(Open.AC), 'Open.AC')
|
||||
self.assertEqual(str(Open.RO | Open.CE), 'Open.CE')
|
||||
self.assertEqual(str(Open.WO | Open.CE), 'Open.WO|CE')
|
||||
self.assertEqual(str(Open.RO), 'RO')
|
||||
self.assertEqual(str(Open.WO), 'WO')
|
||||
self.assertEqual(str(Open.AC), 'AC')
|
||||
self.assertEqual(str(Open.RO | Open.CE), 'CE')
|
||||
self.assertEqual(str(Open.WO | Open.CE), 'WO|CE')
|
||||
self.assertEqual(str(Open(4)), '4')
|
||||
self.assertEqual(str(~Open.RO), 'Open.WO|RW|CE')
|
||||
self.assertEqual(str(~Open.WO), 'Open.RW|CE')
|
||||
self.assertEqual(str(~Open.AC), 'Open.CE')
|
||||
self.assertEqual(str(~Open.CE), 'Open.AC')
|
||||
self.assertEqual(str(~(Open.RO | Open.CE)), 'Open.AC')
|
||||
self.assertEqual(str(~(Open.WO | Open.CE)), 'Open.RW')
|
||||
self.assertEqual(str(~Open.RO), 'WO|RW|CE')
|
||||
self.assertEqual(str(~Open.WO), 'RW|CE')
|
||||
self.assertEqual(str(~Open.AC), 'CE')
|
||||
self.assertEqual(str(~(Open.RO | Open.CE)), 'AC')
|
||||
self.assertEqual(str(~(Open.WO | Open.CE)), 'RW')
|
||||
self.assertEqual(str(Open(~4)), '-5')
|
||||
|
||||
Skip = self.Skip
|
||||
self.assertEqual(str(Skip(~4)), 'Skip.FIRST|SECOND|EIGHTH')
|
||||
|
||||
def test_repr(self):
|
||||
Perm = self.Perm
|
||||
self.assertEqual(repr(Perm.R), '<Perm.R: 4>')
|
||||
self.assertEqual(repr(Perm.W), '<Perm.W: 2>')
|
||||
self.assertEqual(repr(Perm.X), '<Perm.X: 1>')
|
||||
self.assertEqual(repr(Perm.R | Perm.W), '<Perm.R|W: 6>')
|
||||
self.assertEqual(repr(Perm.R | Perm.W | Perm.X), '<Perm.R|W|X: 7>')
|
||||
self.assertEqual(repr(Perm.R), 'Perm.R')
|
||||
self.assertEqual(repr(Perm.W), 'Perm.W')
|
||||
self.assertEqual(repr(Perm.X), 'Perm.X')
|
||||
self.assertEqual(repr(Perm.R | Perm.W), 'Perm.R|Perm.W')
|
||||
self.assertEqual(repr(Perm.R | Perm.W | Perm.X), 'Perm.R|Perm.W|Perm.X')
|
||||
self.assertEqual(repr(Perm.R | 8), '12')
|
||||
self.assertEqual(repr(Perm(0)), '<Perm: 0>')
|
||||
self.assertEqual(repr(Perm(0)), '0x0')
|
||||
self.assertEqual(repr(Perm(8)), '8')
|
||||
self.assertEqual(repr(~Perm.R), '<Perm.W|X: 3>')
|
||||
self.assertEqual(repr(~Perm.W), '<Perm.R|X: 5>')
|
||||
self.assertEqual(repr(~Perm.X), '<Perm.R|W: 6>')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W)), '<Perm.X: 1>')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '<Perm: 0>')
|
||||
self.assertEqual(repr(~Perm.R), 'Perm.W|Perm.X')
|
||||
self.assertEqual(repr(~Perm.W), 'Perm.R|Perm.X')
|
||||
self.assertEqual(repr(~Perm.X), 'Perm.R|Perm.W')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W)), 'Perm.X')
|
||||
self.assertEqual(repr(~(Perm.R | Perm.W | Perm.X)), '0x0')
|
||||
self.assertEqual(repr(~(Perm.R | 8)), '-13')
|
||||
self.assertEqual(repr(Perm(~0)), '<Perm.R|W|X: 7>')
|
||||
self.assertEqual(repr(Perm(~0)), 'Perm.R|Perm.W|Perm.X')
|
||||
self.assertEqual(repr(Perm(~8)), '-9')
|
||||
|
||||
Open = self.Open
|
||||
self.assertEqual(repr(Open.RO), '<Open.RO: 0>')
|
||||
self.assertEqual(repr(Open.WO), '<Open.WO: 1>')
|
||||
self.assertEqual(repr(Open.AC), '<Open.AC: 3>')
|
||||
self.assertEqual(repr(Open.RO | Open.CE), '<Open.CE: 524288>')
|
||||
self.assertEqual(repr(Open.WO | Open.CE), '<Open.WO|CE: 524289>')
|
||||
self.assertEqual(repr(Open.RO), 'Open.RO')
|
||||
self.assertEqual(repr(Open.WO), 'Open.WO')
|
||||
self.assertEqual(repr(Open.AC), 'Open.AC')
|
||||
self.assertEqual(repr(Open.RO | Open.CE), 'Open.CE')
|
||||
self.assertEqual(repr(Open.WO | Open.CE), 'Open.WO|Open.CE')
|
||||
self.assertEqual(repr(Open(4)), '4')
|
||||
self.assertEqual(repr(~Open.RO), '<Open.WO|RW|CE: 524291>')
|
||||
self.assertEqual(repr(~Open.WO), '<Open.RW|CE: 524290>')
|
||||
self.assertEqual(repr(~Open.AC), '<Open.CE: 524288>')
|
||||
self.assertEqual(repr(~(Open.RO | Open.CE)), '<Open.AC: 3>')
|
||||
self.assertEqual(repr(~(Open.WO | Open.CE)), '<Open.RW: 2>')
|
||||
self.assertEqual(repr(~Open.RO), 'Open.WO|Open.RW|Open.CE')
|
||||
self.assertEqual(repr(~Open.WO), 'Open.RW|Open.CE')
|
||||
self.assertEqual(repr(~Open.AC), 'Open.CE')
|
||||
self.assertEqual(repr(~(Open.RO | Open.CE)), 'Open.AC')
|
||||
self.assertEqual(repr(~(Open.WO | Open.CE)), 'Open.RW')
|
||||
self.assertEqual(repr(Open(~4)), '-5')
|
||||
|
||||
Skip = self.Skip
|
||||
self.assertEqual(repr(Skip(~4)), '<Skip.FIRST|SECOND|EIGHTH: 11>')
|
||||
|
||||
def test_format(self):
|
||||
Perm = self.Perm
|
||||
self.assertEqual(format(Perm.R, ''), '4')
|
||||
|
@ -3252,7 +3242,7 @@ class Color(AllMixin, IntFlag):
|
|||
self.assertEqual(Color.GREEN.value, 2)
|
||||
self.assertEqual(Color.BLUE.value, 4)
|
||||
self.assertEqual(Color.ALL.value, 7)
|
||||
self.assertEqual(str(Color.BLUE), 'Color.BLUE')
|
||||
self.assertEqual(str(Color.BLUE), 'BLUE')
|
||||
class Color(AllMixin, StrMixin, IntFlag):
|
||||
RED = auto()
|
||||
GREEN = auto()
|
||||
|
@ -3374,6 +3364,8 @@ class Sillier(IntEnum):
|
|||
value = 4
|
||||
|
||||
|
||||
class TestEnumTypeSubclassing(unittest.TestCase):
|
||||
pass
|
||||
|
||||
expected_help_output_with_docs = """\
|
||||
Help on class Color in module %s:
|
||||
|
@ -3390,11 +3382,11 @@ class Color(enum.Enum)
|
|||
|\x20\x20
|
||||
| Data and other attributes defined here:
|
||||
|\x20\x20
|
||||
| blue = <Color.blue: 3>
|
||||
| blue = Color.blue
|
||||
|\x20\x20
|
||||
| green = <Color.green: 2>
|
||||
| green = Color.green
|
||||
|\x20\x20
|
||||
| red = <Color.red: 1>
|
||||
| red = Color.red
|
||||
|\x20\x20
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors inherited from enum.Enum:
|
||||
|
@ -3406,7 +3398,7 @@ class Color(enum.Enum)
|
|||
| The value of the Enum member.
|
||||
|\x20\x20
|
||||
| ----------------------------------------------------------------------
|
||||
| Readonly properties inherited from enum.EnumMeta:
|
||||
| Readonly properties inherited from enum.EnumType:
|
||||
|\x20\x20
|
||||
| __members__
|
||||
| Returns a mapping of member name->value.
|
||||
|
@ -3427,11 +3419,11 @@ class Color(enum.Enum)
|
|||
|\x20\x20
|
||||
| Data and other attributes defined here:
|
||||
|\x20\x20
|
||||
| blue = <Color.blue: 3>
|
||||
| blue = Color.blue
|
||||
|\x20\x20
|
||||
| green = <Color.green: 2>
|
||||
| green = Color.green
|
||||
|\x20\x20
|
||||
| red = <Color.red: 1>
|
||||
| red = Color.red
|
||||
|\x20\x20
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors inherited from enum.Enum:
|
||||
|
@ -3441,7 +3433,7 @@ class Color(enum.Enum)
|
|||
| value
|
||||
|\x20\x20
|
||||
| ----------------------------------------------------------------------
|
||||
| Data descriptors inherited from enum.EnumMeta:
|
||||
| Data descriptors inherited from enum.EnumType:
|
||||
|\x20\x20
|
||||
| __members__"""
|
||||
|
||||
|
@ -3468,7 +3460,7 @@ def test_pydoc(self):
|
|||
|
||||
def test_inspect_getmembers(self):
|
||||
values = dict((
|
||||
('__class__', EnumMeta),
|
||||
('__class__', EnumType),
|
||||
('__doc__', 'An enumeration.'),
|
||||
('__members__', self.Color.__members__),
|
||||
('__module__', __name__),
|
||||
|
@ -3495,11 +3487,11 @@ def test_inspect_classify_class_attrs(self):
|
|||
from inspect import Attribute
|
||||
values = [
|
||||
Attribute(name='__class__', kind='data',
|
||||
defining_class=object, object=EnumMeta),
|
||||
defining_class=object, object=EnumType),
|
||||
Attribute(name='__doc__', kind='data',
|
||||
defining_class=self.Color, object='An enumeration.'),
|
||||
Attribute(name='__members__', kind='property',
|
||||
defining_class=EnumMeta, object=EnumMeta.__members__),
|
||||
defining_class=EnumType, object=EnumType.__members__),
|
||||
Attribute(name='__module__', kind='data',
|
||||
defining_class=self.Color, object=__name__),
|
||||
Attribute(name='blue', kind='data',
|
||||
|
@ -3589,6 +3581,45 @@ def test_convert_raise(self):
|
|||
('test.test_enum', '__main__')[__name__=='__main__'],
|
||||
filter=lambda x: x.startswith('CONVERT_TEST_'))
|
||||
|
||||
def test_convert_repr_and_str(self):
|
||||
module = ('test.test_enum', '__main__')[__name__=='__main__']
|
||||
test_type = enum.IntEnum._convert_(
|
||||
'UnittestConvert',
|
||||
module,
|
||||
filter=lambda x: x.startswith('CONVERT_TEST_'))
|
||||
self.assertEqual(repr(test_type.CONVERT_TEST_NAME_A), '%s.CONVERT_TEST_NAME_A' % module)
|
||||
self.assertEqual(str(test_type.CONVERT_TEST_NAME_A), 'CONVERT_TEST_NAME_A')
|
||||
self.assertEqual(format(test_type.CONVERT_TEST_NAME_A), '5')
|
||||
|
||||
# global names for StrEnum._convert_ test
|
||||
CONVERT_STR_TEST_2 = 'goodbye'
|
||||
CONVERT_STR_TEST_1 = 'hello'
|
||||
|
||||
class TestStrEnumConvert(unittest.TestCase):
|
||||
|
||||
def test_convert(self):
|
||||
test_type = enum.StrEnum._convert_(
|
||||
'UnittestConvert',
|
||||
('test.test_enum', '__main__')[__name__=='__main__'],
|
||||
filter=lambda x: x.startswith('CONVERT_STR_'))
|
||||
# Ensure that test_type has all of the desired names and values.
|
||||
self.assertEqual(test_type.CONVERT_STR_TEST_1, 'hello')
|
||||
self.assertEqual(test_type.CONVERT_STR_TEST_2, 'goodbye')
|
||||
# Ensure that test_type only picked up names matching the filter.
|
||||
self.assertEqual([name for name in dir(test_type)
|
||||
if name[0:2] not in ('CO', '__')],
|
||||
[], msg='Names other than CONVERT_STR_* found.')
|
||||
|
||||
def test_convert_repr_and_str(self):
|
||||
module = ('test.test_enum', '__main__')[__name__=='__main__']
|
||||
test_type = enum.StrEnum._convert_(
|
||||
'UnittestConvert',
|
||||
module,
|
||||
filter=lambda x: x.startswith('CONVERT_STR_'))
|
||||
self.assertEqual(repr(test_type.CONVERT_STR_TEST_1), '%s.CONVERT_STR_TEST_1' % module)
|
||||
self.assertEqual(str(test_type.CONVERT_STR_TEST_2), 'goodbye')
|
||||
self.assertEqual(format(test_type.CONVERT_STR_TEST_1), 'hello')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -453,7 +453,7 @@ class BinaryInteger(enum.IntEnum):
|
|||
zero = 0
|
||||
one = 1
|
||||
doc = pydoc.render_doc(BinaryInteger)
|
||||
self.assertIn('<BinaryInteger.zero: 0>', doc)
|
||||
self.assertIn('BinaryInteger.zero', doc)
|
||||
|
||||
def test_mixed_case_module_names_are_lower_cased(self):
|
||||
# issue16484
|
||||
|
|
|
@ -872,7 +872,7 @@ def handler(signum, frame):
|
|||
|
||||
%s
|
||||
|
||||
blocked = %s
|
||||
blocked = %r
|
||||
signum = signal.SIGALRM
|
||||
|
||||
# child: block and wait the signal
|
||||
|
|
|
@ -1518,9 +1518,9 @@ def testGetaddrinfo(self):
|
|||
infos = socket.getaddrinfo(HOST, 80, socket.AF_INET, socket.SOCK_STREAM)
|
||||
for family, type, _, _, _ in infos:
|
||||
self.assertEqual(family, socket.AF_INET)
|
||||
self.assertEqual(str(family), 'AddressFamily.AF_INET')
|
||||
self.assertEqual(str(family), 'AF_INET')
|
||||
self.assertEqual(type, socket.SOCK_STREAM)
|
||||
self.assertEqual(str(type), 'SocketKind.SOCK_STREAM')
|
||||
self.assertEqual(str(type), 'SOCK_STREAM')
|
||||
infos = socket.getaddrinfo(HOST, None, 0, socket.SOCK_STREAM)
|
||||
for _, socktype, _, _, _ in infos:
|
||||
self.assertEqual(socktype, socket.SOCK_STREAM)
|
||||
|
@ -1793,8 +1793,8 @@ def test_str_for_enums(self):
|
|||
# Make sure that the AF_* and SOCK_* constants have enum-like string
|
||||
# reprs.
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
self.assertEqual(str(s.family), 'AddressFamily.AF_INET')
|
||||
self.assertEqual(str(s.type), 'SocketKind.SOCK_STREAM')
|
||||
self.assertEqual(str(s.family), 'AF_INET')
|
||||
self.assertEqual(str(s.type), 'SOCK_STREAM')
|
||||
|
||||
def test_socket_consistent_sock_type(self):
|
||||
SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', 0)
|
||||
|
|
|
@ -381,7 +381,7 @@ def test_str_for_enums(self):
|
|||
# Make sure that the PROTOCOL_* constants have enum-like string
|
||||
# reprs.
|
||||
proto = ssl.PROTOCOL_TLS
|
||||
self.assertEqual(str(proto), '_SSLMethod.PROTOCOL_TLS')
|
||||
self.assertEqual(str(proto), 'PROTOCOL_TLS')
|
||||
ctx = ssl.SSLContext(proto)
|
||||
self.assertIs(ctx.protocol, proto)
|
||||
|
||||
|
|
|
@ -1467,18 +1467,18 @@ class Str(str, enum.Enum):
|
|||
ABC = 'abc'
|
||||
# Testing Unicode formatting strings...
|
||||
self.assertEqual("%s, %s" % (Str.ABC, Str.ABC),
|
||||
'Str.ABC, Str.ABC')
|
||||
'ABC, ABC')
|
||||
self.assertEqual("%s, %s, %d, %i, %u, %f, %5.2f" %
|
||||
(Str.ABC, Str.ABC,
|
||||
Int.IDES, Int.IDES, Int.IDES,
|
||||
Float.PI, Float.PI),
|
||||
'Str.ABC, Str.ABC, 15, 15, 15, 3.141593, 3.14')
|
||||
'ABC, ABC, 15, 15, 15, 3.141593, 3.14')
|
||||
|
||||
# formatting jobs delegated from the string implementation:
|
||||
self.assertEqual('...%(foo)s...' % {'foo':Str.ABC},
|
||||
'...Str.ABC...')
|
||||
'...ABC...')
|
||||
self.assertEqual('...%(foo)s...' % {'foo':Int.IDES},
|
||||
'...Int.IDES...')
|
||||
'...IDES...')
|
||||
self.assertEqual('...%(foo)i...' % {'foo':Int.IDES},
|
||||
'...15...')
|
||||
self.assertEqual('...%(foo)d...' % {'foo':Int.IDES},
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Enum's `repr()` and `str()` have changed: `repr()` is now *EnumClass.MemberName*
|
||||
and `str()` is *MemberName*. Additionally, stdlib Enum's whose contents are
|
||||
available as module attributes, such as `RegexFlag.IGNORECASE`, have their
|
||||
`repr()` as *module.name*, e.g. `re.IGNORECASE`.
|
|
@ -0,0 +1,3 @@
|
|||
Enum: adjust ``repr()`` to show only enum and member name (not value, nor
|
||||
angle brackets) and ``str()`` to show only member name. Update and improve
|
||||
documentation to match.
|
Loading…
Reference in a new issue