Merge pull request #4073 from youknowone/unittests

Unittests update from CPython 3.10.6
This commit is contained in:
Jeong YunWon
2022-08-15 06:01:26 +09:00
committed by GitHub
11 changed files with 3620 additions and 834 deletions

5
Lib/getpass.py vendored
View File

@@ -7,7 +7,6 @@ GetPassWarning - This UserWarning is issued when getpass() cannot prevent
echoing of the password contents while reading.
On Windows, the msvcrt module will be used.
On the Mac EasyDialogs.AskPassword is used, if available.
"""
@@ -53,7 +52,7 @@ def unix_getpass(prompt='Password: ', stream=None):
stack.enter_context(input)
if not stream:
stream = input
except OSError as e:
except OSError:
# If that fails, see if stdin can be controlled.
stack.close()
try:
@@ -96,7 +95,7 @@ def unix_getpass(prompt='Password: ', stream=None):
def win_getpass(prompt='Password: ', stream=None):
"""Prompt for password with echo off, using Windows getch()."""
"""Prompt for password with echo off, using Windows getwch()."""
if sys.stdin is not sys.__stdin__:
return fallback_getpass(prompt, stream)

154
Lib/glob.py vendored
View File

@@ -1,12 +1,16 @@
"""Filename globbing utility."""
import contextlib
import os
import re
import fnmatch
import itertools
import stat
import sys
__all__ = ["glob", "iglob", "escape"]
def glob(pathname, *, recursive=False):
def glob(pathname, *, root_dir=None, dir_fd=None, recursive=False):
"""Return a list of paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la
@@ -17,9 +21,9 @@ def glob(pathname, *, recursive=False):
If recursive is true, the pattern '**' will match any files and
zero or more directories and subdirectories.
"""
return list(iglob(pathname, recursive=recursive))
return list(iglob(pathname, root_dir=root_dir, dir_fd=dir_fd, recursive=recursive))
def iglob(pathname, *, recursive=False):
def iglob(pathname, *, root_dir=None, dir_fd=None, recursive=False):
"""Return an iterator which yields the paths matching a pathname pattern.
The pattern may contain simple shell-style wildcards a la
@@ -30,35 +34,45 @@ def iglob(pathname, *, recursive=False):
If recursive is true, the pattern '**' will match any files and
zero or more directories and subdirectories.
"""
it = _iglob(pathname, recursive, False)
if recursive and _isrecursive(pathname):
s = next(it) # skip empty string
assert not s
sys.audit("glob.glob", pathname, recursive)
sys.audit("glob.glob/2", pathname, recursive, root_dir, dir_fd)
if root_dir is not None:
root_dir = os.fspath(root_dir)
else:
root_dir = pathname[:0]
it = _iglob(pathname, root_dir, dir_fd, recursive, False)
if not pathname or recursive and _isrecursive(pathname[:2]):
try:
s = next(it) # skip empty string
if s:
it = itertools.chain((s,), it)
except StopIteration:
pass
return it
def _iglob(pathname, recursive, dironly):
def _iglob(pathname, root_dir, dir_fd, recursive, dironly):
dirname, basename = os.path.split(pathname)
if not has_magic(pathname):
assert not dironly
if basename:
if os.path.lexists(pathname):
if _lexists(_join(root_dir, pathname), dir_fd):
yield pathname
else:
# Patterns ending with a slash should match only directories
if os.path.isdir(dirname):
if _isdir(_join(root_dir, dirname), dir_fd):
yield pathname
return
if not dirname:
if recursive and _isrecursive(basename):
yield from _glob2(dirname, basename, dironly)
yield from _glob2(root_dir, basename, dir_fd, dironly)
else:
yield from _glob1(dirname, basename, dironly)
yield from _glob1(root_dir, basename, dir_fd, dironly)
return
# `os.path.split()` returns the argument itself as a dirname if it is a
# drive or UNC path. Prevent an infinite recursion if a drive or UNC path
# contains magic characters (i.e. r'\\?\C:').
if dirname != pathname and has_magic(dirname):
dirs = _iglob(dirname, recursive, True)
dirs = _iglob(dirname, root_dir, dir_fd, recursive, True)
else:
dirs = [dirname]
if has_magic(basename):
@@ -69,76 +83,125 @@ def _iglob(pathname, recursive, dironly):
else:
glob_in_dir = _glob0
for dirname in dirs:
for name in glob_in_dir(dirname, basename, dironly):
for name in glob_in_dir(_join(root_dir, dirname), basename, dir_fd, dironly):
yield os.path.join(dirname, name)
# These 2 helper functions non-recursively glob inside a literal directory.
# They return a list of basenames. _glob1 accepts a pattern while _glob0
# takes a literal basename (so it only has to check for its existence).
def _glob1(dirname, pattern, dironly):
names = list(_iterdir(dirname, dironly))
def _glob1(dirname, pattern, dir_fd, dironly):
names = _listdir(dirname, dir_fd, dironly)
if not _ishidden(pattern):
names = (x for x in names if not _ishidden(x))
return fnmatch.filter(names, pattern)
def _glob0(dirname, basename, dironly):
if not basename:
# `os.path.split()` returns an empty basename for paths ending with a
# directory separator. 'q*x/' should match only directories.
if os.path.isdir(dirname):
def _glob0(dirname, basename, dir_fd, dironly):
if basename:
if _lexists(_join(dirname, basename), dir_fd):
return [basename]
else:
if os.path.lexists(os.path.join(dirname, basename)):
# `os.path.split()` returns an empty basename for paths ending with a
# directory separator. 'q*x/' should match only directories.
if _isdir(dirname, dir_fd):
return [basename]
return []
# Following functions are not public but can be used by third-party code.
def glob0(dirname, pattern):
return _glob0(dirname, pattern, False)
return _glob0(dirname, pattern, None, False)
def glob1(dirname, pattern):
return _glob1(dirname, pattern, False)
return _glob1(dirname, pattern, None, False)
# This helper function recursively yields relative pathnames inside a literal
# directory.
def _glob2(dirname, pattern, dironly):
def _glob2(dirname, pattern, dir_fd, dironly):
assert _isrecursive(pattern)
yield pattern[:0]
yield from _rlistdir(dirname, dironly)
yield from _rlistdir(dirname, dir_fd, dironly)
# If dironly is false, yields all file names inside a directory.
# If dironly is true, yields only directory names.
def _iterdir(dirname, dironly):
if not dirname:
if isinstance(dirname, bytes):
dirname = bytes(os.curdir, 'ASCII')
else:
dirname = os.curdir
def _iterdir(dirname, dir_fd, dironly):
try:
with os.scandir(dirname) as it:
for entry in it:
try:
if not dironly or entry.is_dir():
yield entry.name
except OSError:
pass
fd = None
fsencode = None
if dir_fd is not None:
if dirname:
fd = arg = os.open(dirname, _dir_open_flags, dir_fd=dir_fd)
else:
arg = dir_fd
if isinstance(dirname, bytes):
fsencode = os.fsencode
elif dirname:
arg = dirname
elif isinstance(dirname, bytes):
arg = bytes(os.curdir, 'ASCII')
else:
arg = os.curdir
try:
with os.scandir(arg) as it:
for entry in it:
try:
if not dironly or entry.is_dir():
if fsencode is not None:
yield fsencode(entry.name)
else:
yield entry.name
except OSError:
pass
finally:
if fd is not None:
os.close(fd)
except OSError:
return
def _listdir(dirname, dir_fd, dironly):
with contextlib.closing(_iterdir(dirname, dir_fd, dironly)) as it:
return list(it)
# Recursively yields relative pathnames inside a literal directory.
def _rlistdir(dirname, dironly):
names = list(_iterdir(dirname, dironly))
def _rlistdir(dirname, dir_fd, dironly):
names = _listdir(dirname, dir_fd, dironly)
for x in names:
if not _ishidden(x):
yield x
path = os.path.join(dirname, x) if dirname else x
for y in _rlistdir(path, dironly):
yield os.path.join(x, y)
path = _join(dirname, x) if dirname else x
for y in _rlistdir(path, dir_fd, dironly):
yield _join(x, y)
def _lexists(pathname, dir_fd):
# Same as os.path.lexists(), but with dir_fd
if dir_fd is None:
return os.path.lexists(pathname)
try:
os.lstat(pathname, dir_fd=dir_fd)
except (OSError, ValueError):
return False
else:
return True
def _isdir(pathname, dir_fd):
# Same as os.path.isdir(), but with dir_fd
if dir_fd is None:
return os.path.isdir(pathname)
try:
st = os.stat(pathname, dir_fd=dir_fd)
except (OSError, ValueError):
return False
else:
return stat.S_ISDIR(st.st_mode)
def _join(dirname, basename):
# It is common if dirname or basename is empty
if not dirname or not basename:
return dirname or basename
return os.path.join(dirname, basename)
magic_check = re.compile('([*?[])')
magic_check_bytes = re.compile(b'([*?[])')
@@ -169,3 +232,6 @@ def escape(pathname):
else:
pathname = magic_check.sub(r'[\1]', pathname)
return drive + pathname
_dir_open_flags = os.O_RDONLY | getattr(os, 'O_DIRECTORY', 0)

4
Lib/heapq.py vendored
View File

@@ -597,5 +597,5 @@ except ImportError:
if __name__ == "__main__":
import doctest
print(doctest.testmod())
import doctest # pragma: no cover
print(doctest.testmod()) # pragma: no cover

2151
Lib/mailbox.py vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,342 +1,346 @@
"""Tests for C-implemented GenericAlias."""
import unittest
import pickle
import copy
from collections import (
defaultdict, deque, OrderedDict, Counter, UserDict, UserList
)
from collections.abc import *
from concurrent.futures import Future
from concurrent.futures.thread import _WorkItem
from contextlib import AbstractContextManager, AbstractAsyncContextManager
# XXX RUSTPYTHON TODO: from contextvars import ContextVar, Token
from dataclasses import Field
from functools import partial, partialmethod, cached_property
# XXX RUSTPYTHON TODO: from mailbox import Mailbox, _PartialFile
try:
import ctypes
except ImportError:
ctypes = None
from difflib import SequenceMatcher
from filecmp import dircmp
# XXX RUSTPYTHON TODO: from fileinput import FileInput
from itertools import chain
from http.cookies import Morsel
from multiprocessing.managers import ValueProxy
from multiprocessing.pool import ApplyResult
try:
from multiprocessing.shared_memory import ShareableList
except ImportError:
# multiprocessing.shared_memory is not available on e.g. Android
ShareableList = None
from multiprocessing.queues import SimpleQueue as MPSimpleQueue
from os import DirEntry
from re import Pattern, Match
from types import GenericAlias, MappingProxyType, AsyncGeneratorType
from tempfile import TemporaryDirectory, SpooledTemporaryFile
from urllib.parse import SplitResult, ParseResult
from unittest.case import _AssertRaisesContext
from queue import Queue, SimpleQueue
from weakref import WeakSet, ReferenceType, ref
import typing
from typing import TypeVar
T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')
class BaseTest(unittest.TestCase):
"""Test basics."""
generic_types = [type, tuple, list, dict, set, frozenset, enumerate,
defaultdict, deque,
SequenceMatcher,
dircmp,
# XXX RUSTPYTHON TODO: FileInput,
OrderedDict, Counter, UserDict, UserList,
Pattern, Match,
partialmethod, cached_property, # XXX RUSTPYTHON TODO: partial
# XXX RUSTPYTHON TODO: AbstractContextManager, AbstractAsyncContextManager,
Awaitable, Coroutine,
AsyncIterable, AsyncIterator,
AsyncGenerator, Generator,
Iterable, Iterator,
Reversible,
Container, Collection,
# XXX RUSTPYTHON TODO: Mailbox, _PartialFile,
# XXX RUSTPYTHON TODO: ContextVar, Token,
Field,
Set, MutableSet,
Mapping, MutableMapping, MappingView,
KeysView, ItemsView, ValuesView,
Sequence, MutableSequence,
MappingProxyType, AsyncGeneratorType,
DirEntry,
chain,
TemporaryDirectory, SpooledTemporaryFile,
Queue, SimpleQueue,
_AssertRaisesContext,
SplitResult, ParseResult,
ValueProxy, ApplyResult,
WeakSet, ReferenceType, ref,
ShareableList, MPSimpleQueue,
Future, _WorkItem,
Morsel]
if ctypes is not None:
generic_types.extend((ctypes.Array, ctypes.LibraryLoader))
def test_subscriptable(self):
for t in self.generic_types:
if t is None:
continue
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertIs(alias.__origin__, t)
self.assertEqual(alias.__args__, (int,))
self.assertEqual(alias.__parameters__, ())
def test_unsubscriptable(self):
for t in int, str, float, Sized, Hashable:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
with self.assertRaises(TypeError):
t[int]
def test_instantiate(self):
for t in tuple, list, dict, set, frozenset, defaultdict, deque:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertEqual(alias(), t())
if t is dict:
self.assertEqual(alias(iter([('a', 1), ('b', 2)])), dict(a=1, b=2))
self.assertEqual(alias(a=1, b=2), dict(a=1, b=2))
elif t is defaultdict:
def default():
return 'value'
a = alias(default)
d = defaultdict(default)
self.assertEqual(a['test'], d['test'])
else:
self.assertEqual(alias(iter((1, 2, 3))), t((1, 2, 3)))
def test_unbound_methods(self):
t = list[int]
a = t()
t.append(a, 'foo')
self.assertEqual(a, ['foo'])
x = t.__getitem__(a, 0)
self.assertEqual(x, 'foo')
self.assertEqual(t.__len__(a), 1)
def test_subclassing(self):
class C(list[int]):
pass
self.assertEqual(C.__bases__, (list,))
self.assertEqual(C.__class__, type)
def test_class_methods(self):
t = dict[int, None]
self.assertEqual(dict.fromkeys(range(2)), {0: None, 1: None}) # This works
self.assertEqual(t.fromkeys(range(2)), {0: None, 1: None}) # Should be equivalent
def test_no_chaining(self):
t = list[int]
with self.assertRaises(TypeError):
t[int]
def test_generic_subclass(self):
class MyList(list):
pass
t = MyList[int]
self.assertIs(t.__origin__, MyList)
self.assertEqual(t.__args__, (int,))
self.assertEqual(t.__parameters__, ())
def test_repr(self):
class MyList(list):
pass
self.assertEqual(repr(list[str]), 'list[str]')
self.assertEqual(repr(list[()]), 'list[()]')
self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]')
self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]'))
self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr
def test_exposed_type(self):
import types
a = types.GenericAlias(list, int)
self.assertEqual(str(a), 'list[int]')
self.assertIs(a.__origin__, list)
self.assertEqual(a.__args__, (int,))
self.assertEqual(a.__parameters__, ())
def test_parameters(self):
from typing import List, Dict, Callable
D0 = dict[str, int]
self.assertEqual(D0.__args__, (str, int))
self.assertEqual(D0.__parameters__, ())
D1a = dict[str, V]
self.assertEqual(D1a.__args__, (str, V))
self.assertEqual(D1a.__parameters__, (V,))
D1b = dict[K, int]
self.assertEqual(D1b.__args__, (K, int))
self.assertEqual(D1b.__parameters__, (K,))
D2a = dict[K, V]
self.assertEqual(D2a.__args__, (K, V))
self.assertEqual(D2a.__parameters__, (K, V))
D2b = dict[T, T]
self.assertEqual(D2b.__args__, (T, T))
self.assertEqual(D2b.__parameters__, (T,))
L0 = list[str]
self.assertEqual(L0.__args__, (str,))
self.assertEqual(L0.__parameters__, ())
L1 = list[T]
self.assertEqual(L1.__args__, (T,))
self.assertEqual(L1.__parameters__, (T,))
L2 = list[list[T]]
self.assertEqual(L2.__args__, (list[T],))
self.assertEqual(L2.__parameters__, (T,))
L3 = list[List[T]]
self.assertEqual(L3.__args__, (List[T],))
self.assertEqual(L3.__parameters__, (T,))
L4a = list[Dict[K, V]]
self.assertEqual(L4a.__args__, (Dict[K, V],))
self.assertEqual(L4a.__parameters__, (K, V))
L4b = list[Dict[T, int]]
self.assertEqual(L4b.__args__, (Dict[T, int],))
self.assertEqual(L4b.__parameters__, (T,))
L5 = list[Callable[[K, V], K]]
self.assertEqual(L5.__args__, (Callable[[K, V], K],))
self.assertEqual(L5.__parameters__, (K, V))
def test_parameter_chaining(self):
from typing import List, Dict, Union, Callable
self.assertEqual(list[T][int], list[int])
self.assertEqual(dict[str, T][int], dict[str, int])
self.assertEqual(dict[T, int][str], dict[str, int])
self.assertEqual(dict[K, V][str, int], dict[str, int])
self.assertEqual(dict[T, T][int], dict[int, int])
self.assertEqual(list[list[T]][int], list[list[int]])
self.assertEqual(list[dict[T, int]][str], list[dict[str, int]])
self.assertEqual(list[dict[str, T]][int], list[dict[str, int]])
self.assertEqual(list[dict[K, V]][str, int], list[dict[str, int]])
self.assertEqual(dict[T, list[int]][str], dict[str, list[int]])
self.assertEqual(list[List[T]][int], list[List[int]])
self.assertEqual(list[Dict[K, V]][str, int], list[Dict[str, int]])
self.assertEqual(list[Union[K, V]][str, int], list[Union[str, int]])
self.assertEqual(list[Callable[[K, V], K]][str, int],
list[Callable[[str, int], str]])
self.assertEqual(dict[T, List[int]][str], dict[str, List[int]])
with self.assertRaises(TypeError):
list[int][int]
dict[T, int][str, int]
dict[str, T][str, int]
dict[T, T][str, int]
def test_equality(self):
self.assertEqual(list[int], list[int])
self.assertEqual(dict[str, int], dict[str, int])
self.assertNotEqual(dict[str, int], dict[str, str])
self.assertNotEqual(list, list[int])
self.assertNotEqual(list[int], list)
def test_isinstance(self):
self.assertTrue(isinstance([], list))
with self.assertRaises(TypeError):
isinstance([], list[str])
def test_issubclass(self):
class L(list): ...
self.assertTrue(issubclass(L, list))
with self.assertRaises(TypeError):
issubclass(L, list[str])
def test_type_generic(self):
t = type[int]
Test = t('Test', (), {})
self.assertTrue(isinstance(Test, type))
test = Test()
self.assertEqual(t(test), Test)
self.assertEqual(t(0), int)
def test_type_subclass_generic(self):
class MyType(type):
pass
with self.assertRaises(TypeError):
MyType[int]
def test_pickle(self):
alias = GenericAlias(list, T)
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(alias, proto)
loaded = pickle.loads(s)
self.assertEqual(loaded.__origin__, alias.__origin__)
self.assertEqual(loaded.__args__, alias.__args__)
self.assertEqual(loaded.__parameters__, alias.__parameters__)
def test_copy(self):
class X(list):
def __copy__(self):
return self
def __deepcopy__(self, memo):
return self
for origin in list, deque, X:
alias = GenericAlias(origin, T)
copied = copy.copy(alias)
self.assertEqual(copied.__origin__, alias.__origin__)
self.assertEqual(copied.__args__, alias.__args__)
self.assertEqual(copied.__parameters__, alias.__parameters__)
copied = copy.deepcopy(alias)
self.assertEqual(copied.__origin__, alias.__origin__)
self.assertEqual(copied.__args__, alias.__args__)
self.assertEqual(copied.__parameters__, alias.__parameters__)
def test_union(self):
a = typing.Union[list[int], list[str]]
self.assertEqual(a.__args__, (list[int], list[str]))
self.assertEqual(a.__parameters__, ())
def test_union_generic(self):
a = typing.Union[list[T], tuple[T, ...]]
self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
self.assertEqual(a.__parameters__, (T,))
def test_dir(self):
dir_of_gen_alias = set(dir(list[int]))
self.assertTrue(dir_of_gen_alias.issuperset(dir(list)))
for generic_alias_property in ("__origin__", "__args__", "__parameters__"):
self.assertIn(generic_alias_property, dir_of_gen_alias)
def test_weakref(self):
for t in self.generic_types:
if t is None:
continue
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertEqual(ref(alias)(), alias)
def test_no_kwargs(self):
# bpo-42576
with self.assertRaises(TypeError):
GenericAlias(bad=float)
def test_subclassing_types_genericalias(self):
class SubClass(GenericAlias): ...
alias = SubClass(list, int)
class Bad(GenericAlias):
def __new__(cls, *args, **kwargs):
super().__new__(cls, *args, **kwargs)
self.assertEqual(alias, list[int])
with self.assertRaises(TypeError):
Bad(list, int, bad=int)
if __name__ == "__main__":
unittest.main()
"""Tests for C-implemented GenericAlias."""
import unittest
import pickle
import copy
from collections import (
defaultdict, deque, OrderedDict, Counter, UserDict, UserList
)
from collections.abc import *
from concurrent.futures import Future
from concurrent.futures.thread import _WorkItem
from contextlib import AbstractContextManager, AbstractAsyncContextManager
from contextvars import ContextVar, Token
from dataclasses import Field
from functools import partial, partialmethod, cached_property
from mailbox import Mailbox, _PartialFile
try:
import ctypes
except ImportError:
ctypes = None
from difflib import SequenceMatcher
from filecmp import dircmp
from fileinput import FileInput
from itertools import chain
from http.cookies import Morsel
from multiprocessing.managers import ValueProxy
from multiprocessing.pool import ApplyResult
try:
from multiprocessing.shared_memory import ShareableList
except ImportError:
# multiprocessing.shared_memory is not available on e.g. Android
ShareableList = None
from multiprocessing.queues import SimpleQueue as MPSimpleQueue
from os import DirEntry
from re import Pattern, Match
from types import GenericAlias, MappingProxyType, AsyncGeneratorType
from tempfile import TemporaryDirectory, SpooledTemporaryFile
from urllib.parse import SplitResult, ParseResult
from unittest.case import _AssertRaisesContext
from queue import Queue, SimpleQueue
from weakref import WeakSet, ReferenceType, ref
import typing
from typing import TypeVar
T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')
class BaseTest(unittest.TestCase):
"""Test basics."""
generic_types = [type, tuple, list, dict, set, frozenset, enumerate,
defaultdict, deque,
SequenceMatcher,
dircmp,
FileInput,
OrderedDict, Counter, UserDict, UserList,
Pattern, Match,
partial, partialmethod, cached_property,
AbstractContextManager, AbstractAsyncContextManager,
Awaitable, Coroutine,
AsyncIterable, AsyncIterator,
AsyncGenerator, Generator,
Iterable, Iterator,
Reversible,
Container, Collection,
Mailbox, _PartialFile,
ContextVar, Token,
Field,
Set, MutableSet,
Mapping, MutableMapping, MappingView,
KeysView, ItemsView, ValuesView,
Sequence, MutableSequence,
MappingProxyType, AsyncGeneratorType,
DirEntry,
chain,
TemporaryDirectory, SpooledTemporaryFile,
Queue, SimpleQueue,
_AssertRaisesContext,
SplitResult, ParseResult,
ValueProxy, ApplyResult,
WeakSet, ReferenceType, ref,
ShareableList, MPSimpleQueue,
Future, _WorkItem,
Morsel]
if ctypes is not None:
generic_types.extend((ctypes.Array, ctypes.LibraryLoader))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_subscriptable(self):
for t in self.generic_types:
if t is None:
continue
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertIs(alias.__origin__, t)
self.assertEqual(alias.__args__, (int,))
self.assertEqual(alias.__parameters__, ())
def test_unsubscriptable(self):
for t in int, str, float, Sized, Hashable:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
with self.assertRaises(TypeError):
t[int]
def test_instantiate(self):
for t in tuple, list, dict, set, frozenset, defaultdict, deque:
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertEqual(alias(), t())
if t is dict:
self.assertEqual(alias(iter([('a', 1), ('b', 2)])), dict(a=1, b=2))
self.assertEqual(alias(a=1, b=2), dict(a=1, b=2))
elif t is defaultdict:
def default():
return 'value'
a = alias(default)
d = defaultdict(default)
self.assertEqual(a['test'], d['test'])
else:
self.assertEqual(alias(iter((1, 2, 3))), t((1, 2, 3)))
def test_unbound_methods(self):
t = list[int]
a = t()
t.append(a, 'foo')
self.assertEqual(a, ['foo'])
x = t.__getitem__(a, 0)
self.assertEqual(x, 'foo')
self.assertEqual(t.__len__(a), 1)
def test_subclassing(self):
class C(list[int]):
pass
self.assertEqual(C.__bases__, (list,))
self.assertEqual(C.__class__, type)
def test_class_methods(self):
t = dict[int, None]
self.assertEqual(dict.fromkeys(range(2)), {0: None, 1: None}) # This works
self.assertEqual(t.fromkeys(range(2)), {0: None, 1: None}) # Should be equivalent
def test_no_chaining(self):
t = list[int]
with self.assertRaises(TypeError):
t[int]
def test_generic_subclass(self):
class MyList(list):
pass
t = MyList[int]
self.assertIs(t.__origin__, MyList)
self.assertEqual(t.__args__, (int,))
self.assertEqual(t.__parameters__, ())
def test_repr(self):
class MyList(list):
pass
self.assertEqual(repr(list[str]), 'list[str]')
self.assertEqual(repr(list[()]), 'list[()]')
self.assertEqual(repr(tuple[int, ...]), 'tuple[int, ...]')
self.assertTrue(repr(MyList[int]).endswith('.BaseTest.test_repr.<locals>.MyList[int]'))
self.assertEqual(repr(list[str]()), '[]') # instances should keep their normal repr
def test_exposed_type(self):
import types
a = types.GenericAlias(list, int)
self.assertEqual(str(a), 'list[int]')
self.assertIs(a.__origin__, list)
self.assertEqual(a.__args__, (int,))
self.assertEqual(a.__parameters__, ())
def test_parameters(self):
from typing import List, Dict, Callable
D0 = dict[str, int]
self.assertEqual(D0.__args__, (str, int))
self.assertEqual(D0.__parameters__, ())
D1a = dict[str, V]
self.assertEqual(D1a.__args__, (str, V))
self.assertEqual(D1a.__parameters__, (V,))
D1b = dict[K, int]
self.assertEqual(D1b.__args__, (K, int))
self.assertEqual(D1b.__parameters__, (K,))
D2a = dict[K, V]
self.assertEqual(D2a.__args__, (K, V))
self.assertEqual(D2a.__parameters__, (K, V))
D2b = dict[T, T]
self.assertEqual(D2b.__args__, (T, T))
self.assertEqual(D2b.__parameters__, (T,))
L0 = list[str]
self.assertEqual(L0.__args__, (str,))
self.assertEqual(L0.__parameters__, ())
L1 = list[T]
self.assertEqual(L1.__args__, (T,))
self.assertEqual(L1.__parameters__, (T,))
L2 = list[list[T]]
self.assertEqual(L2.__args__, (list[T],))
self.assertEqual(L2.__parameters__, (T,))
L3 = list[List[T]]
self.assertEqual(L3.__args__, (List[T],))
self.assertEqual(L3.__parameters__, (T,))
L4a = list[Dict[K, V]]
self.assertEqual(L4a.__args__, (Dict[K, V],))
self.assertEqual(L4a.__parameters__, (K, V))
L4b = list[Dict[T, int]]
self.assertEqual(L4b.__args__, (Dict[T, int],))
self.assertEqual(L4b.__parameters__, (T,))
L5 = list[Callable[[K, V], K]]
self.assertEqual(L5.__args__, (Callable[[K, V], K],))
self.assertEqual(L5.__parameters__, (K, V))
def test_parameter_chaining(self):
from typing import List, Dict, Union, Callable
self.assertEqual(list[T][int], list[int])
self.assertEqual(dict[str, T][int], dict[str, int])
self.assertEqual(dict[T, int][str], dict[str, int])
self.assertEqual(dict[K, V][str, int], dict[str, int])
self.assertEqual(dict[T, T][int], dict[int, int])
self.assertEqual(list[list[T]][int], list[list[int]])
self.assertEqual(list[dict[T, int]][str], list[dict[str, int]])
self.assertEqual(list[dict[str, T]][int], list[dict[str, int]])
self.assertEqual(list[dict[K, V]][str, int], list[dict[str, int]])
self.assertEqual(dict[T, list[int]][str], dict[str, list[int]])
self.assertEqual(list[List[T]][int], list[List[int]])
self.assertEqual(list[Dict[K, V]][str, int], list[Dict[str, int]])
self.assertEqual(list[Union[K, V]][str, int], list[Union[str, int]])
self.assertEqual(list[Callable[[K, V], K]][str, int],
list[Callable[[str, int], str]])
self.assertEqual(dict[T, List[int]][str], dict[str, List[int]])
with self.assertRaises(TypeError):
list[int][int]
dict[T, int][str, int]
dict[str, T][str, int]
dict[T, T][str, int]
def test_equality(self):
self.assertEqual(list[int], list[int])
self.assertEqual(dict[str, int], dict[str, int])
self.assertNotEqual(dict[str, int], dict[str, str])
self.assertNotEqual(list, list[int])
self.assertNotEqual(list[int], list)
def test_isinstance(self):
self.assertTrue(isinstance([], list))
with self.assertRaises(TypeError):
isinstance([], list[str])
def test_issubclass(self):
class L(list): ...
self.assertTrue(issubclass(L, list))
with self.assertRaises(TypeError):
issubclass(L, list[str])
def test_type_generic(self):
t = type[int]
Test = t('Test', (), {})
self.assertTrue(isinstance(Test, type))
test = Test()
self.assertEqual(t(test), Test)
self.assertEqual(t(0), int)
def test_type_subclass_generic(self):
class MyType(type):
pass
with self.assertRaises(TypeError):
MyType[int]
def test_pickle(self):
alias = GenericAlias(list, T)
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(alias, proto)
loaded = pickle.loads(s)
self.assertEqual(loaded.__origin__, alias.__origin__)
self.assertEqual(loaded.__args__, alias.__args__)
self.assertEqual(loaded.__parameters__, alias.__parameters__)
def test_copy(self):
class X(list):
def __copy__(self):
return self
def __deepcopy__(self, memo):
return self
for origin in list, deque, X:
alias = GenericAlias(origin, T)
copied = copy.copy(alias)
self.assertEqual(copied.__origin__, alias.__origin__)
self.assertEqual(copied.__args__, alias.__args__)
self.assertEqual(copied.__parameters__, alias.__parameters__)
copied = copy.deepcopy(alias)
self.assertEqual(copied.__origin__, alias.__origin__)
self.assertEqual(copied.__args__, alias.__args__)
self.assertEqual(copied.__parameters__, alias.__parameters__)
def test_union(self):
a = typing.Union[list[int], list[str]]
self.assertEqual(a.__args__, (list[int], list[str]))
self.assertEqual(a.__parameters__, ())
def test_union_generic(self):
a = typing.Union[list[T], tuple[T, ...]]
self.assertEqual(a.__args__, (list[T], tuple[T, ...]))
self.assertEqual(a.__parameters__, (T,))
def test_dir(self):
dir_of_gen_alias = set(dir(list[int]))
self.assertTrue(dir_of_gen_alias.issuperset(dir(list)))
for generic_alias_property in ("__origin__", "__args__", "__parameters__"):
self.assertIn(generic_alias_property, dir_of_gen_alias)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_weakref(self):
for t in self.generic_types:
if t is None:
continue
tname = t.__name__
with self.subTest(f"Testing {tname}"):
alias = t[int]
self.assertEqual(ref(alias)(), alias)
def test_no_kwargs(self):
# bpo-42576
with self.assertRaises(TypeError):
GenericAlias(bad=float)
def test_subclassing_types_genericalias(self):
class SubClass(GenericAlias): ...
alias = SubClass(list, int)
class Bad(GenericAlias):
def __new__(cls, *args, **kwargs):
super().__new__(cls, *args, **kwargs)
self.assertEqual(alias, list[int])
with self.assertRaises(TypeError):
Bad(list, int, bad=int)
if __name__ == "__main__":
unittest.main()

67
Lib/test/test_glob.py vendored
View File

@@ -9,6 +9,7 @@ from test.support.os_helper import (TESTFN, skip_unless_symlink,
class GlobTests(unittest.TestCase):
dir_fd = None
def norm(self, *parts):
return os.path.normpath(os.path.join(self.tempdir, *parts))
@@ -38,8 +39,14 @@ class GlobTests(unittest.TestCase):
os.symlink(self.norm('broken'), self.norm('sym1'))
os.symlink('broken', self.norm('sym2'))
os.symlink(os.path.join('a', 'bcd'), self.norm('sym3'))
if {os.open, os.stat} <= os.supports_dir_fd and os.scandir in os.supports_fd:
self.dir_fd = os.open(self.tempdir, os.O_RDONLY | os.O_DIRECTORY)
else:
self.dir_fd = None
def tearDown(self):
if self.dir_fd is not None:
os.close(self.dir_fd)
shutil.rmtree(self.tempdir)
def glob(self, *parts, **kwargs):
@@ -53,6 +60,41 @@ class GlobTests(unittest.TestCase):
bres = [os.fsencode(x) for x in res]
self.assertCountEqual(glob.glob(os.fsencode(p), **kwargs), bres)
self.assertCountEqual(glob.iglob(os.fsencode(p), **kwargs), bres)
with change_cwd(self.tempdir):
res2 = glob.glob(pattern, **kwargs)
for x in res2:
self.assertFalse(os.path.isabs(x), x)
if pattern == '**' or pattern == '**' + os.sep:
expected = res[1:]
else:
expected = res
self.assertCountEqual([os.path.join(self.tempdir, x) for x in res2],
expected)
self.assertCountEqual(glob.iglob(pattern, **kwargs), res2)
bpattern = os.fsencode(pattern)
bres2 = [os.fsencode(x) for x in res2]
self.assertCountEqual(glob.glob(bpattern, **kwargs), bres2)
self.assertCountEqual(glob.iglob(bpattern, **kwargs), bres2)
self.assertCountEqual(glob.glob(pattern, root_dir=self.tempdir, **kwargs), res2)
self.assertCountEqual(glob.iglob(pattern, root_dir=self.tempdir, **kwargs), res2)
btempdir = os.fsencode(self.tempdir)
self.assertCountEqual(
glob.glob(bpattern, root_dir=btempdir, **kwargs), bres2)
self.assertCountEqual(
glob.iglob(bpattern, root_dir=btempdir, **kwargs), bres2)
if self.dir_fd is not None:
self.assertCountEqual(
glob.glob(pattern, dir_fd=self.dir_fd, **kwargs), res2)
self.assertCountEqual(
glob.iglob(pattern, dir_fd=self.dir_fd, **kwargs), res2)
self.assertCountEqual(
glob.glob(bpattern, dir_fd=self.dir_fd, **kwargs), bres2)
self.assertCountEqual(
glob.iglob(bpattern, dir_fd=self.dir_fd, **kwargs), bres2)
return res
def assertSequencesEqual_noorder(self, l1, l2):
@@ -78,6 +120,14 @@ class GlobTests(unittest.TestCase):
res = glob.glob(os.path.join(os.fsencode(os.curdir), b'*'))
self.assertEqual({type(r) for r in res}, {bytes})
def test_glob_empty_pattern(self):
self.assertEqual(glob.glob(''), [])
self.assertEqual(glob.glob(b''), [])
self.assertEqual(glob.glob('', root_dir=self.tempdir), [])
self.assertEqual(glob.glob(b'', root_dir=os.fsencode(self.tempdir)), [])
self.assertEqual(glob.glob('', dir_fd=self.dir_fd), [])
self.assertEqual(glob.glob(b'', dir_fd=self.dir_fd), [])
def test_glob_one_directory(self):
eq = self.assertSequencesEqual_noorder
eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa']))
@@ -264,6 +314,23 @@ class GlobTests(unittest.TestCase):
expect += [join('sym3', 'EF')]
eq(glob.glob(join('**', 'EF'), recursive=True), expect)
def test_glob_many_open_files(self):
depth = 30
base = os.path.join(self.tempdir, 'deep')
p = os.path.join(base, *(['d']*depth))
os.makedirs(p)
pattern = os.path.join(base, *(['*']*depth))
iters = [glob.iglob(pattern, recursive=True) for j in range(100)]
for it in iters:
self.assertEqual(next(it), p)
pattern = os.path.join(base, '**', 'd')
iters = [glob.iglob(pattern, recursive=True) for j in range(100)]
p = base
for i in range(depth):
p = os.path.join(p, 'd')
for it in iters:
self.assertEqual(next(it), p)
@skip_unless_symlink
class SymlinkLoopGlobTests(unittest.TestCase):

View File

@@ -1,6 +1,6 @@
"""Verify that warnings are issued for global statements following use."""
from test.support import run_unittest, check_syntax_error
from test.support import check_syntax_error
from test.support.warnings_helper import check_warnings
import unittest
import warnings
@@ -53,10 +53,12 @@ x = 2
compile(prog_text_4, "<test string>", "exec")
def test_main():
with warnings.catch_warnings():
warnings.filterwarnings("error", module="<test string>")
run_unittest(GlobalTests)
def setUpModule():
cm = warnings.catch_warnings()
cm.__enter__()
unittest.addModuleCleanup(cm.__exit__, None, None, None)
warnings.filterwarnings("error", module="<test string>")
if __name__ == "__main__":
test_main()
unittest.main()

358
Lib/test/test_hash.py vendored Normal file
View File

@@ -0,0 +1,358 @@
# test the invariant that
# iff a==b then hash(a)==hash(b)
#
# Also test that hash implementations are inherited as expected
import datetime
import os
import sys
import unittest
from test.support.script_helper import assert_python_ok
from collections.abc import Hashable
IS_64BIT = sys.maxsize > 2**32
def lcg(x, length=16):
"""Linear congruential generator"""
if x == 0:
return bytes(length)
out = bytearray(length)
for i in range(length):
x = (214013 * x + 2531011) & 0x7fffffff
out[i] = (x >> 16) & 0xff
return bytes(out)
def pysiphash(uint64):
"""Convert SipHash24 output to Py_hash_t
"""
assert 0 <= uint64 < (1 << 64)
# simple unsigned to signed int64
if uint64 > (1 << 63) - 1:
int64 = uint64 - (1 << 64)
else:
int64 = uint64
# mangle uint64 to uint32
uint32 = (uint64 ^ uint64 >> 32) & 0xffffffff
# simple unsigned to signed int32
if uint32 > (1 << 31) - 1:
int32 = uint32 - (1 << 32)
else:
int32 = uint32
return int32, int64
def skip_unless_internalhash(test):
"""Skip decorator for tests that depend on SipHash24 or FNV"""
ok = sys.hash_info.algorithm in {"fnv", "siphash24"}
msg = "Requires SipHash24 or FNV"
return test if ok else unittest.skip(msg)(test)
class HashEqualityTestCase(unittest.TestCase):
def same_hash(self, *objlist):
# Hash each object given and fail if
# the hash values are not all the same.
hashed = list(map(hash, objlist))
for h in hashed[1:]:
if h != hashed[0]:
self.fail("hashed values differ: %r" % (objlist,))
def test_numeric_literals(self):
self.same_hash(1, 1, 1.0, 1.0+0.0j)
self.same_hash(0, 0.0, 0.0+0.0j)
self.same_hash(-1, -1.0, -1.0+0.0j)
self.same_hash(-2, -2.0, -2.0+0.0j)
def test_coerced_integers(self):
self.same_hash(int(1), int(1), float(1), complex(1),
int('1'), float('1.0'))
self.same_hash(int(-2**31), float(-2**31))
self.same_hash(int(1-2**31), float(1-2**31))
self.same_hash(int(2**31-1), float(2**31-1))
# for 64-bit platforms
self.same_hash(int(2**31), float(2**31))
self.same_hash(int(-2**63), float(-2**63))
self.same_hash(int(2**63), float(2**63))
def test_coerced_floats(self):
self.same_hash(int(1.23e300), float(1.23e300))
self.same_hash(float(0.5), complex(0.5, 0.0))
def test_unaligned_buffers(self):
# The hash function for bytes-like objects shouldn't have
# alignment-dependent results (example in issue #16427).
b = b"123456789abcdefghijklmnopqrstuvwxyz" * 128
for i in range(16):
for j in range(16):
aligned = b[i:128+j]
unaligned = memoryview(b)[i:128+j]
self.assertEqual(hash(aligned), hash(unaligned))
_default_hash = object.__hash__
class DefaultHash(object): pass
_FIXED_HASH_VALUE = 42
class FixedHash(object):
def __hash__(self):
return _FIXED_HASH_VALUE
class OnlyEquality(object):
def __eq__(self, other):
return self is other
class OnlyInequality(object):
def __ne__(self, other):
return self is not other
class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
class NoHash(object):
__hash__ = None
class HashInheritanceTestCase(unittest.TestCase):
default_expected = [object(),
DefaultHash(),
OnlyInequality(),
]
fixed_expected = [FixedHash(),
InheritedHashWithEquality(),
InheritedHashWithInequality(),
]
error_expected = [NoHash(),
OnlyEquality(),
]
def test_default_hash(self):
for obj in self.default_expected:
self.assertEqual(hash(obj), _default_hash(obj))
def test_fixed_hash(self):
for obj in self.fixed_expected:
self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_error_hash(self):
for obj in self.error_expected:
self.assertRaises(TypeError, hash, obj)
def test_hashable(self):
objects = (self.default_expected +
self.fixed_expected)
for obj in objects:
self.assertIsInstance(obj, Hashable)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_not_hashable(self):
for obj in self.error_expected:
self.assertNotIsInstance(obj, Hashable)
# Issue #4701: Check that some builtin types are correctly hashable
class DefaultIterSeq(object):
seq = range(10)
def __len__(self):
return len(self.seq)
def __getitem__(self, index):
return self.seq[index]
class HashBuiltinsTestCase(unittest.TestCase):
hashes_to_check = [enumerate(range(10)),
iter(DefaultIterSeq()),
iter(lambda: 0, 0),
]
def test_hashes(self):
_default_hash = object.__hash__
for obj in self.hashes_to_check:
self.assertEqual(hash(obj), _default_hash(obj))
class HashRandomizationTests:
# Each subclass should define a field "repr_", containing the repr() of
# an object to be tested
def get_hash_command(self, repr_):
return 'print(hash(eval(%a)))' % repr_
def get_hash(self, repr_, seed=None):
env = os.environ.copy()
env['__cleanenv'] = True # signal to assert_python not to do a copy
# of os.environ on its own
if seed is not None:
env['PYTHONHASHSEED'] = str(seed)
else:
env.pop('PYTHONHASHSEED', None)
out = assert_python_ok(
'-c', self.get_hash_command(repr_),
**env)
stdout = out[1].strip()
return int(stdout)
def test_randomized_hash(self):
# two runs should return different hashes
run1 = self.get_hash(self.repr_, seed='random')
run2 = self.get_hash(self.repr_, seed='random')
self.assertNotEqual(run1, run2)
class StringlikeHashRandomizationTests(HashRandomizationTests):
repr_ = None
repr_long = None
# 32bit little, 64bit little, 32bit big, 64bit big
known_hashes = {
'djba33x': [ # only used for small strings
# seed 0, 'abc'
[193485960, 193485960, 193485960, 193485960],
# seed 42, 'abc'
[-678966196, 573763426263223372, -820489388, -4282905804826039665],
],
'siphash24': [
# NOTE: PyUCS2 layout depends on endianness
# seed 0, 'abc'
[1198583518, 4596069200710135518, 1198583518, 4596069200710135518],
# seed 42, 'abc'
[273876886, -4501618152524544106, 273876886, -4501618152524544106],
# seed 42, 'abcdefghijk'
[-1745215313, 4436719588892876975, -1745215313, 4436719588892876975],
# seed 0, 'äú∑ℇ'
[493570806, 5749986484189612790, -1006381564, -5915111450199468540],
# seed 42, 'äú∑ℇ'
[-1677110816, -2947981342227738144, -1860207793, -4296699217652516017],
],
'fnv': [
# seed 0, 'abc'
[-1600925533, 1453079729188098211, -1600925533,
1453079729188098211],
# seed 42, 'abc'
[-206076799, -4410911502303878509, -1024014457,
-3570150969479994130],
# seed 42, 'abcdefghijk'
[811136751, -5046230049376118746, -77208053 ,
-4779029615281019666],
# seed 0, 'äú∑ℇ'
[44402817, 8998297579845987431, -1956240331,
-782697888614047887],
# seed 42, 'äú∑ℇ'
[-283066365, -4576729883824601543, -271871407,
-3927695501187247084],
]
}
def get_expected_hash(self, position, length):
if length < sys.hash_info.cutoff:
algorithm = "djba33x"
else:
algorithm = sys.hash_info.algorithm
if sys.byteorder == 'little':
platform = 1 if IS_64BIT else 0
else:
assert(sys.byteorder == 'big')
platform = 3 if IS_64BIT else 2
return self.known_hashes[algorithm][position][platform]
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_null_hash(self):
# PYTHONHASHSEED=0 disables the randomized hash
known_hash_of_obj = self.get_expected_hash(0, 3)
# Randomization is enabled by default:
self.assertNotEqual(self.get_hash(self.repr_), known_hash_of_obj)
# It can also be disabled by setting the seed to 0:
self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@skip_unless_internalhash
def test_fixed_hash(self):
# test a fixed seed for the randomized hash
# Note that all types share the same values:
h = self.get_expected_hash(1, 3)
self.assertEqual(self.get_hash(self.repr_, seed=42), h)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@skip_unless_internalhash
def test_long_fixed_hash(self):
if self.repr_long is None:
return
h = self.get_expected_hash(2, 11)
self.assertEqual(self.get_hash(self.repr_long, seed=42), h)
class StrHashRandomizationTests(StringlikeHashRandomizationTests,
unittest.TestCase):
repr_ = repr('abc')
repr_long = repr('abcdefghijk')
repr_ucs2 = repr('äú∑ℇ')
@skip_unless_internalhash
def test_empty_string(self):
self.assertEqual(hash(""), 0)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@skip_unless_internalhash
def test_ucs2_string(self):
h = self.get_expected_hash(3, 6)
self.assertEqual(self.get_hash(self.repr_ucs2, seed=0), h)
h = self.get_expected_hash(4, 6)
self.assertEqual(self.get_hash(self.repr_ucs2, seed=42), h)
class BytesHashRandomizationTests(StringlikeHashRandomizationTests,
unittest.TestCase):
repr_ = repr(b'abc')
repr_long = repr(b'abcdefghijk')
@skip_unless_internalhash
def test_empty_string(self):
self.assertEqual(hash(b""), 0)
class MemoryviewHashRandomizationTests(StringlikeHashRandomizationTests,
unittest.TestCase):
repr_ = "memoryview(b'abc')"
repr_long = "memoryview(b'abcdefghijk')"
@skip_unless_internalhash
def test_empty_string(self):
self.assertEqual(hash(memoryview(b"")), 0)
class DatetimeTests(HashRandomizationTests):
def get_hash_command(self, repr_):
return 'import datetime; print(hash(%s))' % repr_
class DatetimeDateTests(DatetimeTests, unittest.TestCase):
repr_ = repr(datetime.date(1066, 10, 14))
class DatetimeDatetimeTests(DatetimeTests, unittest.TestCase):
repr_ = repr(datetime.datetime(1, 2, 3, 4, 5, 6, 7))
class DatetimeTimeTests(DatetimeTests, unittest.TestCase):
repr_ = repr(datetime.time(0))
class HashDistributionTestCase(unittest.TestCase):
def test_hash_distribution(self):
# check for hash collision
base = "abcdefghabcdefg"
for i in range(1, len(base)):
prefix = base[:i]
with self.subTest(prefix=prefix):
s15 = set()
s255 = set()
for c in range(256):
h = hash(prefix + chr(c))
s15.add(h & 0xf)
s255.add(h & 0xff)
# SipHash24 distribution depends on key, usually > 60%
self.assertGreater(len(s15), 8, prefix)
self.assertGreater(len(s255), 128, prefix)
if __name__ == "__main__":
unittest.main()

View File

@@ -21,6 +21,7 @@ from test import support
from test.support import _4G, bigmemtest
from test.support.import_helper import import_fresh_module
from test.support import threading_helper
from test.support import warnings_helper
from http.client import HTTPException
# Were we compiled --with-pydebug or with #define Py_DEBUG?
@@ -47,12 +48,15 @@ else:
builtin_hashlib = None
try:
from _hashlib import HASH, HASHXOF, openssl_md_meth_names
from _hashlib import HASH, HASHXOF, openssl_md_meth_names, get_fips_mode
except ImportError:
HASH = None
HASHXOF = None
openssl_md_meth_names = frozenset()
def get_fips_mode():
return 0
try:
import _blake2
except ImportError:
@@ -60,12 +64,9 @@ except ImportError:
requires_blake2 = unittest.skipUnless(_blake2, 'requires _blake2')
try:
import _sha3
except ImportError:
_sha3 = None
requires_sha3 = unittest.skipUnless(_sha3, 'requires _sha3')
# bpo-46913: Don't test the _sha3 extension on a Python UBSAN build
SKIP_SHA3 = support.check_sanitizer(ub=True)
requires_sha3 = unittest.skipUnless(not SKIP_SHA3, 'requires _sha3')
def hexstr(s):
@@ -79,11 +80,10 @@ def hexstr(s):
URL = "http://www.pythontest.net/hashlib/{}.txt"
def read_vectors(hash_name):
url = URL.format(hash_name)
try:
testdata = support.open_urlresource(url)
testdata = support.open_urlresource(url, encoding="utf-8")
except (OSError, HTTPException):
raise unittest.SkipTest("Could not retrieve {}".format(url))
with testdata:
@@ -97,13 +97,13 @@ def read_vectors(hash_name):
class HashLibTestCase(unittest.TestCase):
supported_hash_names = ('md5', 'MD5', 'sha1', 'SHA1',
'sha224', 'SHA224', 'sha256', 'SHA256',
'sha384', 'SHA384', 'sha512', 'SHA512',
'blake2b', 'blake2s',
'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
# TODO: RUSTPYTHON
# 'shake_128', 'shake_256'
supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1',
'sha224', 'SHA224', 'sha256', 'SHA256',
'sha384', 'SHA384', 'sha512', 'SHA512',
'blake2b', 'blake2s',
'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512',
# TODO: RUSTPYTHON
# 'shake_128', 'shake_256'
)
shakes = {'shake_128', 'shake_256'}
@@ -131,13 +131,14 @@ class HashLibTestCase(unittest.TestCase):
self.constructors_to_test = {}
for algorithm in algorithms:
if SKIP_SHA3 and algorithm.startswith('sha3_'):
continue
self.constructors_to_test[algorithm] = set()
# For each algorithm, test the direct constructor and the use
# of hashlib.new given the algorithm name.
for algorithm, constructors in self.constructors_to_test.items():
constructors.add(getattr(hashlib, algorithm))
def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
if data is None:
return hashlib.new(_alg, **kwargs)
@@ -184,14 +185,15 @@ class HashLibTestCase(unittest.TestCase):
add_builtin_constructor('blake2s')
add_builtin_constructor('blake2b')
_sha3 = self._conditional_import_module('_sha3')
if _sha3:
add_builtin_constructor('sha3_224')
add_builtin_constructor('sha3_256')
add_builtin_constructor('sha3_384')
add_builtin_constructor('sha3_512')
add_builtin_constructor('shake_128')
add_builtin_constructor('shake_256')
if not SKIP_SHA3:
_sha3 = self._conditional_import_module('_sha3')
if _sha3:
add_builtin_constructor('sha3_224')
add_builtin_constructor('sha3_256')
add_builtin_constructor('sha3_384')
add_builtin_constructor('sha3_512')
add_builtin_constructor('shake_128')
add_builtin_constructor('shake_256')
super(HashLibTestCase, self).__init__(*args, **kwargs)
@@ -202,10 +204,7 @@ class HashLibTestCase(unittest.TestCase):
@property
def is_fips_mode(self):
if hasattr(self._hashlib, "get_fips_mode"):
return self._hashlib.get_fips_mode()
else:
return None
return get_fips_mode()
# TODO: RUSTPYTHON
@unittest.expectedFailure
@@ -222,14 +221,18 @@ class HashLibTestCase(unittest.TestCase):
@unittest.expectedFailure
def test_algorithms_guaranteed(self):
self.assertEqual(hashlib.algorithms_guaranteed,
set(_algo for _algo in self.supported_hash_names
if _algo.islower()))
set(_algo for _algo in self.supported_hash_names
if _algo.islower()))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_algorithms_available(self):
self.assertTrue(set(hashlib.algorithms_guaranteed).
issubset(hashlib.algorithms_available))
issubset(hashlib.algorithms_available))
# all available algorithms must be loadable, bpo-47101
self.assertNotIn("undefined", hashlib.algorithms_available)
for name in hashlib.algorithms_available:
digest = hashlib.new(name, usedforsecurity=False)
def test_usedforsecurity_true(self):
hashlib.new("sha256", usedforsecurity=True)
@@ -337,7 +340,7 @@ class HashLibTestCase(unittest.TestCase):
aas = b'a' * 128
bees = b'b' * 127
cees = b'c' * 126
dees = b'd' * 2048 # HASHLIB_GIL_MINSIZE
dees = b'd' * 2048 # HASHLIB_GIL_MINSIZE
for cons in self.hash_constructors:
m1 = cons(usedforsecurity=False)
@@ -375,11 +378,11 @@ class HashLibTestCase(unittest.TestCase):
m = hash_object_constructor(data, **kwargs)
computed = m.hexdigest() if not shake else m.hexdigest(length)
self.assertEqual(
computed, hexdigest,
"Hash algorithm %s constructed using %s returned hexdigest"
" %r for %d byte input data that should have hashed to %r."
% (name, hash_object_constructor,
computed, len(data), hexdigest))
computed, hexdigest,
"Hash algorithm %s constructed using %s returned hexdigest"
" %r for %d byte input data that should have hashed to %r."
% (name, hash_object_constructor,
computed, len(data), hexdigest))
computed = m.digest() if not shake else m.digest(length)
digest = bytes.fromhex(hexdigest)
self.assertEqual(computed, digest)
@@ -405,6 +408,8 @@ class HashLibTestCase(unittest.TestCase):
self.check_no_unicode('blake2b')
self.check_no_unicode('blake2s')
# TODO: RUSTPYTHON
@unittest.expectedFailure
@requires_sha3
def test_no_unicode_sha3(self):
self.check_no_unicode('sha3_224')
@@ -466,6 +471,8 @@ class HashLibTestCase(unittest.TestCase):
self.assertEqual(m._rate_bits, rate)
self.assertEqual(m._suffix, suffix)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@requires_sha3
def test_extra_sha3(self):
self.check_sha3('sha3_224', 448, 1152, b'\x06')
@@ -531,87 +538,91 @@ class HashLibTestCase(unittest.TestCase):
self.check('sha1', b"a" * 1000000,
"34aa973cd4c4daa4f61eeb2bdbad27316534016f")
# use the examples from Federal Information Processing Standards
# Publication 180-2, Secure Hash Standard, 2002 August 1
# http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
def test_case_sha224_0(self):
self.check('sha224', b"",
"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f")
"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f")
def test_case_sha224_1(self):
self.check('sha224', b"abc",
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7")
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7")
def test_case_sha224_2(self):
self.check('sha224',
b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525")
b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525")
def test_case_sha224_3(self):
self.check('sha224', b"a" * 1000000,
"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67")
"20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67")
def test_case_sha256_0(self):
self.check('sha256', b"",
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
def test_case_sha256_1(self):
self.check('sha256', b"abc",
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad")
def test_case_sha256_2(self):
self.check('sha256',
b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1")
b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1")
def test_case_sha256_3(self):
self.check('sha256', b"a" * 1000000,
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")
"cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0")
def test_case_sha384_0(self):
self.check('sha384', b"",
"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da" +
"274edebfe76f65fbd51ad2f14898b95b")
"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da"+
"274edebfe76f65fbd51ad2f14898b95b")
def test_case_sha384_1(self):
self.check('sha384', b"abc",
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" +
"8086072ba1e7cc2358baeca134c825a7")
"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"+
"8086072ba1e7cc2358baeca134c825a7")
def test_case_sha384_2(self):
self.check('sha384',
b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+
b"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" +
"fcc7c71a557e2db966c3e9fa91746039")
"09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"+
"fcc7c71a557e2db966c3e9fa91746039")
def test_case_sha384_3(self):
self.check('sha384', b"a" * 1000000,
"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b" +
"07b8b3dc38ecc4ebae97ddd87f3d8985")
"9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"+
"07b8b3dc38ecc4ebae97ddd87f3d8985")
def test_case_sha512_0(self):
self.check('sha512', b"",
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce" +
"47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"+
"47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
def test_case_sha512_1(self):
self.check('sha512', b"abc",
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" +
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")
"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"+
"2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f")
def test_case_sha512_2(self):
self.check('sha512',
b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" +
b"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+
b"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" +
"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909")
"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"+
"501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909")
def test_case_sha512_3(self):
self.check('sha512', b"a" * 1000000,
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" +
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")
"e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+
"de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b")
def check_blake2(self, constructor, salt_size, person_size, key_size,
digest_size, max_offset):
@@ -664,9 +675,9 @@ class HashLibTestCase(unittest.TestCase):
self.assertRaises(ValueError, constructor, inner_size=digest_size+1)
constructor(leaf_size=0)
constructor(leaf_size=(1 << 32)-1)
constructor(leaf_size=(1<<32)-1)
self.assertRaises(ValueError, constructor, leaf_size=-1)
self.assertRaises(OverflowError, constructor, leaf_size=1 << 32)
self.assertRaises(OverflowError, constructor, leaf_size=1<<32)
constructor(node_offset=0)
constructor(node_offset=max_offset)
@@ -694,7 +705,7 @@ class HashLibTestCase(unittest.TestCase):
def blake2_rfc7693(self, constructor, md_len, in_len):
def selftest_seq(length, seed):
mask = (1 << 32)-1
mask = (1<<32)-1
a = (0xDEAD4BAD * seed) & mask
b = 1
out = bytearray(length)
@@ -716,7 +727,7 @@ class HashLibTestCase(unittest.TestCase):
@requires_blake2
def test_blake2b(self):
self.check_blake2(hashlib.blake2b, 16, 16, 64, 64, (1 << 64)-1)
self.check_blake2(hashlib.blake2b, 16, 16, 64, 64, (1<<64)-1)
b2b_md_len = [20, 32, 48, 64]
b2b_in_len = [0, 3, 128, 129, 255, 1024]
self.assertEqual(
@@ -726,32 +737,32 @@ class HashLibTestCase(unittest.TestCase):
@requires_blake2
def test_case_blake2b_0(self):
self.check('blake2b', b"",
"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419" +
"d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce")
"786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419"+
"d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce")
@requires_blake2
def test_case_blake2b_1(self):
self.check('blake2b', b"abc",
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1" +
"7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923")
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1"+
"7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923")
@requires_blake2
def test_case_blake2b_all_parameters(self):
# This checks that all the parameters work in general, and also that
# parameter byte order doesn't get confused on big endian platforms.
self.check('blake2b', b"foo",
"920568b0c5873b2f0ab67bedb6cf1b2b",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)
"920568b0c5873b2f0ab67bedb6cf1b2b",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)
@requires_blake2
def test_blake2b_vectors(self):
@@ -761,7 +772,7 @@ class HashLibTestCase(unittest.TestCase):
@requires_blake2
def test_blake2s(self):
self.check_blake2(hashlib.blake2s, 8, 8, 32, 32, (1 << 48)-1)
self.check_blake2(hashlib.blake2s, 8, 8, 32, 32, (1<<48)-1)
b2s_md_len = [16, 20, 28, 32]
b2s_in_len = [0, 3, 64, 65, 255, 1024]
self.assertEqual(
@@ -771,30 +782,30 @@ class HashLibTestCase(unittest.TestCase):
@requires_blake2
def test_case_blake2s_0(self):
self.check('blake2s', b"",
"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9")
"69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9")
@requires_blake2
def test_case_blake2s_1(self):
self.check('blake2s', b"abc",
"508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982")
"508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982")
@requires_blake2
def test_case_blake2s_all_parameters(self):
# This checks that all the parameters work in general, and also that
# parameter byte order doesn't get confused on big endian platforms.
self.check('blake2s', b"foo",
"bf2a8f7fe3c555012a6f8046e646bc75",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)
"bf2a8f7fe3c555012a6f8046e646bc75",
digest_size=16,
key=b"bar",
salt=b"baz",
person=b"bing",
fanout=2,
depth=3,
leaf_size=4,
node_offset=5,
node_depth=6,
inner_size=7,
last_node=True)
@requires_blake2
def test_blake2s_vectors(self):
@@ -805,7 +816,7 @@ class HashLibTestCase(unittest.TestCase):
@requires_sha3
def test_case_sha3_224_0(self):
self.check('sha3_224', b"",
"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7")
"6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7")
@requires_sha3
def test_case_sha3_224_vector(self):
@@ -815,7 +826,7 @@ class HashLibTestCase(unittest.TestCase):
@requires_sha3
def test_case_sha3_256_0(self):
self.check('sha3_256', b"",
"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a")
"a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a")
@requires_sha3
def test_case_sha3_256_vector(self):
@@ -825,8 +836,8 @@ class HashLibTestCase(unittest.TestCase):
@requires_sha3
def test_case_sha3_384_0(self):
self.check('sha3_384', b"",
"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a" +
"c3713831264adb47fb6bd1e058d5f004")
"0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a"+
"c3713831264adb47fb6bd1e058d5f004")
@requires_sha3
def test_case_sha3_384_vector(self):
@@ -836,36 +847,38 @@ class HashLibTestCase(unittest.TestCase):
@requires_sha3
def test_case_sha3_512_0(self):
self.check('sha3_512', b"",
"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6" +
"15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26")
"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6"+
"15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26")
@requires_sha3
def test_case_sha3_512_vector(self):
for msg, md in read_vectors('sha3_512'):
self.check('sha3_512', msg, md)
@requires_sha3
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_case_shake_128_0(self):
self.check('shake_128', b"",
"7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26",
True)
"7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26",
True)
self.check('shake_128', b"", "7f9c", True)
@requires_sha3
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_case_shake128_vector(self):
for msg, md in read_vectors('shake_128'):
self.check('shake_128', msg, md, True)
@requires_sha3
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_case_shake_256_0(self):
self.check('shake_256', b"",
"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f",
True)
"46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762f",
True)
self.check('shake_256', b"", "46b9", True)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@requires_sha3
def test_case_shake256_vector(self):
for msg, md in read_vectors('shake_256'):
self.check('shake_256', msg, md, True)
@@ -940,17 +953,42 @@ class HashLibTestCase(unittest.TestCase):
if fips_mode is not None:
self.assertIsInstance(fips_mode, int)
@support.cpython_only
def test_disallow_instantiation(self):
for algorithm, constructors in self.constructors_to_test.items():
if algorithm.startswith(("sha3_", "shake", "blake")):
# _sha3 and _blake types can be instantiated
continue
# all other types have DISALLOW_INSTANTIATION
for constructor in constructors:
# In FIPS mode some algorithms are not available raising ValueError
try:
h = constructor()
except ValueError:
continue
with self.subTest(constructor=constructor):
support.check_disallow_instantiation(self, type(h))
@unittest.skipUnless(HASH is not None, 'need _hashlib')
def test_internal_types(self):
def test_hash_disallow_instantiation(self):
# internal types like _hashlib.HASH are not constructable
with self.assertRaisesRegex(
TypeError, "cannot create 'HASH' instance"
):
HASH()
with self.assertRaisesRegex(
TypeError, "cannot create 'HASHXOF' instance"
):
HASHXOF()
support.check_disallow_instantiation(self, HASH)
support.check_disallow_instantiation(self, HASHXOF)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_readonly_types(self):
for algorithm, constructors in self.constructors_to_test.items():
# all other types have DISALLOW_INSTANTIATION
for constructor in constructors:
# In FIPS mode some algorithms are not available raising ValueError
try:
hash_type = type(constructor())
except ValueError:
continue
with self.subTest(hash_type=hash_type):
with self.assertRaisesRegex(TypeError, "immutable type"):
hash_type.value = False
class KDFTests(unittest.TestCase):
@@ -967,13 +1005,10 @@ class KDFTests(unittest.TestCase):
]
scrypt_test_vectors = [
(b'', b'', 16, 1, 1, unhexlify(
'77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906')),
(b'password', b'NaCl', 1024, 8, 16, unhexlify(
'fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640')),
(b'pleaseletmein', b'SodiumChloride', 16384, 8, 1, unhexlify(
'7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887')),
]
(b'', b'', 16, 1, 1, unhexlify('77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906')),
(b'password', b'NaCl', 1024, 8, 16, unhexlify('fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640')),
(b'pleaseletmein', b'SodiumChloride', 16384, 8, 1, unhexlify('7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887')),
]
pbkdf2_results = {
"sha1": [
@@ -984,7 +1019,7 @@ class KDFTests(unittest.TestCase):
#(bytes.fromhex('eefe3d61cd4da4e4e9945b3d6ba2158c2634e984'), None),
(bytes.fromhex('3d2eec4fe41c849b80c8d83662c0e44a8b291a964c'
'f2f07038'), 25),
(bytes.fromhex('56fa6aa75548099dcc37d7f03425e0c3'), None), ],
(bytes.fromhex('56fa6aa75548099dcc37d7f03425e0c3'), None),],
"sha256": [
(bytes.fromhex('120fb6cffcf8b32c43e7225256c4f837'
'a86548c92ccc35480805987cb70be17b'), None),
@@ -992,11 +1027,11 @@ class KDFTests(unittest.TestCase):
'2a303f8ef3c251dfd6e2d85a95474c43'), None),
(bytes.fromhex('c5e478d59288c841aa530db6845c4c8d'
'962893a001ce4e11a4963873aa98134a'), None),
# (bytes.fromhex('cf81c66fe8cfc04d1f31ecb65dab4089'
#(bytes.fromhex('cf81c66fe8cfc04d1f31ecb65dab4089'
# 'f7f179e89b3b0bcb17ad10e3ac6eba46'), None),
(bytes.fromhex('348c89dbcbd32b2f32d814b8116e84cf2b17'
'347ebc1800181c4e2a1fb8dd53e1c635518c7dac47e9'), 40),
(bytes.fromhex('89b69d0516f829893c696226650a8687'), None), ],
(bytes.fromhex('89b69d0516f829893c696226650a8687'), None),],
"sha512": [
(bytes.fromhex('867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5'
'd513554e1c8cf252c02d470a285a0501bad999bfe943c08f'
@@ -1010,7 +1045,7 @@ class KDFTests(unittest.TestCase):
(bytes.fromhex('8c0511f4c6e597c6ac6315d8f0362e225f3c501495ba23b8'
'68c005174dc4ee71115b59f9e60cd9532fa33e0f75aefe30'
'225c583a186cd82bd4daea9724a3d3b8'), 64),
(bytes.fromhex('9d9e9c4cd21fe4be24d5b8244c759665'), None), ],
(bytes.fromhex('9d9e9c4cd21fe4be24d5b8244c759665'), None),],
}
def _test_pbkdf2_hmac(self, pbkdf2, supported):
@@ -1036,7 +1071,7 @@ class KDFTests(unittest.TestCase):
self.assertEqual(out, expected,
(digest_name, password, salt, rounds))
with self.assertRaisesRegex(ValueError, 'unsupported hash type'):
with self.assertRaisesRegex(ValueError, '.*unsupported.*'):
pbkdf2('unknown', b'pass', b'salt', 1)
if 'sha1' in supported:
@@ -1059,22 +1094,26 @@ class KDFTests(unittest.TestCase):
ValueError, pbkdf2, 'sha1', b'pass', b'salt', 1, -1
)
out = pbkdf2(hash_name='sha1', password=b'password', salt=b'salt',
iterations=1, dklen=None)
iterations=1, dklen=None)
self.assertEqual(out, self.pbkdf2_results['sha1'][0][0])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.skipIf(builtin_hashlib is None, "test requires builtin_hashlib")
def test_pbkdf2_hmac_py(self):
self._test_pbkdf2_hmac(builtin_hashlib.pbkdf2_hmac, builtin_hashes)
with warnings_helper.check_warnings():
self._test_pbkdf2_hmac(
builtin_hashlib.pbkdf2_hmac, builtin_hashes
)
@unittest.skipUnless(hasattr(openssl_hashlib, 'pbkdf2_hmac'),
' test requires OpenSSL > 1.0')
' test requires OpenSSL > 1.0')
def test_pbkdf2_hmac_c(self):
self._test_pbkdf2_hmac(openssl_hashlib.pbkdf2_hmac, openssl_md_meth_names)
@unittest.skipUnless(hasattr(hashlib, 'scrypt'),
' test requires OpenSSL > 1.1')
' test requires OpenSSL > 1.1')
@unittest.skipIf(get_fips_mode(), reason="scrypt is blocked in FIPS mode")
def test_scrypt(self):
for password, salt, n, r, p, expected in self.scrypt_test_vectors:
result = hashlib.scrypt(password, salt=salt, n=n, r=r, p=p)

View File

@@ -146,11 +146,11 @@ class TestHeap:
self.assertEqual(type(h[0]), int)
self.assertEqual(type(x), float)
h = [10];
h = [10]
x = self.module.heappushpop(h, 9)
self.assertEqual((h, x), ([10], 9))
h = [10];
h = [10]
x = self.module.heappushpop(h, 11)
self.assertEqual((h, x), ([11], 10))
@@ -433,6 +433,37 @@ class TestErrorHandling:
with self.assertRaises((IndexError, RuntimeError)):
self.module.heappop(heap)
def test_comparison_operator_modifiying_heap(self):
# See bpo-39421: Strong references need to be taken
# when comparing objects as they can alter the heap
class EvilClass(int):
def __lt__(self, o):
heap.clear()
return NotImplemented
heap = []
self.module.heappush(heap, EvilClass(0))
self.assertRaises(IndexError, self.module.heappushpop, heap, 1)
def test_comparison_operator_modifiying_heap_two_heaps(self):
class h(int):
def __lt__(self, o):
list2.clear()
return NotImplemented
class g(int):
def __lt__(self, o):
list1.clear()
return NotImplemented
list1, list2 = [], []
self.module.heappush(list1, h(0))
self.module.heappush(list2, g(0))
self.assertRaises((IndexError, RuntimeError), self.module.heappush, list1, g(1))
self.assertRaises((IndexError, RuntimeError), self.module.heappush, list2, h(1))
class TestErrorHandlingPython(TestErrorHandling, TestCase):
module = py_heapq

View File

@@ -1,295 +1,364 @@
# Tests some corner cases with isinstance() and issubclass(). While these
# tests use new style classes and properties, they actually do whitebox
# testing of error conditions uncovered when using extension types.
import unittest
import sys
class TestIsInstanceExceptions(unittest.TestCase):
# Test to make sure that an AttributeError when accessing the instance's
# class's bases is masked. This was actually a bug in Python 2.2 and
# 2.2.1 where the exception wasn't caught but it also wasn't being cleared
# (leading to an "undetected error" in the debug build). Set up is,
# isinstance(inst, cls) where:
#
# - cls isn't a type, or a tuple
# - cls has a __bases__ attribute
# - inst has a __class__ attribute
# - inst.__class__ as no __bases__ attribute
#
# Sounds complicated, I know, but this mimics a situation where an
# extension type raises an AttributeError when its __bases__ attribute is
# gotten. In that case, isinstance() should return False.
def test_class_has_no_bases(self):
class I(object):
def getclass(self):
# This must return an object that has no __bases__ attribute
return None
__class__ = property(getclass)
class C(object):
def getbases(self):
return ()
__bases__ = property(getbases)
self.assertEqual(False, isinstance(I(), C()))
# Like above except that inst.__class__.__bases__ raises an exception
# other than AttributeError
def test_bases_raises_other_than_attribute_error(self):
class E(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
class I(object):
def getclass(self):
return E()
__class__ = property(getclass)
class C(object):
def getbases(self):
return ()
__bases__ = property(getbases)
self.assertRaises(RuntimeError, isinstance, I(), C())
# Here's a situation where getattr(cls, '__bases__') raises an exception.
# If that exception is not AttributeError, it should not get masked
def test_dont_mask_non_attribute_error(self):
class I: pass
class C(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
self.assertRaises(RuntimeError, isinstance, I(), C())
# Like above, except that getattr(cls, '__bases__') raises an
# AttributeError, which /should/ get masked as a TypeError
def test_mask_attribute_error(self):
class I: pass
class C(object):
def getbases(self):
raise AttributeError
__bases__ = property(getbases)
self.assertRaises(TypeError, isinstance, I(), C())
# check that we don't mask non AttributeErrors
# see: http://bugs.python.org/issue1574217
def test_isinstance_dont_mask_non_attribute_error(self):
class C(object):
def getclass(self):
raise RuntimeError
__class__ = property(getclass)
c = C()
self.assertRaises(RuntimeError, isinstance, c, bool)
# test another code path
class D: pass
self.assertRaises(RuntimeError, isinstance, c, D)
# These tests are similar to above, but tickle certain code paths in
# issubclass() instead of isinstance() -- really PyObject_IsSubclass()
# vs. PyObject_IsInstance().
class TestIsSubclassExceptions(unittest.TestCase):
def test_dont_mask_non_attribute_error(self):
class C(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
class S(C): pass
self.assertRaises(RuntimeError, issubclass, C(), S())
def test_mask_attribute_error(self):
class C(object):
def getbases(self):
raise AttributeError
__bases__ = property(getbases)
class S(C): pass
self.assertRaises(TypeError, issubclass, C(), S())
# Like above, but test the second branch, where the __bases__ of the
# second arg (the cls arg) is tested. This means the first arg must
# return a valid __bases__, and it's okay for it to be a normal --
# unrelated by inheritance -- class.
def test_dont_mask_non_attribute_error_in_cls_arg(self):
class B: pass
class C(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
self.assertRaises(RuntimeError, issubclass, B, C())
def test_mask_attribute_error_in_cls_arg(self):
class B: pass
class C(object):
def getbases(self):
raise AttributeError
__bases__ = property(getbases)
self.assertRaises(TypeError, issubclass, B, C())
# meta classes for creating abstract classes and instances
class AbstractClass(object):
def __init__(self, bases):
self.bases = bases
def getbases(self):
return self.bases
__bases__ = property(getbases)
def __call__(self):
return AbstractInstance(self)
class AbstractInstance(object):
def __init__(self, klass):
self.klass = klass
def getclass(self):
return self.klass
__class__ = property(getclass)
# abstract classes
AbstractSuper = AbstractClass(bases=())
AbstractChild = AbstractClass(bases=(AbstractSuper,))
# normal classes
class Super:
pass
class Child(Super):
pass
class TestIsInstanceIsSubclass(unittest.TestCase):
# Tests to ensure that isinstance and issubclass work on abstract
# classes and instances. Before the 2.2 release, TypeErrors were
# raised when boolean values should have been returned. The bug was
# triggered by mixing 'normal' classes and instances were with
# 'abstract' classes and instances. This case tries to test all
# combinations.
def test_isinstance_normal(self):
# normal instances
self.assertEqual(True, isinstance(Super(), Super))
self.assertEqual(False, isinstance(Super(), Child))
self.assertEqual(False, isinstance(Super(), AbstractSuper))
self.assertEqual(False, isinstance(Super(), AbstractChild))
self.assertEqual(True, isinstance(Child(), Super))
self.assertEqual(False, isinstance(Child(), AbstractSuper))
def test_isinstance_abstract(self):
# abstract instances
self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper))
self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild))
self.assertEqual(False, isinstance(AbstractSuper(), Super))
self.assertEqual(False, isinstance(AbstractSuper(), Child))
self.assertEqual(True, isinstance(AbstractChild(), AbstractChild))
self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper))
self.assertEqual(False, isinstance(AbstractChild(), Super))
self.assertEqual(False, isinstance(AbstractChild(), Child))
def test_subclass_normal(self):
# normal classes
self.assertEqual(True, issubclass(Super, Super))
self.assertEqual(False, issubclass(Super, AbstractSuper))
self.assertEqual(False, issubclass(Super, Child))
self.assertEqual(True, issubclass(Child, Child))
self.assertEqual(True, issubclass(Child, Super))
self.assertEqual(False, issubclass(Child, AbstractSuper))
def test_subclass_abstract(self):
# abstract classes
self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
self.assertEqual(False, issubclass(AbstractSuper, Child))
self.assertEqual(True, issubclass(AbstractChild, AbstractChild))
self.assertEqual(True, issubclass(AbstractChild, AbstractSuper))
self.assertEqual(False, issubclass(AbstractChild, Super))
self.assertEqual(False, issubclass(AbstractChild, Child))
def test_subclass_tuple(self):
# test with a tuple as the second argument classes
self.assertEqual(True, issubclass(Child, (Child,)))
self.assertEqual(True, issubclass(Child, (Super,)))
self.assertEqual(False, issubclass(Super, (Child,)))
self.assertEqual(True, issubclass(Super, (Child, Super)))
self.assertEqual(False, issubclass(Child, ()))
self.assertEqual(True, issubclass(Super, (Child, (Super,))))
self.assertEqual(True, issubclass(int, (int, (float, int))))
self.assertEqual(True, issubclass(str, (str, (Child, str))))
def test_subclass_recursion_limit(self):
# make sure that issubclass raises RecursionError before the C stack is
# blown
self.assertRaises(RecursionError, blowstack, issubclass, str, str)
def test_isinstance_recursion_limit(self):
# make sure that issubclass raises RecursionError before the C stack is
# blown
self.assertRaises(RecursionError, blowstack, isinstance, '', str)
def test_issubclass_refcount_handling(self):
# bpo-39382: abstract_issubclass() didn't hold item reference while
# peeking in the bases tuple, in the single inheritance case.
class A:
@property
def __bases__(self):
return (int, )
class B:
def __init__(self):
# setting this here increases the chances of exhibiting the bug,
# probably due to memory layout changes.
self.x = 1
@property
def __bases__(self):
return (A(), )
self.assertEqual(True, issubclass(B(), int))
def test_infinite_recursion_in_bases(self):
class X:
@property
def __bases__(self):
return self.__bases__
self.assertRaises(RecursionError, issubclass, X(), int)
self.assertRaises(RecursionError, issubclass, int, X())
self.assertRaises(RecursionError, isinstance, 1, X())
def blowstack(fxn, arg, compare_to):
# Make sure that calling isinstance with a deeply nested tuple for its
# argument will raise RecursionError eventually.
tuple_arg = (compare_to,)
for cnt in range(sys.getrecursionlimit()+5):
tuple_arg = (tuple_arg,)
fxn(arg, tuple_arg)
if __name__ == '__main__':
unittest.main()
# Tests some corner cases with isinstance() and issubclass(). While these
# tests use new style classes and properties, they actually do whitebox
# testing of error conditions uncovered when using extension types.
import unittest
import sys
import typing
from test import support
class TestIsInstanceExceptions(unittest.TestCase):
# Test to make sure that an AttributeError when accessing the instance's
# class's bases is masked. This was actually a bug in Python 2.2 and
# 2.2.1 where the exception wasn't caught but it also wasn't being cleared
# (leading to an "undetected error" in the debug build). Set up is,
# isinstance(inst, cls) where:
#
# - cls isn't a type, or a tuple
# - cls has a __bases__ attribute
# - inst has a __class__ attribute
# - inst.__class__ as no __bases__ attribute
#
# Sounds complicated, I know, but this mimics a situation where an
# extension type raises an AttributeError when its __bases__ attribute is
# gotten. In that case, isinstance() should return False.
def test_class_has_no_bases(self):
class I(object):
def getclass(self):
# This must return an object that has no __bases__ attribute
return None
__class__ = property(getclass)
class C(object):
def getbases(self):
return ()
__bases__ = property(getbases)
self.assertEqual(False, isinstance(I(), C()))
# Like above except that inst.__class__.__bases__ raises an exception
# other than AttributeError
def test_bases_raises_other_than_attribute_error(self):
class E(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
class I(object):
def getclass(self):
return E()
__class__ = property(getclass)
class C(object):
def getbases(self):
return ()
__bases__ = property(getbases)
self.assertRaises(RuntimeError, isinstance, I(), C())
# Here's a situation where getattr(cls, '__bases__') raises an exception.
# If that exception is not AttributeError, it should not get masked
def test_dont_mask_non_attribute_error(self):
class I: pass
class C(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
self.assertRaises(RuntimeError, isinstance, I(), C())
# Like above, except that getattr(cls, '__bases__') raises an
# AttributeError, which /should/ get masked as a TypeError
def test_mask_attribute_error(self):
class I: pass
class C(object):
def getbases(self):
raise AttributeError
__bases__ = property(getbases)
self.assertRaises(TypeError, isinstance, I(), C())
# check that we don't mask non AttributeErrors
# see: http://bugs.python.org/issue1574217
def test_isinstance_dont_mask_non_attribute_error(self):
class C(object):
def getclass(self):
raise RuntimeError
__class__ = property(getclass)
c = C()
self.assertRaises(RuntimeError, isinstance, c, bool)
# test another code path
class D: pass
self.assertRaises(RuntimeError, isinstance, c, D)
# These tests are similar to above, but tickle certain code paths in
# issubclass() instead of isinstance() -- really PyObject_IsSubclass()
# vs. PyObject_IsInstance().
class TestIsSubclassExceptions(unittest.TestCase):
def test_dont_mask_non_attribute_error(self):
class C(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
class S(C): pass
self.assertRaises(RuntimeError, issubclass, C(), S())
def test_mask_attribute_error(self):
class C(object):
def getbases(self):
raise AttributeError
__bases__ = property(getbases)
class S(C): pass
self.assertRaises(TypeError, issubclass, C(), S())
# Like above, but test the second branch, where the __bases__ of the
# second arg (the cls arg) is tested. This means the first arg must
# return a valid __bases__, and it's okay for it to be a normal --
# unrelated by inheritance -- class.
def test_dont_mask_non_attribute_error_in_cls_arg(self):
class B: pass
class C(object):
def getbases(self):
raise RuntimeError
__bases__ = property(getbases)
self.assertRaises(RuntimeError, issubclass, B, C())
def test_mask_attribute_error_in_cls_arg(self):
class B: pass
class C(object):
def getbases(self):
raise AttributeError
__bases__ = property(getbases)
self.assertRaises(TypeError, issubclass, B, C())
# meta classes for creating abstract classes and instances
class AbstractClass(object):
def __init__(self, bases):
self.bases = bases
def getbases(self):
return self.bases
__bases__ = property(getbases)
def __call__(self):
return AbstractInstance(self)
class AbstractInstance(object):
def __init__(self, klass):
self.klass = klass
def getclass(self):
return self.klass
__class__ = property(getclass)
# abstract classes
AbstractSuper = AbstractClass(bases=())
AbstractChild = AbstractClass(bases=(AbstractSuper,))
# normal classes
class Super:
pass
class Child(Super):
pass
class TestIsInstanceIsSubclass(unittest.TestCase):
# Tests to ensure that isinstance and issubclass work on abstract
# classes and instances. Before the 2.2 release, TypeErrors were
# raised when boolean values should have been returned. The bug was
# triggered by mixing 'normal' classes and instances were with
# 'abstract' classes and instances. This case tries to test all
# combinations.
def test_isinstance_normal(self):
# normal instances
self.assertEqual(True, isinstance(Super(), Super))
self.assertEqual(False, isinstance(Super(), Child))
self.assertEqual(False, isinstance(Super(), AbstractSuper))
self.assertEqual(False, isinstance(Super(), AbstractChild))
self.assertEqual(True, isinstance(Child(), Super))
self.assertEqual(False, isinstance(Child(), AbstractSuper))
def test_isinstance_abstract(self):
# abstract instances
self.assertEqual(True, isinstance(AbstractSuper(), AbstractSuper))
self.assertEqual(False, isinstance(AbstractSuper(), AbstractChild))
self.assertEqual(False, isinstance(AbstractSuper(), Super))
self.assertEqual(False, isinstance(AbstractSuper(), Child))
self.assertEqual(True, isinstance(AbstractChild(), AbstractChild))
self.assertEqual(True, isinstance(AbstractChild(), AbstractSuper))
self.assertEqual(False, isinstance(AbstractChild(), Super))
self.assertEqual(False, isinstance(AbstractChild(), Child))
def test_isinstance_with_or_union(self):
self.assertTrue(isinstance(Super(), Super | int))
self.assertFalse(isinstance(None, str | int))
self.assertTrue(isinstance(3, str | int))
self.assertTrue(isinstance("", str | int))
self.assertTrue(isinstance([], typing.List | typing.Tuple))
self.assertTrue(isinstance(2, typing.List | int))
self.assertFalse(isinstance(2, typing.List | typing.Tuple))
self.assertTrue(isinstance(None, int | None))
self.assertFalse(isinstance(3.14, int | str))
with self.assertRaises(TypeError):
isinstance(2, list[int])
with self.assertRaises(TypeError):
isinstance(2, list[int] | int)
with self.assertRaises(TypeError):
isinstance(2, int | str | list[int] | float)
def test_subclass_normal(self):
# normal classes
self.assertEqual(True, issubclass(Super, Super))
self.assertEqual(False, issubclass(Super, AbstractSuper))
self.assertEqual(False, issubclass(Super, Child))
self.assertEqual(True, issubclass(Child, Child))
self.assertEqual(True, issubclass(Child, Super))
self.assertEqual(False, issubclass(Child, AbstractSuper))
self.assertTrue(issubclass(typing.List, typing.List|typing.Tuple))
self.assertFalse(issubclass(int, typing.List|typing.Tuple))
def test_subclass_abstract(self):
# abstract classes
self.assertEqual(True, issubclass(AbstractSuper, AbstractSuper))
self.assertEqual(False, issubclass(AbstractSuper, AbstractChild))
self.assertEqual(False, issubclass(AbstractSuper, Child))
self.assertEqual(True, issubclass(AbstractChild, AbstractChild))
self.assertEqual(True, issubclass(AbstractChild, AbstractSuper))
self.assertEqual(False, issubclass(AbstractChild, Super))
self.assertEqual(False, issubclass(AbstractChild, Child))
def test_subclass_tuple(self):
# test with a tuple as the second argument classes
self.assertEqual(True, issubclass(Child, (Child,)))
self.assertEqual(True, issubclass(Child, (Super,)))
self.assertEqual(False, issubclass(Super, (Child,)))
self.assertEqual(True, issubclass(Super, (Child, Super)))
self.assertEqual(False, issubclass(Child, ()))
self.assertEqual(True, issubclass(Super, (Child, (Super,))))
self.assertEqual(True, issubclass(int, (int, (float, int))))
self.assertEqual(True, issubclass(str, (str, (Child, str))))
def test_subclass_recursion_limit(self):
# make sure that issubclass raises RecursionError before the C stack is
# blown
with support.infinite_recursion():
self.assertRaises(RecursionError, blowstack, issubclass, str, str)
def test_isinstance_recursion_limit(self):
# make sure that issubclass raises RecursionError before the C stack is
# blown
with support.infinite_recursion():
self.assertRaises(RecursionError, blowstack, isinstance, '', str)
def test_subclass_with_union(self):
self.assertTrue(issubclass(int, int | float | int))
self.assertTrue(issubclass(str, str | Child | str))
self.assertFalse(issubclass(dict, float|str))
self.assertFalse(issubclass(object, float|str))
with self.assertRaises(TypeError):
issubclass(2, Child | Super)
with self.assertRaises(TypeError):
issubclass(int, list[int] | Child)
def test_issubclass_refcount_handling(self):
# bpo-39382: abstract_issubclass() didn't hold item reference while
# peeking in the bases tuple, in the single inheritance case.
class A:
@property
def __bases__(self):
return (int, )
class B:
def __init__(self):
# setting this here increases the chances of exhibiting the bug,
# probably due to memory layout changes.
self.x = 1
@property
def __bases__(self):
return (A(), )
self.assertEqual(True, issubclass(B(), int))
def test_infinite_recursion_in_bases(self):
class X:
@property
def __bases__(self):
return self.__bases__
with support.infinite_recursion():
self.assertRaises(RecursionError, issubclass, X(), int)
self.assertRaises(RecursionError, issubclass, int, X())
self.assertRaises(RecursionError, isinstance, 1, X())
@unittest.skip("TODO: RUSTPYTHON")
def test_infinite_recursion_via_bases_tuple(self):
"""Regression test for bpo-30570."""
class Failure(object):
def __getattr__(self, attr):
return (self, None)
with support.infinite_recursion():
with self.assertRaises(RecursionError):
issubclass(Failure(), int)
@unittest.skip("TODO: RUSTPYTHON")
def test_infinite_cycle_in_bases(self):
"""Regression test for bpo-30570."""
class X:
@property
def __bases__(self):
return (self, self, self)
with support.infinite_recursion():
self.assertRaises(RecursionError, issubclass, X(), int)
def test_infinitely_many_bases(self):
"""Regression test for bpo-30570."""
class X:
def __getattr__(self, attr):
self.assertEqual(attr, "__bases__")
class A:
pass
class B:
pass
A.__getattr__ = B.__getattr__ = X.__getattr__
return (A(), B())
with support.infinite_recursion():
self.assertRaises(RecursionError, issubclass, X(), int)
def blowstack(fxn, arg, compare_to):
# Make sure that calling isinstance with a deeply nested tuple for its
# argument will raise RecursionError eventually.
tuple_arg = (compare_to,)
for cnt in range(sys.getrecursionlimit()+5):
tuple_arg = (tuple_arg,)
fxn(arg, tuple_arg)
if __name__ == '__main__':
unittest.main()