Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Lib/test/test_asyncio/test_sendfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,12 @@ class SendfileBase:
# 64 KiB page configuration.
DATA = b"x" * (1024 * 17 * 64 + 1)
# Reduce socket buffer size to test on relative small data sets.
BUF_SIZE = 4 * 1024 # 4 KiB
if sys.platform.startswith('dragonfly'):
# A smaller buffer makes every window update wait 100 ms for the
# delayed ACK timer.
BUF_SIZE = 32 * 1024 # 32 KiB
else:
BUF_SIZE = 4 * 1024 # 4 KiB

def create_event_loop(self):
raise NotImplementedError
Expand Down
85 changes: 75 additions & 10 deletions Lib/test/test_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
'?':0, 'c':0, 'b':0, 'B':0,
'h':0, 'H':0, 'i':0, 'I':0,
'l':0, 'L':0, 'n':0, 'N':0,
'e':0, 'f':0, 'd':0, 'P':0
'e':0, 'f':0, 'd':0, 'P':0,
'Zf':0, 'Zd':0,
}

# NumPy does not have 'n' or 'N':
Expand All @@ -92,7 +93,9 @@
'l':(-(1<<31), 1<<31), 'L':(0, 1<<32),
'q':(-(1<<63), 1<<63), 'Q':(0, 1<<64),
'e':(-65519, 65520), 'f':(-(1<<63), 1<<63),
'd':(-(1<<1023), 1<<1023)
'd':(-(1<<1023), 1<<1023),
'Zf':(-(1<<63), 1<<63),
'Zd':(-(1<<1023), 1<<1023),
}

def native_type_range(fmt):
Expand All @@ -107,6 +110,10 @@ def native_type_range(fmt):
lh = (-(1<<63), 1<<63)
elif fmt == 'd':
lh = (-(1<<1023), 1<<1023)
elif fmt == 'Zf':
lh = (-(1<<63), 1<<63)
elif fmt == 'Zd':
lh = (-(1<<1023), 1<<1023)
else:
for exp in (128, 127, 64, 63, 32, 31, 16, 15, 8, 7):
try:
Expand Down Expand Up @@ -136,7 +143,7 @@ def native_type_range(fmt):
# Format codes supported by array.array
ARRAY = NATIVE.copy()
for k in NATIVE:
if not k in "bBhHiIlLfd":
if k not in list("bBhHiIlLefd") + ['Zf', 'Zd']:
del ARRAY[k]

BYTEFMT = NATIVE.copy()
Expand Down Expand Up @@ -175,13 +182,28 @@ def randrange_fmt(mode, char, obj):
if char in 'efd':
x = struct.pack(char, x)
x = struct.unpack(char, x)[0]
if char in ('Zf', 'Zd'):
y = randrange(*fmtdict[mode][char])
x = complex(x, y)
x = struct.pack(char, x)
x = struct.unpack(char, x)[0]
return x

def split_format(fmt):
i = 0
while i < len(fmt):
if fmt[i] == 'Z':
n = 2
else:
n = 1
yield fmt[i:i + n]
i += n

def gen_item(fmt, obj):
"""Return single random item."""
mode, chars = fmt.split('#')
x = []
for c in chars:
for c in split_format(chars):
x.append(randrange_fmt(mode, c, obj))
return x[0] if len(x) == 1 else tuple(x)

Expand Down Expand Up @@ -242,9 +264,7 @@ def is_byte_format(fmt):

def is_memoryview_format(fmt):
"""format suitable for memoryview"""
x = len(fmt)
return ((x == 1 or (x == 2 and fmt[0] == '@')) and
fmt[x-1] in MEMORYVIEW)
return fmt.removeprefix('@') in MEMORYVIEW

NON_BYTE_FORMAT = [c for c in fmtdict['@'] if not is_byte_format(c)]

Expand Down Expand Up @@ -636,14 +656,22 @@ def ndarray_from_structure(items, fmt, t, flags=0):
return ndarray(items, shape=shape, strides=strides, format=fmt,
offset=offset, flags=ND_WRITABLE|flags)

# Convert PEP 3118 formats to numpy dtypes
FORMAT_TO_DTYPE = {
'Zf': 'F',
'Zd': 'D',
}

def numpy_array_from_structure(items, fmt, t):
"""Return numpy_array from the tuple returned by rand_structure()"""
memlen, itemsize, ndim, shape, strides, offset = t
buf = bytearray(memlen)
for j, v in enumerate(items):
struct.pack_into(fmt, buf, j*itemsize, v)
# Replace Zd/Zf formats with D/F dtypes
dtype = FORMAT_TO_DTYPE.get(fmt, fmt)
return numpy_array(buffer=buf, shape=shape, strides=strides,
dtype=fmt, offset=offset)
dtype=dtype, offset=offset)


# ======================================================================
Expand Down Expand Up @@ -3015,7 +3043,7 @@ def test_memoryview_assign(self):
m = memoryview(nd)
self.assertRaises(TypeError, m.__setitem__, 0, 100)

ex = ndarray(list(range(120)), shape=[1,2,3,4,5], flags=ND_WRITABLE)
ex = ndarray(list(range(144)), shape=[1,2,3,4,6], flags=ND_WRITABLE)
m1 = memoryview(ex)

for fmt, _range in fmtdict['@'].items():
Expand All @@ -3025,7 +3053,7 @@ def test_memoryview_assign(self):
continue
m2 = m1.cast(fmt)
lo, hi = _range
if fmt == 'd' or fmt == 'f':
if fmt in ("d", "f", "Zd", "Zf"):
lo, hi = -2**1024, 2**1024
if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers
self.assertRaises(ValueError, m2.__setitem__, 0, lo-1)
Expand Down Expand Up @@ -4447,6 +4475,43 @@ def test_bytearray_release_buffer_read_flag(self):
with self.assertRaises(SystemError):
obj.__buffer__(inspect.BufferFlags.WRITE)

@support.cpython_only
@unittest.skipIf(_testcapi is None, "requires _testcapi")
def test_bytearray_alignment(self):
# gh-140557: pointer alignment of buffers including empty allocation
# should be at least to `size_t`.
align = struct.calcsize("N")
cases = [
bytearray(),
bytearray(1),
bytearray(b"0123456789abcdef"),
bytearray(16),
]
ptrs = [_testcapi.buffer_pointer_as_int(array) for array in cases]
self.assertEqual([ptr % align for ptr in ptrs], [0]*len(ptrs))

@support.cpython_only
@unittest.skipIf(_testcapi is None, "requires _testcapi")
def test_array_alignment(self):
# gh-140557: pointer alignment of buffers including empty allocation
# should match the maximum array alignment.
formats = [fmt for fmt in ARRAY
if struct.calcsize(fmt) <= struct.calcsize('P')]
align = max(struct.calcsize(fmt) for fmt in formats)
cases = [array.array(fmt) for fmt in formats]
# Empty arrays
self.assertEqual(
[_testcapi.buffer_pointer_as_int(case) % align for case in cases],
[0] * len(cases),
)
for case in cases:
case.append(0)
# Allocated arrays
self.assertEqual(
[_testcapi.buffer_pointer_as_int(case) % align for case in cases],
[0] * len(cases),
)

@support.cpython_only
def test_pybuffer_size_from_format(self):
# basic tests
Expand Down
57 changes: 53 additions & 4 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set_recursion_limit, skip_on_s390x,
skip_emscripten_stack_overflow,
skip_wasi_stack_overflow, skip_if_sanitizer,
import_helper)
skip_if_huge_c_stack, import_helper)
try:
import _testcapi
except ImportError:
Expand Down Expand Up @@ -47,6 +47,54 @@ def fn(**kw):
self.assertIsInstance(res, dict)
self.assertEqual(list(res.items()), expected)

def test_kwargs_order_preserved(self):
# PEP 468: Preserving Keyword Argument Order
def fn(**kw):
return list(kw)

self.assertEqual(fn(b=1, a=2, c=3), ['b', 'a', 'c'])
self.assertEqual(fn(c=3, a=2, b=1), ['c', 'a', 'b'])
# Unpacked mappings are merged in place, keeping their own order.
self.assertEqual(fn(z=0, **{'x': 1, 'a': 2}, y=3),
['z', 'x', 'a', 'y'])
self.assertEqual(fn(**{'b': 1}, **{'a': 2}), ['b', 'a'])
# Named parameters are removed from **kwargs without reordering
# the rest.
def fn2(a, c=None, **kw):
return list(kw)

self.assertEqual(fn2(d=1, a=2, b=3, c=4, e=5), ['d', 'b', 'e'])

def test_kwargs_order_preserved_in_methods(self):
# PEP 468: Preserving Keyword Argument Order
class C:
def __init__(self, **kw):
self.init_kw = list(kw)

def meth(self, **kw):
return list(kw)

@classmethod
def cmeth(cls, **kw):
return list(kw)

@staticmethod
def smeth(**kw):
return list(kw)

c = C(b=1, a=2, c=3)
self.assertEqual(c.init_kw, ['b', 'a', 'c'])
self.assertEqual(c.meth(b=1, a=2, c=3), ['b', 'a', 'c'])
self.assertEqual(C.cmeth(b=1, a=2, c=3), ['b', 'a', 'c'])
self.assertEqual(C.smeth(b=1, a=2, c=3), ['b', 'a', 'c'])

def test_kwargs_order_preserved_in_c_functions(self):
# PEP 468: Preserving Keyword Argument Order
self.assertEqual(list(dict(b=1, a=2, c=3)), ['b', 'a', 'c'])
self.assertEqual(list(dict(**{'b': 1}, a=2)), ['b', 'a'])
self.assertEqual(list(collections.OrderedDict(b=1, a=2, c=3)),
['b', 'a', 'c'])

def test_frames_are_popped_after_failed_calls(self):
# GH-93252: stuff blows up if we don't pop the new frame after
# recovering from failed calls:
Expand Down Expand Up @@ -1052,16 +1100,17 @@ def get_sp():
self.assertLess(lower_sp, this_sp)
safe_margin = this_sp - lower_sp
else:
self.assertLess(this_sp, lower_sp)
self.assertGreater(lower_sp, this_sp)
safe_margin = lower_sp - this_sp
# Add an (arbitrary) extra 20% for safety
safe_margin *= 6 / 5
# Add an (arbitrary) extra 25% for safety
safe_margin = safe_margin * 5 / 4
self.assertLess(safe_margin, _testinternalcapi.get_stack_margin())

@skip_on_s390x
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
@skip_if_sanitizer("requires deep stack", thread=True)
@unittest.skipIf(_testcapi is None, "requires _testcapi")
@skip_if_huge_c_stack(90_000)
@skip_emscripten_stack_overflow()
@skip_wasi_stack_overflow()
def test_super_deep(self):
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_future_stmt/test_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ def test_annotations(self):
eq("(i ** 2 + j for i in (1, 2, 3) for j in (1, 2, 3))")
eq("{i: 0 for i in (1, 2, 3)}")
eq("{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}")
eq("{**x for x in ()}")
eq("[*x for x in ()]")
eq("[(x, y) for x, y in (a, b)]")
eq("[(x,) for x, in (a,)]")
eq("Python3 > Python2 > COBOL")
Expand Down
Loading