summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorEthan Furman <ethan@stoneleaf.us>2021-04-21 17:20:44 (GMT)
committerGitHub <noreply@github.com>2021-04-21 17:20:44 (GMT)
commita02cb474f9c097c83cd444a47e9fb5f99b4aaf45 (patch)
treec9ebd2e0b7762ad1ca1f986966cb2ca02ea7fa6d /Lib/test
parent56c95dfe271b1242bdc8163d4677e311552c00cb (diff)
downloadcpython-a02cb474f9c097c83cd444a47e9fb5f99b4aaf45.zip
cpython-a02cb474f9c097c83cd444a47e9fb5f99b4aaf45.tar.gz
cpython-a02cb474f9c097c83cd444a47e9fb5f99b4aaf45.tar.bz2
bpo-38659: [Enum] add _simple_enum decorator (GH-25497)
add: * `_simple_enum` decorator to transform a normal class into an enum * `_test_simple_enum` function to compare * `_old_convert_` to enable checking `_convert_` generated enums `_simple_enum` takes a normal class and converts it into an enum: @simple_enum(Enum) class Color: RED = 1 GREEN = 2 BLUE = 3 `_old_convert_` works much like` _convert_` does, using the original logic: # in a test file import socket, enum CheckedAddressFamily = enum._old_convert_( enum.IntEnum, 'AddressFamily', 'socket', lambda C: C.isupper() and C.startswith('AF_'), source=_socket, ) `_test_simple_enum` takes a traditional enum and a simple enum and compares the two: # in the REPL or the same module as Color class CheckedColor(Enum): RED = 1 GREEN = 2 BLUE = 3 _test_simple_enum(CheckedColor, Color) _test_simple_enum(CheckedAddressFamily, socket.AddressFamily) Any important differences will raise a TypeError
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_ast.py30
-rw-r--r--Lib/test/test_enum.py61
-rw-r--r--Lib/test/test_httplib.py145
-rw-r--r--Lib/test/test_pstats.py20
-rw-r--r--Lib/test/test_signal.py27
-rwxr-xr-xLib/test/test_socket.py35
-rw-r--r--Lib/test/test_ssl.py153
-rw-r--r--Lib/test/test_unicode.py9
-rwxr-xr-xLib/test/test_uuid.py8
9 files changed, 478 insertions, 10 deletions
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 6824958..80d24e9 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -1,6 +1,7 @@
import ast
import builtins
import dis
+import enum
import os
import sys
import types
@@ -698,6 +699,35 @@ class AST_Tests(unittest.TestCase):
with self.assertRaisesRegex(ValueError, f"Name node can't be used with '{constant}' constant"):
compile(expr, "<test>", "eval")
+ def test_precedence_enum(self):
+ class _Precedence(enum.IntEnum):
+ """Precedence table that originated from python grammar."""
+ TUPLE = enum.auto()
+ YIELD = enum.auto() # 'yield', 'yield from'
+ TEST = enum.auto() # 'if'-'else', 'lambda'
+ OR = enum.auto() # 'or'
+ AND = enum.auto() # 'and'
+ NOT = enum.auto() # 'not'
+ CMP = enum.auto() # '<', '>', '==', '>=', '<=', '!=',
+ # 'in', 'not in', 'is', 'is not'
+ EXPR = enum.auto()
+ BOR = EXPR # '|'
+ BXOR = enum.auto() # '^'
+ BAND = enum.auto() # '&'
+ SHIFT = enum.auto() # '<<', '>>'
+ ARITH = enum.auto() # '+', '-'
+ TERM = enum.auto() # '*', '@', '/', '%', '//'
+ FACTOR = enum.auto() # unary '+', '-', '~'
+ POWER = enum.auto() # '**'
+ AWAIT = enum.auto() # 'await'
+ ATOM = enum.auto()
+ def next(self):
+ try:
+ return self.__class__(self + 1)
+ except ValueError:
+ return self
+ enum._test_simple_enum(_Precedence, ast._Precedence)
+
class ASTHelpers_Test(unittest.TestCase):
maxDiff = None
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index b9d7f96..d946dd5 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -8,7 +8,7 @@ import unittest
import threading
from collections import OrderedDict
from enum import Enum, IntEnum, StrEnum, EnumType, Flag, IntFlag, unique, auto
-from enum import STRICT, CONFORM, EJECT, KEEP
+from enum import STRICT, CONFORM, EJECT, KEEP, _simple_enum, _test_simple_enum
from io import StringIO
from pickle import dumps, loads, PicklingError, HIGHEST_PROTOCOL
from test import support
@@ -2511,10 +2511,13 @@ class TestFlag(unittest.TestCase):
d = 6
#
self.assertRaisesRegex(ValueError, 'invalid value: 7', Iron, 7)
+ #
self.assertIs(Water(7), Water.ONE|Water.TWO)
self.assertIs(Water(~9), Water.TWO)
+ #
self.assertEqual(Space(7), 7)
self.assertTrue(type(Space(7)) is int)
+ #
self.assertEqual(list(Bizarre), [Bizarre.c])
self.assertIs(Bizarre(3), Bizarre.b)
self.assertIs(Bizarre(6), Bizarre.d)
@@ -3053,16 +3056,20 @@ class TestIntFlag(unittest.TestCase):
EIGHT = 8
self.assertIs(Space._boundary_, EJECT)
#
+ #
class Bizarre(IntFlag, boundary=KEEP):
b = 3
c = 4
d = 6
#
self.assertRaisesRegex(ValueError, 'invalid value: 5', Iron, 5)
+ #
self.assertIs(Water(7), Water.ONE|Water.TWO)
self.assertIs(Water(~9), Water.TWO)
+ #
self.assertEqual(Space(7), 7)
self.assertTrue(type(Space(7)) is int)
+ #
self.assertEqual(list(Bizarre), [Bizarre.c])
self.assertIs(Bizarre(3), Bizarre.b)
self.assertIs(Bizarre(6), Bizarre.d)
@@ -3577,6 +3584,41 @@ class TestStdLib(unittest.TestCase):
if failed:
self.fail("result does not equal expected, see print above")
+ def test_test_simple_enum(self):
+ @_simple_enum(Enum)
+ class SimpleColor:
+ RED = 1
+ GREEN = 2
+ BLUE = 3
+ class CheckedColor(Enum):
+ RED = 1
+ GREEN = 2
+ BLUE = 3
+ self.assertTrue(_test_simple_enum(CheckedColor, SimpleColor) is None)
+ SimpleColor.GREEN._value_ = 9
+ self.assertRaisesRegex(
+ TypeError, "enum mismatch",
+ _test_simple_enum, CheckedColor, SimpleColor,
+ )
+ class CheckedMissing(IntFlag, boundary=KEEP):
+ SIXTY_FOUR = 64
+ ONE_TWENTY_EIGHT = 128
+ TWENTY_FORTY_EIGHT = 2048
+ ALL = 2048 + 128 + 64 + 12
+ CM = CheckedMissing
+ self.assertEqual(list(CheckedMissing), [CM.SIXTY_FOUR, CM.ONE_TWENTY_EIGHT, CM.TWENTY_FORTY_EIGHT])
+ #
+ @_simple_enum(IntFlag, boundary=KEEP)
+ class Missing:
+ SIXTY_FOUR = 64
+ ONE_TWENTY_EIGHT = 128
+ TWENTY_FORTY_EIGHT = 2048
+ ALL = 2048 + 128 + 64 + 12
+ M = Missing
+ self.assertEqual(list(CheckedMissing), [M.SIXTY_FOUR, M.ONE_TWENTY_EIGHT, M.TWENTY_FORTY_EIGHT])
+ #
+ _test_simple_enum(CheckedMissing, Missing)
+
class MiscTestCase(unittest.TestCase):
def test__all__(self):
@@ -3592,6 +3634,13 @@ CONVERT_TEST_NAME_A = 5 # This one should sort first.
CONVERT_TEST_NAME_E = 5
CONVERT_TEST_NAME_F = 5
+CONVERT_STRING_TEST_NAME_D = 5
+CONVERT_STRING_TEST_NAME_C = 5
+CONVERT_STRING_TEST_NAME_B = 5
+CONVERT_STRING_TEST_NAME_A = 5 # This one should sort first.
+CONVERT_STRING_TEST_NAME_E = 5
+CONVERT_STRING_TEST_NAME_F = 5
+
class TestIntEnumConvert(unittest.TestCase):
def test_convert_value_lookup_priority(self):
test_type = enum.IntEnum._convert_(
@@ -3639,14 +3688,16 @@ class TestIntEnumConvert(unittest.TestCase):
filter=lambda x: x.startswith('CONVERT_TEST_'))
def test_convert_repr_and_str(self):
+ # reset global constants, as previous tests could have converted the
+ # integer values to enums
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')
+ filter=lambda x: x.startswith('CONVERT_STRING_TEST_'))
+ self.assertEqual(repr(test_type.CONVERT_STRING_TEST_NAME_A), '%s.CONVERT_STRING_TEST_NAME_A' % module)
+ self.assertEqual(str(test_type.CONVERT_STRING_TEST_NAME_A), 'CONVERT_STRING_TEST_NAME_A')
+ self.assertEqual(format(test_type.CONVERT_STRING_TEST_NAME_A), '5')
# global names for StrEnum._convert_ test
CONVERT_STR_TEST_2 = 'goodbye'
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
index 5fb4592..438c2eb 100644
--- a/Lib/test/test_httplib.py
+++ b/Lib/test/test_httplib.py
@@ -1,3 +1,4 @@
+import enum
import errno
from http import client, HTTPStatus
import io
@@ -524,6 +525,150 @@ class BasicTest(TestCase):
# see issue40084
self.assertTrue({'description', 'name', 'phrase', 'value'} <= set(dir(HTTPStatus(404))))
+ def test_simple_httpstatus(self):
+ class CheckedHTTPStatus(enum.IntEnum):
+ """HTTP status codes and reason phrases
+
+ Status codes from the following RFCs are all observed:
+
+ * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
+ * RFC 6585: Additional HTTP Status Codes
+ * RFC 3229: Delta encoding in HTTP
+ * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518
+ * RFC 5842: Binding Extensions to WebDAV
+ * RFC 7238: Permanent Redirect
+ * RFC 2295: Transparent Content Negotiation in HTTP
+ * RFC 2774: An HTTP Extension Framework
+ * RFC 7725: An HTTP Status Code to Report Legal Obstacles
+ * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2)
+ * RFC 2324: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0)
+ * RFC 8297: An HTTP Status Code for Indicating Hints
+ * RFC 8470: Using Early Data in HTTP
+ """
+ def __new__(cls, value, phrase, description=''):
+ obj = int.__new__(cls, value)
+ obj._value_ = value
+
+ obj.phrase = phrase
+ obj.description = description
+ return obj
+ # informational
+ CONTINUE = 100, 'Continue', 'Request received, please continue'
+ SWITCHING_PROTOCOLS = (101, 'Switching Protocols',
+ 'Switching to new protocol; obey Upgrade header')
+ PROCESSING = 102, 'Processing'
+ EARLY_HINTS = 103, 'Early Hints'
+ # success
+ OK = 200, 'OK', 'Request fulfilled, document follows'
+ CREATED = 201, 'Created', 'Document created, URL follows'
+ ACCEPTED = (202, 'Accepted',
+ 'Request accepted, processing continues off-line')
+ NON_AUTHORITATIVE_INFORMATION = (203,
+ 'Non-Authoritative Information', 'Request fulfilled from cache')
+ NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows'
+ RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input'
+ PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows'
+ MULTI_STATUS = 207, 'Multi-Status'
+ ALREADY_REPORTED = 208, 'Already Reported'
+ IM_USED = 226, 'IM Used'
+ # redirection
+ MULTIPLE_CHOICES = (300, 'Multiple Choices',
+ 'Object has several resources -- see URI list')
+ MOVED_PERMANENTLY = (301, 'Moved Permanently',
+ 'Object moved permanently -- see URI list')
+ FOUND = 302, 'Found', 'Object moved temporarily -- see URI list'
+ SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list'
+ NOT_MODIFIED = (304, 'Not Modified',
+ 'Document has not changed since given time')
+ USE_PROXY = (305, 'Use Proxy',
+ 'You must use proxy specified in Location to access this resource')
+ TEMPORARY_REDIRECT = (307, 'Temporary Redirect',
+ 'Object moved temporarily -- see URI list')
+ PERMANENT_REDIRECT = (308, 'Permanent Redirect',
+ 'Object moved permanently -- see URI list')
+ # client error
+ BAD_REQUEST = (400, 'Bad Request',
+ 'Bad request syntax or unsupported method')
+ UNAUTHORIZED = (401, 'Unauthorized',
+ 'No permission -- see authorization schemes')
+ PAYMENT_REQUIRED = (402, 'Payment Required',
+ 'No payment -- see charging schemes')
+ FORBIDDEN = (403, 'Forbidden',
+ 'Request forbidden -- authorization will not help')
+ NOT_FOUND = (404, 'Not Found',
+ 'Nothing matches the given URI')
+ METHOD_NOT_ALLOWED = (405, 'Method Not Allowed',
+ 'Specified method is invalid for this resource')
+ NOT_ACCEPTABLE = (406, 'Not Acceptable',
+ 'URI not available in preferred format')
+ PROXY_AUTHENTICATION_REQUIRED = (407,
+ 'Proxy Authentication Required',
+ 'You must authenticate with this proxy before proceeding')
+ REQUEST_TIMEOUT = (408, 'Request Timeout',
+ 'Request timed out; try again later')
+ CONFLICT = 409, 'Conflict', 'Request conflict'
+ GONE = (410, 'Gone',
+ 'URI no longer exists and has been permanently removed')
+ LENGTH_REQUIRED = (411, 'Length Required',
+ 'Client must specify Content-Length')
+ PRECONDITION_FAILED = (412, 'Precondition Failed',
+ 'Precondition in headers is false')
+ REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large',
+ 'Entity is too large')
+ REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long',
+ 'URI is too long')
+ UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type',
+ 'Entity body in unsupported format')
+ REQUESTED_RANGE_NOT_SATISFIABLE = (416,
+ 'Requested Range Not Satisfiable',
+ 'Cannot satisfy request range')
+ EXPECTATION_FAILED = (417, 'Expectation Failed',
+ 'Expect condition could not be satisfied')
+ IM_A_TEAPOT = (418, 'I\'m a Teapot',
+ 'Server refuses to brew coffee because it is a teapot.')
+ MISDIRECTED_REQUEST = (421, 'Misdirected Request',
+ 'Server is not able to produce a response')
+ UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity'
+ LOCKED = 423, 'Locked'
+ FAILED_DEPENDENCY = 424, 'Failed Dependency'
+ TOO_EARLY = 425, 'Too Early'
+ UPGRADE_REQUIRED = 426, 'Upgrade Required'
+ PRECONDITION_REQUIRED = (428, 'Precondition Required',
+ 'The origin server requires the request to be conditional')
+ TOO_MANY_REQUESTS = (429, 'Too Many Requests',
+ 'The user has sent too many requests in '
+ 'a given amount of time ("rate limiting")')
+ REQUEST_HEADER_FIELDS_TOO_LARGE = (431,
+ 'Request Header Fields Too Large',
+ 'The server is unwilling to process the request because its header '
+ 'fields are too large')
+ UNAVAILABLE_FOR_LEGAL_REASONS = (451,
+ 'Unavailable For Legal Reasons',
+ 'The server is denying access to the '
+ 'resource as a consequence of a legal demand')
+ # server errors
+ INTERNAL_SERVER_ERROR = (500, 'Internal Server Error',
+ 'Server got itself in trouble')
+ NOT_IMPLEMENTED = (501, 'Not Implemented',
+ 'Server does not support this operation')
+ BAD_GATEWAY = (502, 'Bad Gateway',
+ 'Invalid responses from another server/proxy')
+ SERVICE_UNAVAILABLE = (503, 'Service Unavailable',
+ 'The server cannot process the request due to a high load')
+ GATEWAY_TIMEOUT = (504, 'Gateway Timeout',
+ 'The gateway server did not receive a timely response')
+ HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported',
+ 'Cannot fulfill request')
+ VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates'
+ INSUFFICIENT_STORAGE = 507, 'Insufficient Storage'
+ LOOP_DETECTED = 508, 'Loop Detected'
+ NOT_EXTENDED = 510, 'Not Extended'
+ NETWORK_AUTHENTICATION_REQUIRED = (511,
+ 'Network Authentication Required',
+ 'The client needs to authenticate to gain network access')
+ enum._test_simple_enum(CheckedHTTPStatus, HTTPStatus)
+
+
def test_status_lines(self):
# Test HTTP status lines
diff --git a/Lib/test/test_pstats.py b/Lib/test/test_pstats.py
index 4f78b99..acc2fa5 100644
--- a/Lib/test/test_pstats.py
+++ b/Lib/test/test_pstats.py
@@ -3,6 +3,7 @@ import unittest
from test import support
from io import StringIO
from pstats import SortKey
+from enum import StrEnum, _test_simple_enum
import pstats
import cProfile
@@ -67,6 +68,25 @@ class StatsTestCase(unittest.TestCase):
self.assertEqual(
self.stats.sort_type,
self.stats.sort_arg_dict_default[member.value][-1])
+ class CheckedSortKey(StrEnum):
+ CALLS = 'calls', 'ncalls'
+ CUMULATIVE = 'cumulative', 'cumtime'
+ FILENAME = 'filename', 'module'
+ LINE = 'line'
+ NAME = 'name'
+ NFL = 'nfl'
+ PCALLS = 'pcalls'
+ STDNAME = 'stdname'
+ TIME = 'time', 'tottime'
+ def __new__(cls, *values):
+ value = values[0]
+ obj = str.__new__(cls, value)
+ obj._value_ = value
+ for other_value in values[1:]:
+ cls._value2member_map_[other_value] = obj
+ obj._all_values = values
+ return obj
+ _test_simple_enum(CheckedSortKey, SortKey)
def test_sort_starts_mix(self):
self.assertRaises(TypeError, self.stats.sort_stats,
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 8f943be..06b644e 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -1,3 +1,4 @@
+import enum
import errno
import os
import random
@@ -33,6 +34,32 @@ class GenericTests(unittest.TestCase):
self.assertIsInstance(sig, signal.Signals)
self.assertEqual(sys.platform, "win32")
+ CheckedSignals = enum._old_convert_(
+ enum.IntEnum, 'Signals', 'signal',
+ lambda name:
+ name.isupper()
+ and (name.startswith('SIG') and not name.startswith('SIG_'))
+ or name.startswith('CTRL_'),
+ source=signal,
+ )
+ enum._test_simple_enum(CheckedSignals, signal.Signals)
+
+ CheckedHandlers = enum._old_convert_(
+ enum.IntEnum, 'Handlers', 'signal',
+ lambda name: name in ('SIG_DFL', 'SIG_IGN'),
+ source=signal,
+ )
+ enum._test_simple_enum(CheckedHandlers, signal.Handlers)
+
+ Sigmasks = getattr(signal, 'Sigmasks', None)
+ if Sigmasks is not None:
+ CheckedSigmasks = enum._old_convert_(
+ enum.IntEnum, 'Sigmasks', 'signal',
+ lambda name: name in ('SIG_BLOCK', 'SIG_UNBLOCK', 'SIG_SETMASK'),
+ source=signal,
+ )
+ enum._test_simple_enum(CheckedSigmasks, Sigmasks)
+
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
class PosixTests(unittest.TestCase):
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index f91e000..43a1d5b 100755
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -1941,6 +1941,41 @@ class GeneralModuleTests(unittest.TestCase):
fileno=afile.fileno())
self.assertEqual(cm.exception.errno, errno.ENOTSOCK)
+ def test_addressfamily_enum(self):
+ import _socket, enum
+ CheckedAddressFamily = enum._old_convert_(
+ enum.IntEnum, 'AddressFamily', 'socket',
+ lambda C: C.isupper() and C.startswith('AF_'),
+ source=_socket,
+ )
+ enum._test_simple_enum(CheckedAddressFamily, socket.AddressFamily)
+
+ def test_socketkind_enum(self):
+ import _socket, enum
+ CheckedSocketKind = enum._old_convert_(
+ enum.IntEnum, 'SocketKind', 'socket',
+ lambda C: C.isupper() and C.startswith('SOCK_'),
+ source=_socket,
+ )
+ enum._test_simple_enum(CheckedSocketKind, socket.SocketKind)
+
+ def test_msgflag_enum(self):
+ import _socket, enum
+ CheckedMsgFlag = enum._old_convert_(
+ enum.IntFlag, 'MsgFlag', 'socket',
+ lambda C: C.isupper() and C.startswith('MSG_'),
+ source=_socket,
+ )
+ enum._test_simple_enum(CheckedMsgFlag, socket.MsgFlag)
+
+ def test_addressinfo_enum(self):
+ import _socket, enum
+ CheckedAddressInfo = enum._old_convert_(
+ enum.IntFlag, 'AddressInfo', 'socket',
+ lambda C: C.isupper() and C.startswith('AI_'),
+ source=_socket)
+ enum._test_simple_enum(CheckedAddressInfo, socket.AddressInfo)
+
@unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.')
class BasicCANTest(unittest.TestCase):
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 697971e..0b8cef6 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -12,6 +12,8 @@ from test.support import warnings_helper
import socket
import select
import time
+import datetime
+import enum
import gc
import os
import errno
@@ -31,7 +33,7 @@ except ImportError:
ssl = import_helper.import_module("ssl")
-from ssl import TLSVersion, _TLSContentType, _TLSMessageType
+from ssl import TLSVersion, _TLSContentType, _TLSMessageType, _TLSAlertType
Py_DEBUG = hasattr(sys, 'gettotalrefcount')
Py_DEBUG_WIN32 = Py_DEBUG and sys.platform == 'win32'
@@ -4697,6 +4699,155 @@ class TestSSLDebug(unittest.TestCase):
s.connect((HOST, server.port))
+class TestEnumerations(unittest.TestCase):
+
+ def test_tlsversion(self):
+ class CheckedTLSVersion(enum.IntEnum):
+ MINIMUM_SUPPORTED = _ssl.PROTO_MINIMUM_SUPPORTED
+ SSLv3 = _ssl.PROTO_SSLv3
+ TLSv1 = _ssl.PROTO_TLSv1
+ TLSv1_1 = _ssl.PROTO_TLSv1_1
+ TLSv1_2 = _ssl.PROTO_TLSv1_2
+ TLSv1_3 = _ssl.PROTO_TLSv1_3
+ MAXIMUM_SUPPORTED = _ssl.PROTO_MAXIMUM_SUPPORTED
+ enum._test_simple_enum(CheckedTLSVersion, TLSVersion)
+
+ def test_tlscontenttype(self):
+ class Checked_TLSContentType(enum.IntEnum):
+ """Content types (record layer)
+
+ See RFC 8446, section B.1
+ """
+ CHANGE_CIPHER_SPEC = 20
+ ALERT = 21
+ HANDSHAKE = 22
+ APPLICATION_DATA = 23
+ # pseudo content types
+ HEADER = 0x100
+ INNER_CONTENT_TYPE = 0x101
+ enum._test_simple_enum(Checked_TLSContentType, _TLSContentType)
+
+ def test_tlsalerttype(self):
+ class Checked_TLSAlertType(enum.IntEnum):
+ """Alert types for TLSContentType.ALERT messages
+
+ See RFC 8466, section B.2
+ """
+ CLOSE_NOTIFY = 0
+ UNEXPECTED_MESSAGE = 10
+ BAD_RECORD_MAC = 20
+ DECRYPTION_FAILED = 21
+ RECORD_OVERFLOW = 22
+ DECOMPRESSION_FAILURE = 30
+ HANDSHAKE_FAILURE = 40
+ NO_CERTIFICATE = 41
+ BAD_CERTIFICATE = 42
+ UNSUPPORTED_CERTIFICATE = 43
+ CERTIFICATE_REVOKED = 44
+ CERTIFICATE_EXPIRED = 45
+ CERTIFICATE_UNKNOWN = 46
+ ILLEGAL_PARAMETER = 47
+ UNKNOWN_CA = 48
+ ACCESS_DENIED = 49
+ DECODE_ERROR = 50
+ DECRYPT_ERROR = 51
+ EXPORT_RESTRICTION = 60
+ PROTOCOL_VERSION = 70
+ INSUFFICIENT_SECURITY = 71
+ INTERNAL_ERROR = 80
+ INAPPROPRIATE_FALLBACK = 86
+ USER_CANCELED = 90
+ NO_RENEGOTIATION = 100
+ MISSING_EXTENSION = 109
+ UNSUPPORTED_EXTENSION = 110
+ CERTIFICATE_UNOBTAINABLE = 111
+ UNRECOGNIZED_NAME = 112
+ BAD_CERTIFICATE_STATUS_RESPONSE = 113
+ BAD_CERTIFICATE_HASH_VALUE = 114
+ UNKNOWN_PSK_IDENTITY = 115
+ CERTIFICATE_REQUIRED = 116
+ NO_APPLICATION_PROTOCOL = 120
+ enum._test_simple_enum(Checked_TLSAlertType, _TLSAlertType)
+
+ def test_tlsmessagetype(self):
+ class Checked_TLSMessageType(enum.IntEnum):
+ """Message types (handshake protocol)
+
+ See RFC 8446, section B.3
+ """
+ HELLO_REQUEST = 0
+ CLIENT_HELLO = 1
+ SERVER_HELLO = 2
+ HELLO_VERIFY_REQUEST = 3
+ NEWSESSION_TICKET = 4
+ END_OF_EARLY_DATA = 5
+ HELLO_RETRY_REQUEST = 6
+ ENCRYPTED_EXTENSIONS = 8
+ CERTIFICATE = 11
+ SERVER_KEY_EXCHANGE = 12
+ CERTIFICATE_REQUEST = 13
+ SERVER_DONE = 14
+ CERTIFICATE_VERIFY = 15
+ CLIENT_KEY_EXCHANGE = 16
+ FINISHED = 20
+ CERTIFICATE_URL = 21
+ CERTIFICATE_STATUS = 22
+ SUPPLEMENTAL_DATA = 23
+ KEY_UPDATE = 24
+ NEXT_PROTO = 67
+ MESSAGE_HASH = 254
+ CHANGE_CIPHER_SPEC = 0x0101
+ enum._test_simple_enum(Checked_TLSMessageType, _TLSMessageType)
+
+ def test_sslmethod(self):
+ Checked_SSLMethod = enum._old_convert_(
+ enum.IntEnum, '_SSLMethod', 'ssl',
+ lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
+ source=ssl._ssl,
+ )
+ enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod)
+
+ def test_options(self):
+ CheckedOptions = enum._old_convert_(
+ enum.FlagEnum, 'Options', 'ssl',
+ lambda name: name.startswith('OP_'),
+ source=ssl._ssl,
+ )
+ enum._test_simple_enum(CheckedOptions, ssl.Options)
+
+
+ def test_alertdescription(self):
+ CheckedAlertDescription = enum._old_convert_(
+ enum.IntEnum, 'AlertDescription', 'ssl',
+ lambda name: name.startswith('ALERT_DESCRIPTION_'),
+ source=ssl._ssl,
+ )
+ enum._test_simple_enum(CheckedAlertDescription, ssl.AlertDescription)
+
+ def test_sslerrornumber(self):
+ Checked_SSLMethod = enum._old_convert_(
+ enum.IntEnum, '_SSLMethod', 'ssl',
+ lambda name: name.startswith('PROTOCOL_') and name != 'PROTOCOL_SSLv23',
+ source=ssl._ssl,
+ )
+ enum._test_simple_enum(Checked_SSLMethod, ssl._SSLMethod)
+
+ def test_verifyflags(self):
+ CheckedVerifyFlags = enum._old_convert_(
+ enum.FlagEnum, 'VerifyFlags', 'ssl',
+ lambda name: name.startswith('VERIFY_'),
+ source=ssl._ssl,
+ )
+ enum._test_simple_enum(CheckedVerifyFlags, ssl.VerifyFlags)
+
+ def test_verifymode(self):
+ CheckedVerifyMode = enum._old_convert_(
+ enum.IntEnum, 'VerifyMode', 'ssl',
+ lambda name: name.startswith('CERT_'),
+ source=ssl._ssl,
+ )
+ enum._test_simple_enum(CheckedVerifyMode, ssl.VerifyMode)
+
def test_main(verbose=False):
if support.verbose:
plats = {
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index d47cf28..0e6cbb6 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -1463,20 +1463,21 @@ class UnicodeTest(string_tests.CommonTest,
PI = 3.1415926
class Int(enum.IntEnum):
IDES = 15
- class Str(str, enum.Enum):
+ class Str(enum.StrEnum):
+ # StrEnum uses the value and not the name for %s etc.
ABC = 'abc'
# Testing Unicode formatting strings...
self.assertEqual("%s, %s" % (Str.ABC, Str.ABC),
- 'ABC, 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),
- 'ABC, 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},
- '...ABC...')
+ '...abc...')
self.assertEqual('...%(foo)s...' % {'foo':Int.IDES},
'...IDES...')
self.assertEqual('...%(foo)i...' % {'foo':Int.IDES},
diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py
index d6a8333..3f56192 100755
--- a/Lib/test/test_uuid.py
+++ b/Lib/test/test_uuid.py
@@ -4,6 +4,7 @@ from test.support import import_helper
import builtins
import contextlib
import copy
+import enum
import io
import os
import pickle
@@ -31,6 +32,13 @@ def mock_get_command_stdout(data):
class BaseTestUUID:
uuid = None
+ def test_safe_uuid_enum(self):
+ class CheckedSafeUUID(enum.Enum):
+ safe = 0
+ unsafe = -1
+ unknown = None
+ enum._test_simple_enum(CheckedSafeUUID, py_uuid.SafeUUID)
+
def test_UUID(self):
equal = self.assertEqual
ascending = []