mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Merge pull request #5127 from NakanoMiku39/main
Update test files from CPython v3.12.0
This commit is contained in:
17 files changed
+1186
-61
No files matched your search
Vendored
+9
-9
@@ -18,9 +18,6 @@ from test.support.script_helper import (
|
||||
if not support.has_subprocess_support:
|
||||
raise unittest.SkipTest("test module requires subprocess")
|
||||
|
||||
# Debug build?
|
||||
Py_DEBUG = hasattr(sys, "gettotalrefcount")
|
||||
|
||||
|
||||
# XXX (ncoghlan): Move to script_helper and make consistent with run_python
|
||||
def _kill_python_and_exit_code(p):
|
||||
@@ -144,7 +141,7 @@ class CmdLineTest(unittest.TestCase):
|
||||
# "-X showrefcount" shows the refcount, but only in debug builds
|
||||
rc, out, err = run_python('-I', '-X', 'showrefcount', '-c', code)
|
||||
self.assertEqual(out.rstrip(), b"{'showrefcount': True}")
|
||||
if Py_DEBUG:
|
||||
if support.Py_DEBUG:
|
||||
# bpo-46417: Tolerate negative reference count which can occur
|
||||
# because of bugs in C extensions. This test is only about checking
|
||||
# the showrefcount feature.
|
||||
@@ -753,7 +750,7 @@ class CmdLineTest(unittest.TestCase):
|
||||
code = ("import warnings; "
|
||||
"print(' '.join('%s::%s' % (f[0], f[2].__name__) "
|
||||
"for f in warnings.filters))")
|
||||
if Py_DEBUG:
|
||||
if support.Py_DEBUG:
|
||||
expected_filters = "default::Warning"
|
||||
else:
|
||||
expected_filters = ("default::Warning "
|
||||
@@ -827,7 +824,7 @@ class CmdLineTest(unittest.TestCase):
|
||||
expected_filters = ("error::BytesWarning "
|
||||
"once::UserWarning "
|
||||
"always::UserWarning")
|
||||
if not Py_DEBUG:
|
||||
if not support.Py_DEBUG:
|
||||
expected_filters += (" "
|
||||
"default::DeprecationWarning "
|
||||
"ignore::DeprecationWarning "
|
||||
@@ -867,10 +864,10 @@ class CmdLineTest(unittest.TestCase):
|
||||
# Test the PYTHONMALLOC environment variable
|
||||
pymalloc = support.with_pymalloc()
|
||||
if pymalloc:
|
||||
default_name = 'pymalloc_debug' if Py_DEBUG else 'pymalloc'
|
||||
default_name = 'pymalloc_debug' if support.Py_DEBUG else 'pymalloc'
|
||||
default_name_debug = 'pymalloc_debug'
|
||||
else:
|
||||
default_name = 'malloc_debug' if Py_DEBUG else 'malloc'
|
||||
default_name = 'malloc_debug' if support.Py_DEBUG else 'malloc'
|
||||
default_name_debug = 'malloc_debug'
|
||||
|
||||
tests = [
|
||||
@@ -933,6 +930,8 @@ class CmdLineTest(unittest.TestCase):
|
||||
self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr)
|
||||
self.assertNotEqual(proc.returncode, 0)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_int_max_str_digits(self):
|
||||
code = "import sys; print(sys.flags.int_max_str_digits, sys.get_int_max_str_digits())"
|
||||
|
||||
@@ -950,7 +949,8 @@ class CmdLineTest(unittest.TestCase):
|
||||
return tuple(int(i) for i in out.split())
|
||||
|
||||
res = assert_python_ok('-c', code)
|
||||
self.assertEqual(res2int(res), (-1, sys.get_int_max_str_digits()))
|
||||
current_max = sys.get_int_max_str_digits()
|
||||
self.assertEqual(res2int(res), (current_max, current_max))
|
||||
res = assert_python_ok('-X', 'int_max_str_digits=0', '-c', code)
|
||||
self.assertEqual(res2int(res), (0, 0))
|
||||
res = assert_python_ok('-X', 'int_max_str_digits=4000', '-c', code)
|
||||
|
||||
Vendored
+33
-4
@@ -662,9 +662,9 @@ class CmdLineTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
stderr.splitlines()[-3:],
|
||||
[
|
||||
b' foo"""',
|
||||
b' ^',
|
||||
b'SyntaxError: f-string: empty expression not allowed',
|
||||
b' foo = f"""{}',
|
||||
b' ^',
|
||||
b'SyntaxError: f-string: valid expression required before \'}\'',
|
||||
],
|
||||
)
|
||||
|
||||
@@ -685,6 +685,35 @@ class CmdLineTest(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_syntaxerror_null_bytes(self):
|
||||
script = "x = '\0' nothing to see here\n';import os;os.system('echo pwnd')\n"
|
||||
with os_helper.temp_dir() as script_dir:
|
||||
script_name = _make_test_script(script_dir, 'script', script)
|
||||
exitcode, stdout, stderr = assert_python_failure(script_name)
|
||||
self.assertEqual(
|
||||
stderr.splitlines()[-2:],
|
||||
[ b" x = '",
|
||||
b'SyntaxError: source code cannot contain null bytes'
|
||||
],
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_syntaxerror_null_bytes_in_multiline_string(self):
|
||||
scripts = ["\n'''\nmultilinestring\0\n'''", "\nf'''\nmultilinestring\0\n'''"] # Both normal and f-strings
|
||||
with os_helper.temp_dir() as script_dir:
|
||||
for script in scripts:
|
||||
script_name = _make_test_script(script_dir, 'script', script)
|
||||
_, _, stderr = assert_python_failure(script_name)
|
||||
self.assertEqual(
|
||||
stderr.splitlines()[-2:],
|
||||
[ b" multilinestring",
|
||||
b'SyntaxError: source code cannot contain null bytes'
|
||||
]
|
||||
)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_consistent_sys_path_for_direct_execution(self):
|
||||
@@ -785,7 +814,7 @@ class CmdLineTest(unittest.TestCase):
|
||||
with os_helper.temp_dir() as work_dir:
|
||||
script_name = _make_test_script(work_dir, 'script.py', script)
|
||||
with open(script_name, "r") as fp:
|
||||
p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=False, pass_fds=(0,1,2,fp.fileno()))
|
||||
p = spawn_python(f"/dev/fd/{fp.fileno()}", close_fds=True, pass_fds=(0,1,2,fp.fileno()))
|
||||
out, err = p.communicate()
|
||||
self.assertEqual(out, b"12345678912345678912345\n")
|
||||
|
||||
|
||||
Vendored
+1
@@ -6,6 +6,7 @@ from contextlib import ExitStack
|
||||
from unittest import mock
|
||||
from test.support import import_helper
|
||||
|
||||
|
||||
code = import_helper.import_module('code')
|
||||
|
||||
|
||||
|
||||
Vendored
+409
-17
@@ -1,21 +1,27 @@
|
||||
"""Test equality and order comparisons."""
|
||||
import unittest
|
||||
from test.support import ALWAYS_EQ
|
||||
from fractions import Fraction
|
||||
from decimal import Decimal
|
||||
|
||||
class Empty:
|
||||
def __repr__(self):
|
||||
return '<Empty>'
|
||||
|
||||
class Cmp:
|
||||
def __init__(self,arg):
|
||||
self.arg = arg
|
||||
class ComparisonSimpleTest(unittest.TestCase):
|
||||
"""Test equality and order comparisons for some simple cases."""
|
||||
|
||||
def __repr__(self):
|
||||
return '<Cmp %s>' % self.arg
|
||||
class Empty:
|
||||
def __repr__(self):
|
||||
return '<Empty>'
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.arg == other
|
||||
class Cmp:
|
||||
def __init__(self, arg):
|
||||
self.arg = arg
|
||||
|
||||
def __repr__(self):
|
||||
return '<Cmp %s>' % self.arg
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.arg == other
|
||||
|
||||
class ComparisonTest(unittest.TestCase):
|
||||
set1 = [2, 2.0, 2, 2+0j, Cmp(2.0)]
|
||||
set2 = [[1], (3,), None, Empty()]
|
||||
candidates = set1 + set2
|
||||
@@ -32,16 +38,15 @@ class ComparisonTest(unittest.TestCase):
|
||||
# Ensure default comparison compares id() of args
|
||||
L = []
|
||||
for i in range(10):
|
||||
L.insert(len(L)//2, Empty())
|
||||
L.insert(len(L)//2, self.Empty())
|
||||
for a in L:
|
||||
for b in L:
|
||||
self.assertEqual(a == b, id(a) == id(b),
|
||||
'a=%r, b=%r' % (a, b))
|
||||
self.assertEqual(a == b, a is b, 'a=%r, b=%r' % (a, b))
|
||||
|
||||
def test_ne_defaults_to_not_eq(self):
|
||||
a = Cmp(1)
|
||||
b = Cmp(1)
|
||||
c = Cmp(2)
|
||||
a = self.Cmp(1)
|
||||
b = self.Cmp(1)
|
||||
c = self.Cmp(2)
|
||||
self.assertIs(a == b, True)
|
||||
self.assertIs(a != b, False)
|
||||
self.assertIs(a != c, True)
|
||||
@@ -114,5 +119,392 @@ class ComparisonTest(unittest.TestCase):
|
||||
self.assertEqual(ALWAYS_EQ, y)
|
||||
|
||||
|
||||
class ComparisonFullTest(unittest.TestCase):
|
||||
"""Test equality and ordering comparisons for built-in types and
|
||||
user-defined classes that implement relevant combinations of rich
|
||||
comparison methods.
|
||||
"""
|
||||
|
||||
class CompBase:
|
||||
"""Base class for classes with rich comparison methods.
|
||||
|
||||
The "x" attribute should be set to an underlying value to compare.
|
||||
|
||||
Derived classes have a "meth" tuple attribute listing names of
|
||||
comparison methods implemented. See assert_total_order().
|
||||
"""
|
||||
|
||||
# Class without any rich comparison methods.
|
||||
class CompNone(CompBase):
|
||||
meth = ()
|
||||
|
||||
# Classes with all combinations of value-based equality comparison methods.
|
||||
class CompEq(CompBase):
|
||||
meth = ("eq",)
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x
|
||||
|
||||
class CompNe(CompBase):
|
||||
meth = ("ne",)
|
||||
def __ne__(self, other):
|
||||
return self.x != other.x
|
||||
|
||||
class CompEqNe(CompBase):
|
||||
meth = ("eq", "ne")
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x
|
||||
def __ne__(self, other):
|
||||
return self.x != other.x
|
||||
|
||||
# Classes with all combinations of value-based less/greater-than order
|
||||
# comparison methods.
|
||||
class CompLt(CompBase):
|
||||
meth = ("lt",)
|
||||
def __lt__(self, other):
|
||||
return self.x < other.x
|
||||
|
||||
class CompGt(CompBase):
|
||||
meth = ("gt",)
|
||||
def __gt__(self, other):
|
||||
return self.x > other.x
|
||||
|
||||
class CompLtGt(CompBase):
|
||||
meth = ("lt", "gt")
|
||||
def __lt__(self, other):
|
||||
return self.x < other.x
|
||||
def __gt__(self, other):
|
||||
return self.x > other.x
|
||||
|
||||
# Classes with all combinations of value-based less/greater-or-equal-than
|
||||
# order comparison methods
|
||||
class CompLe(CompBase):
|
||||
meth = ("le",)
|
||||
def __le__(self, other):
|
||||
return self.x <= other.x
|
||||
|
||||
class CompGe(CompBase):
|
||||
meth = ("ge",)
|
||||
def __ge__(self, other):
|
||||
return self.x >= other.x
|
||||
|
||||
class CompLeGe(CompBase):
|
||||
meth = ("le", "ge")
|
||||
def __le__(self, other):
|
||||
return self.x <= other.x
|
||||
def __ge__(self, other):
|
||||
return self.x >= other.x
|
||||
|
||||
# It should be sufficient to combine the comparison methods only within
|
||||
# each group.
|
||||
all_comp_classes = (
|
||||
CompNone,
|
||||
CompEq, CompNe, CompEqNe, # equal group
|
||||
CompLt, CompGt, CompLtGt, # less/greater-than group
|
||||
CompLe, CompGe, CompLeGe) # less/greater-or-equal group
|
||||
|
||||
def create_sorted_instances(self, class_, values):
|
||||
"""Create objects of type `class_` and return them in a list.
|
||||
|
||||
`values` is a list of values that determines the value of data
|
||||
attribute `x` of each object.
|
||||
|
||||
Objects in the returned list are sorted by their identity. They
|
||||
assigned values in `values` list order. By assign decreasing
|
||||
values to objects with increasing identities, testcases can assert
|
||||
that order comparison is performed by value and not by identity.
|
||||
"""
|
||||
|
||||
instances = [class_() for __ in range(len(values))]
|
||||
instances.sort(key=id)
|
||||
# Assign the provided values to the instances.
|
||||
for inst, value in zip(instances, values):
|
||||
inst.x = value
|
||||
return instances
|
||||
|
||||
def assert_equality_only(self, a, b, equal):
|
||||
"""Assert equality result and that ordering is not implemented.
|
||||
|
||||
a, b: Instances to be tested (of same or different type).
|
||||
equal: Boolean indicating the expected equality comparison results.
|
||||
"""
|
||||
self.assertEqual(a == b, equal)
|
||||
self.assertEqual(b == a, equal)
|
||||
self.assertEqual(a != b, not equal)
|
||||
self.assertEqual(b != a, not equal)
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a < b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a <= b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a > b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a >= b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b < a
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b <= a
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b > a
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b >= a
|
||||
|
||||
def assert_total_order(self, a, b, comp, a_meth=None, b_meth=None):
|
||||
"""Test total ordering comparison of two instances.
|
||||
|
||||
a, b: Instances to be tested (of same or different type).
|
||||
|
||||
comp: -1, 0, or 1 indicates that the expected order comparison
|
||||
result for operations that are supported by the classes is
|
||||
a <, ==, or > b.
|
||||
|
||||
a_meth, b_meth: Either None, indicating that all rich comparison
|
||||
methods are available, aa for builtins, or the tuple (subset)
|
||||
of "eq", "ne", "lt", "le", "gt", and "ge" that are available
|
||||
for the corresponding instance (of a user-defined class).
|
||||
"""
|
||||
self.assert_eq_subtest(a, b, comp, a_meth, b_meth)
|
||||
self.assert_ne_subtest(a, b, comp, a_meth, b_meth)
|
||||
self.assert_lt_subtest(a, b, comp, a_meth, b_meth)
|
||||
self.assert_le_subtest(a, b, comp, a_meth, b_meth)
|
||||
self.assert_gt_subtest(a, b, comp, a_meth, b_meth)
|
||||
self.assert_ge_subtest(a, b, comp, a_meth, b_meth)
|
||||
|
||||
# The body of each subtest has form:
|
||||
#
|
||||
# if value-based comparison methods:
|
||||
# expect what the testcase defined for a op b and b rop a;
|
||||
# else: no value-based comparison
|
||||
# expect default behavior of object for a op b and b rop a.
|
||||
|
||||
def assert_eq_subtest(self, a, b, comp, a_meth, b_meth):
|
||||
if a_meth is None or "eq" in a_meth or "eq" in b_meth:
|
||||
self.assertEqual(a == b, comp == 0)
|
||||
self.assertEqual(b == a, comp == 0)
|
||||
else:
|
||||
self.assertEqual(a == b, a is b)
|
||||
self.assertEqual(b == a, a is b)
|
||||
|
||||
def assert_ne_subtest(self, a, b, comp, a_meth, b_meth):
|
||||
if a_meth is None or not {"ne", "eq"}.isdisjoint(a_meth + b_meth):
|
||||
self.assertEqual(a != b, comp != 0)
|
||||
self.assertEqual(b != a, comp != 0)
|
||||
else:
|
||||
self.assertEqual(a != b, a is not b)
|
||||
self.assertEqual(b != a, a is not b)
|
||||
|
||||
def assert_lt_subtest(self, a, b, comp, a_meth, b_meth):
|
||||
if a_meth is None or "lt" in a_meth or "gt" in b_meth:
|
||||
self.assertEqual(a < b, comp < 0)
|
||||
self.assertEqual(b > a, comp < 0)
|
||||
else:
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a < b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b > a
|
||||
|
||||
def assert_le_subtest(self, a, b, comp, a_meth, b_meth):
|
||||
if a_meth is None or "le" in a_meth or "ge" in b_meth:
|
||||
self.assertEqual(a <= b, comp <= 0)
|
||||
self.assertEqual(b >= a, comp <= 0)
|
||||
else:
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a <= b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b >= a
|
||||
|
||||
def assert_gt_subtest(self, a, b, comp, a_meth, b_meth):
|
||||
if a_meth is None or "gt" in a_meth or "lt" in b_meth:
|
||||
self.assertEqual(a > b, comp > 0)
|
||||
self.assertEqual(b < a, comp > 0)
|
||||
else:
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a > b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b < a
|
||||
|
||||
def assert_ge_subtest(self, a, b, comp, a_meth, b_meth):
|
||||
if a_meth is None or "ge" in a_meth or "le" in b_meth:
|
||||
self.assertEqual(a >= b, comp >= 0)
|
||||
self.assertEqual(b <= a, comp >= 0)
|
||||
else:
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
a >= b
|
||||
with self.assertRaisesRegex(TypeError, "not supported"):
|
||||
b <= a
|
||||
|
||||
def test_objects(self):
|
||||
"""Compare instances of type 'object'."""
|
||||
a = object()
|
||||
b = object()
|
||||
self.assert_equality_only(a, a, True)
|
||||
self.assert_equality_only(a, b, False)
|
||||
|
||||
def test_comp_classes_same(self):
|
||||
"""Compare same-class instances with comparison methods."""
|
||||
|
||||
for cls in self.all_comp_classes:
|
||||
with self.subTest(cls):
|
||||
instances = self.create_sorted_instances(cls, (1, 2, 1))
|
||||
|
||||
# Same object.
|
||||
self.assert_total_order(instances[0], instances[0], 0,
|
||||
cls.meth, cls.meth)
|
||||
|
||||
# Different objects, same value.
|
||||
self.assert_total_order(instances[0], instances[2], 0,
|
||||
cls.meth, cls.meth)
|
||||
|
||||
# Different objects, value ascending for ascending identities.
|
||||
self.assert_total_order(instances[0], instances[1], -1,
|
||||
cls.meth, cls.meth)
|
||||
|
||||
# different objects, value descending for ascending identities.
|
||||
# This is the interesting case to assert that order comparison
|
||||
# is performed based on the value and not based on the identity.
|
||||
self.assert_total_order(instances[1], instances[2], +1,
|
||||
cls.meth, cls.meth)
|
||||
|
||||
def test_comp_classes_different(self):
|
||||
"""Compare different-class instances with comparison methods."""
|
||||
|
||||
for cls_a in self.all_comp_classes:
|
||||
for cls_b in self.all_comp_classes:
|
||||
with self.subTest(a=cls_a, b=cls_b):
|
||||
a1 = cls_a()
|
||||
a1.x = 1
|
||||
b1 = cls_b()
|
||||
b1.x = 1
|
||||
b2 = cls_b()
|
||||
b2.x = 2
|
||||
|
||||
self.assert_total_order(
|
||||
a1, b1, 0, cls_a.meth, cls_b.meth)
|
||||
self.assert_total_order(
|
||||
a1, b2, -1, cls_a.meth, cls_b.meth)
|
||||
|
||||
def test_str_subclass(self):
|
||||
"""Compare instances of str and a subclass."""
|
||||
class StrSubclass(str):
|
||||
pass
|
||||
|
||||
s1 = str("a")
|
||||
s2 = str("b")
|
||||
c1 = StrSubclass("a")
|
||||
c2 = StrSubclass("b")
|
||||
c3 = StrSubclass("b")
|
||||
|
||||
self.assert_total_order(s1, s1, 0)
|
||||
self.assert_total_order(s1, s2, -1)
|
||||
self.assert_total_order(c1, c1, 0)
|
||||
self.assert_total_order(c1, c2, -1)
|
||||
self.assert_total_order(c2, c3, 0)
|
||||
|
||||
self.assert_total_order(s1, c2, -1)
|
||||
self.assert_total_order(s2, c3, 0)
|
||||
self.assert_total_order(c1, s2, -1)
|
||||
self.assert_total_order(c2, s2, 0)
|
||||
|
||||
def test_numbers(self):
|
||||
"""Compare number types."""
|
||||
|
||||
# Same types.
|
||||
i1 = 1001
|
||||
i2 = 1002
|
||||
self.assert_total_order(i1, i1, 0)
|
||||
self.assert_total_order(i1, i2, -1)
|
||||
|
||||
f1 = 1001.0
|
||||
f2 = 1001.1
|
||||
self.assert_total_order(f1, f1, 0)
|
||||
self.assert_total_order(f1, f2, -1)
|
||||
|
||||
q1 = Fraction(2002, 2)
|
||||
q2 = Fraction(2003, 2)
|
||||
self.assert_total_order(q1, q1, 0)
|
||||
self.assert_total_order(q1, q2, -1)
|
||||
|
||||
d1 = Decimal('1001.0')
|
||||
d2 = Decimal('1001.1')
|
||||
self.assert_total_order(d1, d1, 0)
|
||||
self.assert_total_order(d1, d2, -1)
|
||||
|
||||
c1 = 1001+0j
|
||||
c2 = 1001+1j
|
||||
self.assert_equality_only(c1, c1, True)
|
||||
self.assert_equality_only(c1, c2, False)
|
||||
|
||||
|
||||
# Mixing types.
|
||||
for n1, n2 in ((i1,f1), (i1,q1), (i1,d1), (f1,q1), (f1,d1), (q1,d1)):
|
||||
self.assert_total_order(n1, n2, 0)
|
||||
for n1 in (i1, f1, q1, d1):
|
||||
self.assert_equality_only(n1, c1, True)
|
||||
|
||||
def test_sequences(self):
|
||||
"""Compare list, tuple, and range."""
|
||||
l1 = [1, 2]
|
||||
l2 = [2, 3]
|
||||
self.assert_total_order(l1, l1, 0)
|
||||
self.assert_total_order(l1, l2, -1)
|
||||
|
||||
t1 = (1, 2)
|
||||
t2 = (2, 3)
|
||||
self.assert_total_order(t1, t1, 0)
|
||||
self.assert_total_order(t1, t2, -1)
|
||||
|
||||
r1 = range(1, 2)
|
||||
r2 = range(2, 2)
|
||||
self.assert_equality_only(r1, r1, True)
|
||||
self.assert_equality_only(r1, r2, False)
|
||||
|
||||
self.assert_equality_only(t1, l1, False)
|
||||
self.assert_equality_only(l1, r1, False)
|
||||
self.assert_equality_only(r1, t1, False)
|
||||
|
||||
def test_bytes(self):
|
||||
"""Compare bytes and bytearray."""
|
||||
bs1 = b'a1'
|
||||
bs2 = b'b2'
|
||||
self.assert_total_order(bs1, bs1, 0)
|
||||
self.assert_total_order(bs1, bs2, -1)
|
||||
|
||||
ba1 = bytearray(b'a1')
|
||||
ba2 = bytearray(b'b2')
|
||||
self.assert_total_order(ba1, ba1, 0)
|
||||
self.assert_total_order(ba1, ba2, -1)
|
||||
|
||||
self.assert_total_order(bs1, ba1, 0)
|
||||
self.assert_total_order(bs1, ba2, -1)
|
||||
self.assert_total_order(ba1, bs1, 0)
|
||||
self.assert_total_order(ba1, bs2, -1)
|
||||
|
||||
def test_sets(self):
|
||||
"""Compare set and frozenset."""
|
||||
s1 = {1, 2}
|
||||
s2 = {1, 2, 3}
|
||||
self.assert_total_order(s1, s1, 0)
|
||||
self.assert_total_order(s1, s2, -1)
|
||||
|
||||
f1 = frozenset(s1)
|
||||
f2 = frozenset(s2)
|
||||
self.assert_total_order(f1, f1, 0)
|
||||
self.assert_total_order(f1, f2, -1)
|
||||
|
||||
self.assert_total_order(s1, f1, 0)
|
||||
self.assert_total_order(s1, f2, -1)
|
||||
self.assert_total_order(f1, s1, 0)
|
||||
self.assert_total_order(f1, s2, -1)
|
||||
|
||||
def test_mappings(self):
|
||||
""" Compare dict.
|
||||
"""
|
||||
d1 = {1: "a", 2: "b"}
|
||||
d2 = {2: "b", 3: "c"}
|
||||
d3 = {3: "c", 2: "b"}
|
||||
self.assert_equality_only(d1, d1, True)
|
||||
self.assert_equality_only(d1, d2, False)
|
||||
self.assert_equality_only(d2, d3, True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Vendored
+58
@@ -109,6 +109,8 @@ class ComplexTest(unittest.TestCase):
|
||||
complex(random(), random()))
|
||||
|
||||
self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j)
|
||||
self.assertRaises(TypeError, operator.truediv, 1j, None)
|
||||
self.assertRaises(TypeError, operator.truediv, None, 1j)
|
||||
|
||||
for denom_real, denom_imag in [(0, NAN), (NAN, 0), (NAN, NAN)]:
|
||||
z = complex(0, 0) / complex(denom_real, denom_imag)
|
||||
@@ -140,6 +142,7 @@ class ComplexTest(unittest.TestCase):
|
||||
def test_richcompare(self):
|
||||
self.assertIs(complex.__eq__(1+1j, 1<<10000), False)
|
||||
self.assertIs(complex.__lt__(1+1j, None), NotImplemented)
|
||||
self.assertIs(complex.__eq__(1+1j, None), NotImplemented)
|
||||
self.assertIs(complex.__eq__(1+1j, 1+1j), True)
|
||||
self.assertIs(complex.__eq__(1+1j, 2+2j), False)
|
||||
self.assertIs(complex.__ne__(1+1j, 1+1j), False)
|
||||
@@ -162,6 +165,7 @@ class ComplexTest(unittest.TestCase):
|
||||
self.assertIs(operator.eq(1+1j, 2+2j), False)
|
||||
self.assertIs(operator.ne(1+1j, 1+1j), False)
|
||||
self.assertIs(operator.ne(1+1j, 2+2j), True)
|
||||
self.assertIs(operator.eq(1+1j, 2.0), False)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
@@ -182,6 +186,27 @@ class ComplexTest(unittest.TestCase):
|
||||
check(2 ** pow, range(1, 101), lambda delta: False, float(i))
|
||||
check(2 ** 53, range(-100, 0), lambda delta: True)
|
||||
|
||||
def test_add(self):
|
||||
self.assertEqual(1j + int(+1), complex(+1, 1))
|
||||
self.assertEqual(1j + int(-1), complex(-1, 1))
|
||||
self.assertRaises(OverflowError, operator.add, 1j, 10**1000)
|
||||
self.assertRaises(TypeError, operator.add, 1j, None)
|
||||
self.assertRaises(TypeError, operator.add, None, 1j)
|
||||
|
||||
def test_sub(self):
|
||||
self.assertEqual(1j - int(+1), complex(-1, 1))
|
||||
self.assertEqual(1j - int(-1), complex(1, 1))
|
||||
self.assertRaises(OverflowError, operator.sub, 1j, 10**1000)
|
||||
self.assertRaises(TypeError, operator.sub, 1j, None)
|
||||
self.assertRaises(TypeError, operator.sub, None, 1j)
|
||||
|
||||
def test_mul(self):
|
||||
self.assertEqual(1j * int(20), complex(0, 20))
|
||||
self.assertEqual(1j * int(-1), complex(0, -1))
|
||||
self.assertRaises(OverflowError, operator.mul, 1j, 10**1000)
|
||||
self.assertRaises(TypeError, operator.mul, 1j, None)
|
||||
self.assertRaises(TypeError, operator.mul, None, 1j)
|
||||
|
||||
def test_mod(self):
|
||||
# % is no longer supported on complex numbers
|
||||
with self.assertRaises(TypeError):
|
||||
@@ -211,14 +236,23 @@ class ComplexTest(unittest.TestCase):
|
||||
for a, b in ZERO_DIVISION:
|
||||
self.assertRaises(TypeError, divmod, a, b)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_pow(self):
|
||||
self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0)
|
||||
self.assertAlmostEqual(pow(0+0j, 2+0j), 0.0)
|
||||
self.assertEqual(pow(0+0j, 2000+0j), 0.0)
|
||||
self.assertEqual(pow(0, 0+0j), 1.0)
|
||||
self.assertEqual(pow(-1, 0+0j), 1.0)
|
||||
self.assertRaises(ZeroDivisionError, pow, 0+0j, 1j)
|
||||
self.assertRaises(ZeroDivisionError, pow, 0+0j, -1000)
|
||||
self.assertAlmostEqual(pow(1j, -1), 1/1j)
|
||||
self.assertAlmostEqual(pow(1j, 200), 1)
|
||||
self.assertRaises(ValueError, pow, 1+1j, 1+1j, 1+1j)
|
||||
self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
|
||||
self.assertRaises(TypeError, pow, 1j, None)
|
||||
self.assertRaises(TypeError, pow, None, 1j)
|
||||
self.assertAlmostEqual(pow(1j, 0.5), 0.7071067811865476+0.7071067811865475j)
|
||||
|
||||
a = 3.33+4.43j
|
||||
self.assertEqual(a ** 0j, 1)
|
||||
@@ -303,6 +337,7 @@ class ComplexTest(unittest.TestCase):
|
||||
for i in range(100):
|
||||
self.assertTrue(complex(random() + 1e-6, random() + 1e-6))
|
||||
self.assertTrue(not complex(0.0, 0.0))
|
||||
self.assertTrue(1j)
|
||||
|
||||
def test_conjugate(self):
|
||||
self.assertClose(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
|
||||
@@ -318,6 +353,8 @@ class ComplexTest(unittest.TestCase):
|
||||
self.assertRaises(TypeError, complex, {})
|
||||
self.assertRaises(TypeError, complex, NS(1.5))
|
||||
self.assertRaises(TypeError, complex, NS(1))
|
||||
self.assertRaises(TypeError, complex, object())
|
||||
self.assertRaises(TypeError, complex, NS(4.25+0.5j), object())
|
||||
|
||||
self.assertAlmostEqual(complex("1+10j"), 1+10j)
|
||||
self.assertAlmostEqual(complex(10), 10+0j)
|
||||
@@ -363,6 +400,8 @@ class ComplexTest(unittest.TestCase):
|
||||
self.assertAlmostEqual(complex('1e-500'), 0.0 + 0.0j)
|
||||
self.assertAlmostEqual(complex('-1e-500j'), 0.0 - 0.0j)
|
||||
self.assertAlmostEqual(complex('-1e-500+1e-500j'), -0.0 + 0.0j)
|
||||
self.assertEqual(complex('1-1j'), 1.0 - 1j)
|
||||
self.assertEqual(complex('1J'), 1j)
|
||||
|
||||
class complex2(complex): pass
|
||||
self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j)
|
||||
@@ -533,6 +572,14 @@ class ComplexTest(unittest.TestCase):
|
||||
self.assertFloatsAreIdentical(z.real, x)
|
||||
self.assertFloatsAreIdentical(z.imag, y)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_constructor_negative_nans_from_string(self):
|
||||
self.assertEqual(copysign(1., complex("-nan").real), -1.)
|
||||
self.assertEqual(copysign(1., complex("-nanj").imag), -1.)
|
||||
self.assertEqual(copysign(1., complex("-nan-nanj").real), -1.)
|
||||
self.assertEqual(copysign(1., complex("-nan-nanj").imag), -1.)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_underscores(self):
|
||||
@@ -553,6 +600,8 @@ class ComplexTest(unittest.TestCase):
|
||||
x /= 3.0 # now check against floating point
|
||||
self.assertEqual(hash(x), hash(complex(x, 0.)))
|
||||
|
||||
self.assertNotEqual(hash(2000005 - 1j), -1)
|
||||
|
||||
def test_abs(self):
|
||||
nums = [complex(x/3., y/7.) for x in range(-9,9) for y in range(-9,9)]
|
||||
for num in nums:
|
||||
@@ -575,6 +624,7 @@ class ComplexTest(unittest.TestCase):
|
||||
test(complex(NAN, 1), "(nan+1j)")
|
||||
test(complex(1, NAN), "(1+nanj)")
|
||||
test(complex(NAN, NAN), "(nan+nanj)")
|
||||
test(complex(-NAN, -NAN), "(nan+nanj)")
|
||||
|
||||
test(complex(0, INF), "infj")
|
||||
test(complex(0, -INF), "-infj")
|
||||
@@ -601,6 +651,14 @@ class ComplexTest(unittest.TestCase):
|
||||
test(complex(-0., 0.), "(-0+0j)")
|
||||
test(complex(-0., -0.), "(-0-0j)")
|
||||
|
||||
def test_pos(self):
|
||||
class ComplexSubclass(complex):
|
||||
pass
|
||||
|
||||
self.assertEqual(+(1+6j), 1+6j)
|
||||
self.assertEqual(+ComplexSubclass(1, 6), 1+6j)
|
||||
self.assertIs(type(+ComplexSubclass(1, 6)), complex)
|
||||
|
||||
def test_neg(self):
|
||||
self.assertEqual(-(1+6j), -1-6j)
|
||||
|
||||
|
||||
Vendored
+2
@@ -6,6 +6,7 @@ import random
|
||||
import time
|
||||
import unittest
|
||||
import weakref
|
||||
from test import support
|
||||
from test.support import threading_helper
|
||||
|
||||
try:
|
||||
@@ -608,6 +609,7 @@ class HamtTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual({k.name for k in h.keys()}, {'C', 'D', 'E'})
|
||||
|
||||
@support.requires_resource('cpu')
|
||||
def test_hamt_stress(self):
|
||||
COLLECTION_SIZE = 7000
|
||||
TEST_ITERS_EVERY = 647
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
from test import support
|
||||
import unittest
|
||||
from types import MethodType
|
||||
|
||||
|
||||
Vendored
-2
@@ -1,9 +1,7 @@
|
||||
"""Unit tests for collections.defaultdict."""
|
||||
|
||||
import os
|
||||
import copy
|
||||
import pickle
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
Vendored
+47
-15
@@ -21,6 +21,11 @@ try:
|
||||
except ImportError:
|
||||
_testcapi = None
|
||||
|
||||
try:
|
||||
import xxsubtype
|
||||
except ImportError:
|
||||
xxsubtype = None
|
||||
|
||||
|
||||
class OperatorsTest(unittest.TestCase):
|
||||
|
||||
@@ -299,6 +304,7 @@ class OperatorsTest(unittest.TestCase):
|
||||
self.assertEqual(float.__rsub__(3.0, 1), -2.0)
|
||||
|
||||
@support.impl_detail("the module 'xxsubtype' is internal")
|
||||
@unittest.skipIf(xxsubtype is None, "requires xxsubtype module")
|
||||
def test_spam_lists(self):
|
||||
# Testing spamlist operations...
|
||||
import copy, xxsubtype as spam
|
||||
@@ -343,6 +349,7 @@ class OperatorsTest(unittest.TestCase):
|
||||
self.assertEqual(a.getstate(), 42)
|
||||
|
||||
@support.impl_detail("the module 'xxsubtype' is internal")
|
||||
@unittest.skipIf(xxsubtype is None, "requires xxsubtype module")
|
||||
def test_spam_dicts(self):
|
||||
# Testing spamdict operations...
|
||||
import copy, xxsubtype as spam
|
||||
@@ -426,7 +433,7 @@ class ClassPropertiesAndMethods(unittest.TestCase):
|
||||
def __getitem__(self, key):
|
||||
return self.get(key, 0)
|
||||
def __setitem__(self_local, key, value):
|
||||
self.assertIsInstance(key, type(0))
|
||||
self.assertIsInstance(key, int)
|
||||
dict.__setitem__(self_local, key, value)
|
||||
def setstate(self, state):
|
||||
self.state = state
|
||||
@@ -842,7 +849,7 @@ class ClassPropertiesAndMethods(unittest.TestCase):
|
||||
("getattr", "foo"),
|
||||
("delattr", "foo")])
|
||||
|
||||
# http://python.org/sf/1174712
|
||||
# https://bugs.python.org/issue1174712
|
||||
try:
|
||||
class Module(types.ModuleType, str):
|
||||
pass
|
||||
@@ -875,7 +882,7 @@ class ClassPropertiesAndMethods(unittest.TestCase):
|
||||
self.assertEqual(a.getstate(), 10)
|
||||
class D(dict, C):
|
||||
def __init__(self):
|
||||
type({}).__init__(self)
|
||||
dict.__init__(self)
|
||||
C.__init__(self)
|
||||
d = D()
|
||||
self.assertEqual(list(d.keys()), [])
|
||||
@@ -1627,6 +1634,7 @@ order (MRO) for bases """
|
||||
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
|
||||
|
||||
@support.impl_detail("the module 'xxsubtype' is internal")
|
||||
@unittest.skipIf(xxsubtype is None, "requires xxsubtype module")
|
||||
def test_classmethods_in_c(self):
|
||||
# Testing C-based class methods...
|
||||
import xxsubtype as spam
|
||||
@@ -1712,6 +1720,7 @@ order (MRO) for bases """
|
||||
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
|
||||
|
||||
@support.impl_detail("the module 'xxsubtype' is internal")
|
||||
@unittest.skipIf(xxsubtype is None, "requires xxsubtype module")
|
||||
def test_staticmethods_in_c(self):
|
||||
# Testing C-based static methods...
|
||||
import xxsubtype as spam
|
||||
@@ -1848,9 +1857,8 @@ order (MRO) for bases """
|
||||
object.__init__(A(3))
|
||||
self.assertRaises(TypeError, object.__init__, A(3), 5)
|
||||
|
||||
# TODO: RUSTPYTHON, CPython 3.5 and above expect this test case to fail, but in RustPython this currently passes.
|
||||
# See https://github.com/python/cpython/issues/49572 for more details.
|
||||
# @unittest.expectedFailure
|
||||
@unittest.expectedFailure
|
||||
@unittest.skip("TODO: RUSTPYTHON")
|
||||
def test_restored_object_new(self):
|
||||
class A(object):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
@@ -2006,7 +2014,7 @@ order (MRO) for bases """
|
||||
ns = {}
|
||||
exec(code, ns)
|
||||
number_attrs = ns["number_attrs"]
|
||||
# Warm up the the function for quickening (PEP 659)
|
||||
# Warm up the function for quickening (PEP 659)
|
||||
for _ in range(30):
|
||||
self.assertEqual(number_attrs(Numbers()), list(range(280)))
|
||||
|
||||
@@ -3298,12 +3306,8 @@ order (MRO) for bases """
|
||||
if otype:
|
||||
otype = otype.__name__
|
||||
return 'object=%s; type=%s' % (object, otype)
|
||||
class OldClass:
|
||||
class NewClass:
|
||||
__doc__ = DocDescr()
|
||||
class NewClass(object):
|
||||
__doc__ = DocDescr()
|
||||
self.assertEqual(OldClass.__doc__, 'object=None; type=OldClass')
|
||||
self.assertEqual(OldClass().__doc__, 'object=OldClass instance; type=OldClass')
|
||||
self.assertEqual(NewClass.__doc__, 'object=None; type=NewClass')
|
||||
self.assertEqual(NewClass().__doc__, 'object=NewClass instance; type=NewClass')
|
||||
|
||||
@@ -3345,7 +3349,7 @@ order (MRO) for bases """
|
||||
cant(True, int)
|
||||
cant(2, bool)
|
||||
o = object()
|
||||
cant(o, type(1))
|
||||
cant(o, int)
|
||||
cant(o, type(None))
|
||||
del o
|
||||
class G(object):
|
||||
@@ -3622,7 +3626,6 @@ order (MRO) for bases """
|
||||
def test_str_of_str_subclass(self):
|
||||
# Testing __str__ defined in subclass of str ...
|
||||
import binascii
|
||||
import io
|
||||
|
||||
class octetstring(str):
|
||||
def __str__(self):
|
||||
@@ -4527,8 +4530,9 @@ order (MRO) for bases """
|
||||
o = Oops()
|
||||
o.whatever = Provoker(o)
|
||||
del o
|
||||
|
||||
|
||||
@unittest.skip("TODO: RUSTPYTHON, rustpython segmentation fault")
|
||||
@support.requires_resource('cpu')
|
||||
def test_wrapper_segfault(self):
|
||||
# SF 927248: deeply nested wrappers could cause stack overflow
|
||||
f = lambda:None
|
||||
@@ -5095,6 +5099,34 @@ order (MRO) for bases """
|
||||
gc.collect()
|
||||
self.assertEqual(Parent.__subclasses__(), [])
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_attr_raise_through_property(self):
|
||||
# test case for gh-103272
|
||||
class A:
|
||||
def __getattr__(self, name):
|
||||
raise ValueError("FOO")
|
||||
|
||||
@property
|
||||
def foo(self):
|
||||
return self.__getattr__("asdf")
|
||||
|
||||
with self.assertRaisesRegex(ValueError, "FOO"):
|
||||
A().foo
|
||||
|
||||
# test case for gh-103551
|
||||
class B:
|
||||
@property
|
||||
def __getattr__(self, name):
|
||||
raise ValueError("FOO")
|
||||
|
||||
@property
|
||||
def foo(self):
|
||||
raise NotImplementedError("BAR")
|
||||
|
||||
with self.assertRaisesRegex(NotImplementedError, "BAR"):
|
||||
B().foo
|
||||
|
||||
|
||||
class DictProxyTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
||||
Vendored
+484
@@ -0,0 +1,484 @@
|
||||
# This contains most of the executable examples from Guido's descr
|
||||
# tutorial, once at
|
||||
#
|
||||
# https://www.python.org/download/releases/2.2.3/descrintro/
|
||||
#
|
||||
# A few examples left implicit in the writeup were fleshed out, a few were
|
||||
# skipped due to lack of interest (e.g., faking super() by hand isn't
|
||||
# of much interest anymore), and a few were fiddled to make the output
|
||||
# deterministic.
|
||||
|
||||
from test.support import sortdict
|
||||
import doctest
|
||||
import unittest
|
||||
|
||||
|
||||
class defaultdict(dict):
|
||||
def __init__(self, default=None):
|
||||
dict.__init__(self)
|
||||
self.default = default
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return dict.__getitem__(self, key)
|
||||
except KeyError:
|
||||
return self.default
|
||||
|
||||
def get(self, key, *args):
|
||||
if not args:
|
||||
args = (self.default,)
|
||||
return dict.get(self, key, *args)
|
||||
|
||||
def merge(self, other):
|
||||
for key in other:
|
||||
if key not in self:
|
||||
self[key] = other[key]
|
||||
|
||||
|
||||
test_1 = """
|
||||
|
||||
Here's the new type at work:
|
||||
|
||||
>>> print(defaultdict) # show our type
|
||||
<class 'test.test_descrtut.defaultdict'>
|
||||
>>> print(type(defaultdict)) # its metatype
|
||||
<class 'type'>
|
||||
>>> a = defaultdict(default=0.0) # create an instance
|
||||
>>> print(a) # show the instance
|
||||
{}
|
||||
>>> print(type(a)) # show its type
|
||||
<class 'test.test_descrtut.defaultdict'>
|
||||
>>> print(a.__class__) # show its class
|
||||
<class 'test.test_descrtut.defaultdict'>
|
||||
>>> print(type(a) is a.__class__) # its type is its class
|
||||
True
|
||||
>>> a[1] = 3.25 # modify the instance
|
||||
>>> print(a) # show the new value
|
||||
{1: 3.25}
|
||||
>>> print(a[1]) # show the new item
|
||||
3.25
|
||||
>>> print(a[0]) # a non-existent item
|
||||
0.0
|
||||
>>> a.merge({1:100, 2:200}) # use a dict method
|
||||
>>> print(sortdict(a)) # show the result
|
||||
{1: 3.25, 2: 200}
|
||||
>>>
|
||||
|
||||
We can also use the new type in contexts where classic only allows "real"
|
||||
dictionaries, such as the locals/globals dictionaries for the exec
|
||||
statement or the built-in function eval():
|
||||
|
||||
>>> print(sorted(a.keys()))
|
||||
[1, 2]
|
||||
>>> a['print'] = print # need the print function here
|
||||
>>> exec("x = 3; print(x)", a)
|
||||
3
|
||||
>>> print(sorted(a.keys(), key=lambda x: (str(type(x)), x)))
|
||||
[1, 2, '__builtins__', 'print', 'x']
|
||||
>>> print(a['x'])
|
||||
3
|
||||
>>>
|
||||
|
||||
Now I'll show that defaultdict instances have dynamic instance variables,
|
||||
just like classic classes:
|
||||
|
||||
>>> a.default = -1
|
||||
>>> print(a["noway"])
|
||||
-1
|
||||
>>> a.default = -1000
|
||||
>>> print(a["noway"])
|
||||
-1000
|
||||
>>> 'default' in dir(a)
|
||||
True
|
||||
>>> a.x1 = 100
|
||||
>>> a.x2 = 200
|
||||
>>> print(a.x1)
|
||||
100
|
||||
>>> d = dir(a)
|
||||
>>> 'default' in d and 'x1' in d and 'x2' in d
|
||||
True
|
||||
>>> print(sortdict(a.__dict__))
|
||||
{'default': -1000, 'x1': 100, 'x2': 200}
|
||||
>>>
|
||||
"""
|
||||
|
||||
class defaultdict2(dict):
|
||||
__slots__ = ['default']
|
||||
|
||||
def __init__(self, default=None):
|
||||
dict.__init__(self)
|
||||
self.default = default
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return dict.__getitem__(self, key)
|
||||
except KeyError:
|
||||
return self.default
|
||||
|
||||
def get(self, key, *args):
|
||||
if not args:
|
||||
args = (self.default,)
|
||||
return dict.get(self, key, *args)
|
||||
|
||||
def merge(self, other):
|
||||
for key in other:
|
||||
if key not in self:
|
||||
self[key] = other[key]
|
||||
|
||||
test_2 = """
|
||||
|
||||
The __slots__ declaration takes a list of instance variables, and reserves
|
||||
space for exactly these in the instance. When __slots__ is used, other
|
||||
instance variables cannot be assigned to:
|
||||
|
||||
>>> a = defaultdict2(default=0.0)
|
||||
>>> a[1]
|
||||
0.0
|
||||
>>> a.default = -1
|
||||
>>> a[1]
|
||||
-1
|
||||
>>> a.x1 = 1
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in ?
|
||||
AttributeError: 'defaultdict2' object has no attribute 'x1'
|
||||
>>>
|
||||
|
||||
"""
|
||||
|
||||
test_3 = """
|
||||
|
||||
Introspecting instances of built-in types
|
||||
|
||||
For instance of built-in types, x.__class__ is now the same as type(x):
|
||||
|
||||
>>> type([])
|
||||
<class 'list'>
|
||||
>>> [].__class__
|
||||
<class 'list'>
|
||||
>>> list
|
||||
<class 'list'>
|
||||
>>> isinstance([], list)
|
||||
True
|
||||
>>> isinstance([], dict)
|
||||
False
|
||||
>>> isinstance([], object)
|
||||
True
|
||||
>>>
|
||||
|
||||
You can get the information from the list type:
|
||||
|
||||
>>> import pprint
|
||||
>>> pprint.pprint(dir(list)) # like list.__dict__.keys(), but sorted
|
||||
['__add__',
|
||||
'__class__',
|
||||
'__class_getitem__',
|
||||
'__contains__',
|
||||
'__delattr__',
|
||||
'__delitem__',
|
||||
'__dir__',
|
||||
'__doc__',
|
||||
'__eq__',
|
||||
'__format__',
|
||||
'__ge__',
|
||||
'__getattribute__',
|
||||
'__getitem__',
|
||||
'__getstate__',
|
||||
'__gt__',
|
||||
'__hash__',
|
||||
'__iadd__',
|
||||
'__imul__',
|
||||
'__init__',
|
||||
'__init_subclass__',
|
||||
'__iter__',
|
||||
'__le__',
|
||||
'__len__',
|
||||
'__lt__',
|
||||
'__mul__',
|
||||
'__ne__',
|
||||
'__new__',
|
||||
'__reduce__',
|
||||
'__reduce_ex__',
|
||||
'__repr__',
|
||||
'__reversed__',
|
||||
'__rmul__',
|
||||
'__setattr__',
|
||||
'__setitem__',
|
||||
'__sizeof__',
|
||||
'__str__',
|
||||
'__subclasshook__',
|
||||
'append',
|
||||
'clear',
|
||||
'copy',
|
||||
'count',
|
||||
'extend',
|
||||
'index',
|
||||
'insert',
|
||||
'pop',
|
||||
'remove',
|
||||
'reverse',
|
||||
'sort']
|
||||
|
||||
The new introspection API gives more information than the old one: in
|
||||
addition to the regular methods, it also shows the methods that are
|
||||
normally invoked through special notations, e.g. __iadd__ (+=), __len__
|
||||
(len), __ne__ (!=). You can invoke any method from this list directly:
|
||||
|
||||
>>> a = ['tic', 'tac']
|
||||
>>> list.__len__(a) # same as len(a)
|
||||
2
|
||||
>>> a.__len__() # ditto
|
||||
2
|
||||
>>> list.append(a, 'toe') # same as a.append('toe')
|
||||
>>> a
|
||||
['tic', 'tac', 'toe']
|
||||
>>>
|
||||
|
||||
This is just like it is for user-defined classes.
|
||||
"""
|
||||
|
||||
test_4 = """
|
||||
|
||||
Static methods and class methods
|
||||
|
||||
The new introspection API makes it possible to add static methods and class
|
||||
methods. Static methods are easy to describe: they behave pretty much like
|
||||
static methods in C++ or Java. Here's an example:
|
||||
|
||||
>>> class C:
|
||||
...
|
||||
... @staticmethod
|
||||
... def foo(x, y):
|
||||
... print("staticmethod", x, y)
|
||||
|
||||
>>> C.foo(1, 2)
|
||||
staticmethod 1 2
|
||||
>>> c = C()
|
||||
>>> c.foo(1, 2)
|
||||
staticmethod 1 2
|
||||
|
||||
Class methods use a similar pattern to declare methods that receive an
|
||||
implicit first argument that is the *class* for which they are invoked.
|
||||
|
||||
>>> class C:
|
||||
... @classmethod
|
||||
... def foo(cls, y):
|
||||
... print("classmethod", cls, y)
|
||||
|
||||
>>> C.foo(1)
|
||||
classmethod <class 'test.test_descrtut.C'> 1
|
||||
>>> c = C()
|
||||
>>> c.foo(1)
|
||||
classmethod <class 'test.test_descrtut.C'> 1
|
||||
|
||||
>>> class D(C):
|
||||
... pass
|
||||
|
||||
>>> D.foo(1)
|
||||
classmethod <class 'test.test_descrtut.D'> 1
|
||||
>>> d = D()
|
||||
>>> d.foo(1)
|
||||
classmethod <class 'test.test_descrtut.D'> 1
|
||||
|
||||
This prints "classmethod __main__.D 1" both times; in other words, the
|
||||
class passed as the first argument of foo() is the class involved in the
|
||||
call, not the class involved in the definition of foo().
|
||||
|
||||
But notice this:
|
||||
|
||||
>>> class E(C):
|
||||
... @classmethod
|
||||
... def foo(cls, y): # override C.foo
|
||||
... print("E.foo() called")
|
||||
... C.foo(y)
|
||||
|
||||
>>> E.foo(1)
|
||||
E.foo() called
|
||||
classmethod <class 'test.test_descrtut.C'> 1
|
||||
>>> e = E()
|
||||
>>> e.foo(1)
|
||||
E.foo() called
|
||||
classmethod <class 'test.test_descrtut.C'> 1
|
||||
|
||||
In this example, the call to C.foo() from E.foo() will see class C as its
|
||||
first argument, not class E. This is to be expected, since the call
|
||||
specifies the class C. But it stresses the difference between these class
|
||||
methods and methods defined in metaclasses (where an upcall to a metamethod
|
||||
would pass the target class as an explicit first argument).
|
||||
"""
|
||||
|
||||
test_5 = """
|
||||
|
||||
Attributes defined by get/set methods
|
||||
|
||||
|
||||
>>> class property(object):
|
||||
...
|
||||
... def __init__(self, get, set=None):
|
||||
... self.__get = get
|
||||
... self.__set = set
|
||||
...
|
||||
... def __get__(self, inst, type=None):
|
||||
... return self.__get(inst)
|
||||
...
|
||||
... def __set__(self, inst, value):
|
||||
... if self.__set is None:
|
||||
... raise AttributeError("this attribute is read-only")
|
||||
... return self.__set(inst, value)
|
||||
|
||||
Now let's define a class with an attribute x defined by a pair of methods,
|
||||
getx() and setx():
|
||||
|
||||
>>> class C(object):
|
||||
...
|
||||
... def __init__(self):
|
||||
... self.__x = 0
|
||||
...
|
||||
... def getx(self):
|
||||
... return self.__x
|
||||
...
|
||||
... def setx(self, x):
|
||||
... if x < 0: x = 0
|
||||
... self.__x = x
|
||||
...
|
||||
... x = property(getx, setx)
|
||||
|
||||
Here's a small demonstration:
|
||||
|
||||
>>> a = C()
|
||||
>>> a.x = 10
|
||||
>>> print(a.x)
|
||||
10
|
||||
>>> a.x = -10
|
||||
>>> print(a.x)
|
||||
0
|
||||
>>>
|
||||
|
||||
Hmm -- property is builtin now, so let's try it that way too.
|
||||
|
||||
>>> del property # unmask the builtin
|
||||
>>> property
|
||||
<class 'property'>
|
||||
|
||||
>>> class C(object):
|
||||
... def __init__(self):
|
||||
... self.__x = 0
|
||||
... def getx(self):
|
||||
... return self.__x
|
||||
... def setx(self, x):
|
||||
... if x < 0: x = 0
|
||||
... self.__x = x
|
||||
... x = property(getx, setx)
|
||||
|
||||
|
||||
>>> a = C()
|
||||
>>> a.x = 10
|
||||
>>> print(a.x)
|
||||
10
|
||||
>>> a.x = -10
|
||||
>>> print(a.x)
|
||||
0
|
||||
>>>
|
||||
"""
|
||||
|
||||
test_6 = """
|
||||
|
||||
Method resolution order
|
||||
|
||||
This example is implicit in the writeup.
|
||||
|
||||
>>> class A: # implicit new-style class
|
||||
... def save(self):
|
||||
... print("called A.save()")
|
||||
>>> class B(A):
|
||||
... pass
|
||||
>>> class C(A):
|
||||
... def save(self):
|
||||
... print("called C.save()")
|
||||
>>> class D(B, C):
|
||||
... pass
|
||||
|
||||
>>> D().save()
|
||||
called C.save()
|
||||
|
||||
>>> class A(object): # explicit new-style class
|
||||
... def save(self):
|
||||
... print("called A.save()")
|
||||
>>> class B(A):
|
||||
... pass
|
||||
>>> class C(A):
|
||||
... def save(self):
|
||||
... print("called C.save()")
|
||||
>>> class D(B, C):
|
||||
... pass
|
||||
|
||||
>>> D().save()
|
||||
called C.save()
|
||||
"""
|
||||
|
||||
class A(object):
|
||||
def m(self):
|
||||
return "A"
|
||||
|
||||
class B(A):
|
||||
def m(self):
|
||||
return "B" + super(B, self).m()
|
||||
|
||||
class C(A):
|
||||
def m(self):
|
||||
return "C" + super(C, self).m()
|
||||
|
||||
class D(C, B):
|
||||
def m(self):
|
||||
return "D" + super(D, self).m()
|
||||
|
||||
|
||||
test_7 = """
|
||||
|
||||
Cooperative methods and "super"
|
||||
|
||||
>>> print(D().m()) # "DCBA"
|
||||
DCBA
|
||||
"""
|
||||
|
||||
test_8 = """
|
||||
|
||||
Backwards incompatibilities
|
||||
|
||||
>>> class A:
|
||||
... def foo(self):
|
||||
... print("called A.foo()")
|
||||
|
||||
>>> class B(A):
|
||||
... pass
|
||||
|
||||
>>> class C(A):
|
||||
... def foo(self):
|
||||
... B.foo(self)
|
||||
|
||||
>>> C().foo()
|
||||
called A.foo()
|
||||
|
||||
>>> class C(A):
|
||||
... def foo(self):
|
||||
... A.foo(self)
|
||||
>>> C().foo()
|
||||
called A.foo()
|
||||
"""
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
__test__ = {# "tut1": test_1,
|
||||
# "tut2": test_2,
|
||||
# "tut3": test_3,
|
||||
# "tut4": test_4,
|
||||
"tut5": test_5,
|
||||
"tut6": test_6,
|
||||
"tut7": test_7,
|
||||
"tut8": test_8}
|
||||
|
||||
def load_tests(loader, tests, pattern):
|
||||
tests.addTest(doctest.DocTestSuite())
|
||||
return tests
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Vendored
+17
-2
@@ -8,7 +8,7 @@ import sys
|
||||
import unittest
|
||||
import weakref
|
||||
from test import support
|
||||
from test.support import import_helper
|
||||
from test.support import import_helper, C_RECURSION_LIMIT
|
||||
|
||||
|
||||
class DictTest(unittest.TestCase):
|
||||
@@ -599,7 +599,7 @@ class DictTest(unittest.TestCase):
|
||||
@unittest.skipIf(sys.platform == 'win32', 'TODO: RUSTPYTHON Windows')
|
||||
def test_repr_deep(self):
|
||||
d = {}
|
||||
for i in range(sys.getrecursionlimit() + 100):
|
||||
for i in range(C_RECURSION_LIMIT + 1):
|
||||
d = {1: d}
|
||||
self.assertRaises(RecursionError, repr, d)
|
||||
|
||||
@@ -1099,6 +1099,21 @@ class DictTest(unittest.TestCase):
|
||||
d.update(o.__dict__)
|
||||
self.assertEqual(list(d), ["c", "b", "a"])
|
||||
|
||||
@support.cpython_only
|
||||
def test_splittable_to_generic_combinedtable(self):
|
||||
"""split table must be correctly resized and converted to generic combined table"""
|
||||
class C:
|
||||
pass
|
||||
|
||||
a = C()
|
||||
a.x = 1
|
||||
d = a.__dict__
|
||||
before_resize = sys.getsizeof(d)
|
||||
d[2] = 2 # split table is resized to a generic combined table
|
||||
|
||||
self.assertGreater(sys.getsizeof(d), before_resize)
|
||||
self.assertEqual(list(d), ['x', 2])
|
||||
|
||||
def test_iterator_pickling(self):
|
||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||
data = {1:"a", 2:"b", 3:"c"}
|
||||
|
||||
Vendored
+22
-1
@@ -3,6 +3,7 @@ import copy
|
||||
import pickle
|
||||
import sys
|
||||
import unittest
|
||||
from test.support import C_RECURSION_LIMIT
|
||||
|
||||
class DictSetTest(unittest.TestCase):
|
||||
|
||||
@@ -170,6 +171,10 @@ class DictSetTest(unittest.TestCase):
|
||||
{('a', 1), ('b', 2)})
|
||||
self.assertEqual(d1.items() & set(d2.items()), {('b', 2)})
|
||||
self.assertEqual(d1.items() & set(d3.items()), set())
|
||||
self.assertEqual(d1.items() & (("a", 1), ("b", 2)),
|
||||
{('a', 1), ('b', 2)})
|
||||
self.assertEqual(d1.items() & (("a", 2), ("b", 2)), {('b', 2)})
|
||||
self.assertEqual(d1.items() & (("d", 4), ("e", 5)), set())
|
||||
|
||||
self.assertEqual(d1.items() | d1.items(),
|
||||
{('a', 1), ('b', 2)})
|
||||
@@ -183,12 +188,23 @@ class DictSetTest(unittest.TestCase):
|
||||
{('a', 1), ('a', 2), ('b', 2)})
|
||||
self.assertEqual(d1.items() | set(d3.items()),
|
||||
{('a', 1), ('b', 2), ('d', 4), ('e', 5)})
|
||||
self.assertEqual(d1.items() | (('a', 1), ('b', 2)),
|
||||
{('a', 1), ('b', 2)})
|
||||
self.assertEqual(d1.items() | (('a', 2), ('b', 2)),
|
||||
{('a', 1), ('a', 2), ('b', 2)})
|
||||
self.assertEqual(d1.items() | (('d', 4), ('e', 5)),
|
||||
{('a', 1), ('b', 2), ('d', 4), ('e', 5)})
|
||||
|
||||
self.assertEqual(d1.items() ^ d1.items(), set())
|
||||
self.assertEqual(d1.items() ^ d2.items(),
|
||||
{('a', 1), ('a', 2)})
|
||||
self.assertEqual(d1.items() ^ d3.items(),
|
||||
{('a', 1), ('b', 2), ('d', 4), ('e', 5)})
|
||||
self.assertEqual(d1.items() ^ (('a', 1), ('b', 2)), set())
|
||||
self.assertEqual(d1.items() ^ (("a", 2), ("b", 2)),
|
||||
{('a', 1), ('a', 2)})
|
||||
self.assertEqual(d1.items() ^ (("d", 4), ("e", 5)),
|
||||
{('a', 1), ('b', 2), ('d', 4), ('e', 5)})
|
||||
|
||||
self.assertEqual(d1.items() - d1.items(), set())
|
||||
self.assertEqual(d1.items() - d2.items(), {('a', 1)})
|
||||
@@ -196,6 +212,9 @@ class DictSetTest(unittest.TestCase):
|
||||
self.assertEqual(d1.items() - set(d1.items()), set())
|
||||
self.assertEqual(d1.items() - set(d2.items()), {('a', 1)})
|
||||
self.assertEqual(d1.items() - set(d3.items()), {('a', 1), ('b', 2)})
|
||||
self.assertEqual(d1.items() - (('a', 1), ('b', 2)), set())
|
||||
self.assertEqual(d1.items() - (("a", 2), ("b", 2)), {('a', 1)})
|
||||
self.assertEqual(d1.items() - (("d", 4), ("e", 5)), {('a', 1), ('b', 2)})
|
||||
|
||||
self.assertFalse(d1.items().isdisjoint(d1.items()))
|
||||
self.assertFalse(d1.items().isdisjoint(d2.items()))
|
||||
@@ -259,9 +278,11 @@ class DictSetTest(unittest.TestCase):
|
||||
# Again.
|
||||
self.assertIsInstance(r, str)
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
def test_deeply_nested_repr(self):
|
||||
d = {}
|
||||
for i in range(sys.getrecursionlimit() + 100):
|
||||
for i in range(C_RECURSION_LIMIT//2 + 100):
|
||||
d = {42: d.values()}
|
||||
self.assertRaises(RecursionError, repr, d)
|
||||
|
||||
|
||||
Vendored
+82
@@ -3,6 +3,7 @@ import os.path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import types
|
||||
import unittest
|
||||
|
||||
@@ -173,6 +174,87 @@ class SystemTapOptimizedTests(TraceTests, unittest.TestCase):
|
||||
backend = SystemTapBackend()
|
||||
optimize_python = 2
|
||||
|
||||
class CheckDtraceProbes(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if sysconfig.get_config_var('WITH_DTRACE'):
|
||||
readelf_major_version, readelf_minor_version = cls.get_readelf_version()
|
||||
if support.verbose:
|
||||
print(f"readelf version: {readelf_major_version}.{readelf_minor_version}")
|
||||
else:
|
||||
raise unittest.SkipTest("CPython must be configured with the --with-dtrace option.")
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_readelf_version():
|
||||
try:
|
||||
cmd = ["readelf", "--version"]
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True,
|
||||
)
|
||||
with proc:
|
||||
version, stderr = proc.communicate()
|
||||
|
||||
if proc.returncode:
|
||||
raise Exception(
|
||||
f"Command {' '.join(cmd)!r} failed "
|
||||
f"with exit code {proc.returncode}: "
|
||||
f"stdout={version!r} stderr={stderr!r}"
|
||||
)
|
||||
except OSError:
|
||||
raise unittest.SkipTest("Couldn't find readelf on the path")
|
||||
|
||||
# Regex to parse:
|
||||
# 'GNU readelf (GNU Binutils) 2.40.0\n' -> 2.40
|
||||
match = re.search(r"^(?:GNU) readelf.*?\b(\d+)\.(\d+)", version)
|
||||
if match is None:
|
||||
raise unittest.SkipTest(f"Unable to parse readelf version: {version}")
|
||||
|
||||
return int(match.group(1)), int(match.group(2))
|
||||
|
||||
def get_readelf_output(self):
|
||||
command = ["readelf", "-n", sys.executable]
|
||||
stdout, _ = subprocess.Popen(
|
||||
command,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
).communicate()
|
||||
return stdout
|
||||
|
||||
def test_check_probes(self):
|
||||
readelf_output = self.get_readelf_output()
|
||||
|
||||
available_probe_names = [
|
||||
"Name: import__find__load__done",
|
||||
"Name: import__find__load__start",
|
||||
"Name: audit",
|
||||
"Name: gc__start",
|
||||
"Name: gc__done",
|
||||
]
|
||||
|
||||
for probe_name in available_probe_names:
|
||||
with self.subTest(probe_name=probe_name):
|
||||
self.assertIn(probe_name, readelf_output)
|
||||
|
||||
@unittest.expectedFailure
|
||||
def test_missing_probes(self):
|
||||
readelf_output = self.get_readelf_output()
|
||||
|
||||
# Missing probes will be added in the future.
|
||||
missing_probe_names = [
|
||||
"Name: function__entry",
|
||||
"Name: function__return",
|
||||
"Name: line",
|
||||
]
|
||||
|
||||
for probe_name in missing_probe_names:
|
||||
with self.subTest(probe_name=probe_name):
|
||||
self.assertIn(probe_name, readelf_output)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Vendored
+7
-5
@@ -142,12 +142,14 @@ class RebindBuiltinsTests(unittest.TestCase):
|
||||
def __missing__(self, key):
|
||||
return int(key.removeprefix("_number_"))
|
||||
|
||||
code = "lambda: " + "+".join(f"_number_{i}" for i in range(1000))
|
||||
sum_1000 = eval(code, MyGlobals())
|
||||
expected = sum(range(1000))
|
||||
# Warm up the the function for quickening (PEP 659)
|
||||
# Need more than 256 variables to use EXTENDED_ARGS
|
||||
variables = 400
|
||||
code = "lambda: " + "+".join(f"_number_{i}" for i in range(variables))
|
||||
sum_func = eval(code, MyGlobals())
|
||||
expected = sum(range(variables))
|
||||
# Warm up the function for quickening (PEP 659)
|
||||
for _ in range(30):
|
||||
self.assertEqual(sum_1000(), expected)
|
||||
self.assertEqual(sum_func(), expected)
|
||||
|
||||
|
||||
class TestTracing(unittest.TestCase):
|
||||
|
||||
Vendored
+1
@@ -9,6 +9,7 @@ from test.support import script_helper
|
||||
class EINTRTests(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
|
||||
@support.requires_resource('walltime')
|
||||
def test_all(self):
|
||||
# Run the tester in a sub-process, to make sure there is only one
|
||||
# thread (for reliable signal delivery).
|
||||
|
||||
Vendored
+3
-1
@@ -4,6 +4,7 @@ import sys
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
from test.support import script_helper
|
||||
from test.support import warnings_helper
|
||||
import unittest
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@@ -38,10 +39,11 @@ class EOFTestCase(unittest.TestCase):
|
||||
rc, out, err = script_helper.assert_python_failure(file_name)
|
||||
self.assertIn(b'unterminated triple-quoted string literal (detected at line 3)', err)
|
||||
|
||||
@warnings_helper.ignore_warnings(category=SyntaxWarning)
|
||||
def test_eof_with_line_continuation(self):
|
||||
expect = "unexpected EOF while parsing (<string>, line 1)"
|
||||
try:
|
||||
compile('"\\xhh" \\', '<string>', 'exec', dont_inherit=True)
|
||||
compile('"\\Xhh" \\', '<string>', 'exec')
|
||||
except SyntaxError as msg:
|
||||
self.assertEqual(str(msg), expect)
|
||||
else:
|
||||
|
||||
Vendored
+11
-4
@@ -27,6 +27,7 @@ import select
|
||||
import socket
|
||||
import time
|
||||
import unittest
|
||||
from test import support
|
||||
|
||||
if not hasattr(select, "epoll"):
|
||||
raise unittest.SkipTest("test works only on Linux 2.6")
|
||||
@@ -186,10 +187,16 @@ class TestEPoll(unittest.TestCase):
|
||||
client.sendall(b"Hello!")
|
||||
server.sendall(b"world!!!")
|
||||
|
||||
now = time.monotonic()
|
||||
events = ep.poll(1.0, 4)
|
||||
then = time.monotonic()
|
||||
self.assertFalse(then - now > 0.01)
|
||||
# we might receive events one at a time, necessitating multiple calls to
|
||||
# poll
|
||||
events = []
|
||||
for _ in support.busy_retry(support.SHORT_TIMEOUT):
|
||||
now = time.monotonic()
|
||||
events += ep.poll(1.0, 4)
|
||||
then = time.monotonic()
|
||||
self.assertFalse(then - now > 0.01)
|
||||
if len(events) >= 2:
|
||||
break
|
||||
|
||||
expected = [(client.fileno(), select.EPOLLIN | select.EPOLLOUT),
|
||||
(server.fileno(), select.EPOLLIN | select.EPOLLOUT)]
|
||||
|
||||
Reference in new issue
Block a user