Skip to content
Open
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
15 changes: 15 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3227,3 +3227,18 @@ def control_characters_c0() -> list[str]:
C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
"""
return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]


STATUS_DLL_INIT_FAILED = 0xC0000142
def skip_on_low_desktop_heap_memory_subprocess(returncode):
if sys.platform not in ('win32', 'cygwin'):
return
# On Windows, STATUS_DLL_INIT_FAILED is a generic error code that could
# come from any of the DLLs being loaded when a new Python process is
# created. In practice, it's likely a memory allocation failure in the
# desktop heap memory which caused the DLL init failure, especially on
# process created with CREATE_NEW_CONSOLE creation flag. See the article:
# https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
if returncode == STATUS_DLL_INIT_FAILED:
raise unittest.SkipTest('gh-150436: DLL init failed, likely because '
'of low desktop heap memory')
7 changes: 2 additions & 5 deletions Lib/test/test_bytes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2622,10 +2622,6 @@ def iconcat(b, a): # MODIFIES!
b.wait()
a += c

def irepeat(b, a): # MODIFIES!
b.wait()
a *= 2

def subscript(b, a):
b.wait()
try: assert a[0] != 0xdd
Expand Down Expand Up @@ -2747,9 +2743,10 @@ def check(funcs, a=None, *args):

check([clear] + [repeat] * 10)
check([clear] + [iconcat] * 10)
check([clear] + [irepeat] * 10)
check([clear] + [ass_subscript] * 10)
check([clear] + [repr_] * 10)
# gh-148605: Do not test "a *= 2" since it allocates up to 4 GiB using
# 10 threads

# value errors

Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_bz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,22 @@ def test_failure(self):
# Previously, a second call could crash due to internal inconsistency
self.assertRaises(Exception, bzd.decompress, self.BAD_DATA * 30)

@unittest.expectedFailure # TODO: RUSTPYTHON; Wrong error message
def test_decompress_after_data_error(self):
data = bytes.fromhex(
"425a6839314159265359000000000000007fffff000000000000000000000000"
"00000000000000000000000000000000000000e0370000000000000000000000"
"000000000000000000000000000000000000000000000000000083f3"
)
bzd = BZ2Decompressor()
with self.assertRaisesRegex(OSError, "Invalid data stream"):
bzd.decompress(data)
# Previously, a second call could crash due to internal inconsistency
self.assertFalse(bzd.needs_input)
self.assertFalse(bzd.eof)
with self.assertRaisesRegex(ValueError, "previous error"):
bzd.decompress(b'\x00' * 18)

@support.refcount_test
def test_refleaks_in___init__(self):
gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount')
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_cmd_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ def test_python_legacy_windows_stdio(self):
p = subprocess.run([sys.executable, "-c", code],
creationflags=subprocess.CREATE_NEW_CONSOLE,
env=env)
support.skip_on_low_desktop_heap_memory_subprocess(p.returncode)
self.assertEqual(p.returncode, 0)

# Then test that FIleIO is used when PYTHONLEGACYWINDOWSSTDIO is set.
Expand All @@ -1022,6 +1023,7 @@ def test_python_legacy_windows_stdio(self):
p = subprocess.run([sys.executable, "-c", code],
creationflags=subprocess.CREATE_NEW_CONSOLE,
env=env)
support.skip_on_low_desktop_heap_memory_subprocess(p.returncode)
self.assertEqual(p.returncode, 0)

@unittest.expectedFailure # TODO: RUSTPYTHON
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_deque.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,22 @@ def test_index(self):
else:
self.assertEqual(d.index(element, start, stop), target)

# Test stop argument
for elem in d:
index = d.index(elem)
self.assertEqual(
index,
d.index(elem, 0),
)
self.assertEqual(
index,
d.index(elem, 0, len(d)),
)
self.assertEqual(
index,
d.index(elem, 0, len(d) + 100),
)

# Test large start argument
d = deque(range(0, 10000, 10))
for step in range(100):
Expand Down
13 changes: 10 additions & 3 deletions Lib/test/test_genericalias.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,14 @@
from unittest.case import _AssertRaisesContext
from queue import Queue, SimpleQueue
from weakref import WeakSet, ReferenceType, ref
import typing
from typing import Unpack
try:
from tkinter import Event
except ImportError:
Event = None
from string.templatelib import Template, Interpolation

from typing import TypeVar
import typing
from typing import TypeVar, Unpack
T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')
Expand Down Expand Up @@ -619,6 +618,14 @@ def test_nested_paramspec_specialization(self):
self.assertEqual(deeply_nested_specialized.__args__, ([str, [float], int], float))
self.assertEqual(deeply_nested_specialized.__parameters__, ())

def test_gh150146(self):
# It used to crash:
for container in [memoryview, list, tuple]:
with self.subTest(container=container):
x = container[TypeVar("")]
with self.assertRaises(TypeError):
x[*typing.Mapping[..., ...]]


class TypeIterationTests(unittest.TestCase):
_UNITERABLE_TYPES = (list, tuple)
Expand Down
91 changes: 42 additions & 49 deletions Lib/test/test_grp.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Test script for the grp module."""

import random
import string
import unittest
from test.support import import_helper

Expand Down Expand Up @@ -47,64 +49,55 @@ def test_values_extended(self):
# Discovered on Ubuntu 5.04 (custom).
self.assertEqual(e2.gr_name.lower(), name.lower())

@unittest.expectedFailure # TODO: RUSTPYTHON; KeyError: 'getgrgid: group id 340282366920938463463374607431768211456 not found'
def test_errors(self):
self.assertRaises(TypeError, grp.getgrgid)
self.assertRaises(TypeError, grp.getgrgid, 3.14)
self.assertRaises(TypeError, grp.getgrgid, 0.0)
self.assertRaises(TypeError, grp.getgrgid, 0, 0)
# should be out of gid_t range
self.assertRaises(OverflowError, grp.getgrgid, 2**128)
self.assertRaises(OverflowError, grp.getgrgid, -2**128)
self.assertRaises(TypeError, grp.getgrnam)
self.assertRaises(TypeError, grp.getgrnam, 42)
self.assertRaises(TypeError, grp.getgrall, 42)
self.assertRaises(TypeError, grp.getgrnam, b'root')
self.assertRaises(TypeError, grp.getgrnam, 'root', 0)
# embedded null character
self.assertRaisesRegex(ValueError, 'null', grp.getgrnam, 'a\x00b')
self.assertRaisesRegex(ValueError, 'null', grp.getgrnam, 'root\x00')
self.assertRaises(UnicodeEncodeError, grp.getgrnam, 'roo\udc74')
self.assertRaises(KeyError, grp.getgrnam, '')
self.assertRaises(TypeError, grp.getgrall, 42)

# try to get some errors
bynames = {}
bygids = {}
for (n, p, g, mem) in grp.getgrall():
if not n or n == '+':
continue # skip NIS entries etc.
bynames[n] = g
bygids[g] = n

allnames = list(bynames.keys())
namei = 0
fakename = allnames[namei]
while fakename in bynames:
chars = list(fakename)
for i in range(len(chars)):
if chars[i] == 'z':
chars[i] = 'A'
break
elif chars[i] == 'Z':
continue
# Find a non-existent group name.
# getgrall() will not necessarily report all existing groups
# (typical for LDAP based directories in big organizations).
for _ in range(30):
fakename = ''.join(random.choices(string.ascii_lowercase, k=6))
try:
grp.getgrnam(fakename)
except KeyError:
break
else:
self.fail('Cannot find non-existent group name')

# Find a non-existent gid.
maxgid = 2**31
for _ in range(30):
fakegid = random.randrange(maxgid)
try:
grp.getgrgid(fakegid)
except KeyError:
break
except OverflowError:
if maxgid == 2**31:
maxgid = 2**16-1
elif maxgid == 2**16-1:
maxgid = 2**15
else:
chars[i] = chr(ord(chars[i]) + 1)
break
else:
namei = namei + 1
try:
fakename = allnames[namei]
except IndexError:
# should never happen... if so, just forget it
break
fakename = ''.join(chars)

self.assertRaises(KeyError, grp.getgrnam, fakename)

# Choose a non-existent gid.
fakegid = 4127
while fakegid in bygids:
fakegid = (fakegid * 3) % 0x10000

self.assertRaises(KeyError, grp.getgrgid, fakegid)

def test_noninteger_gid(self):
entries = grp.getgrall()
if not entries:
self.skipTest('no groups')
# Choose an existent gid.
gid = entries[0][2]
self.assertRaises(TypeError, grp.getgrgid, float(gid))
self.assertRaises(TypeError, grp.getgrgid, str(gid))
raise
else:
self.fail('Cannot find non-existent gid')


if __name__ == "__main__":
Expand Down
10 changes: 10 additions & 0 deletions Lib/test/test_imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,16 @@ def cmd_AUTHENTICATE(self, tag, args):
r'\[AUTHENTICATIONFAILED\] invalid'):
client.authenticate('MYAUTH', lambda x: b'fake')

def test_invalid_login(self):
class MyServer(SimpleIMAPHandler):
def cmd_LOGIN(self, tag, args):
self.server.logged = args[0]
self._send_tagged(tag, 'NO', '[LOGIN] failed')
client, _ = self._setup(MyServer)
with self.assertRaisesRegex(imaplib.IMAP4.error,
r'\[LOGIN\] failed'):
client.login('user', 'wrongpass')

def test_valid_authentication_bytes(self):
class MyServer(SimpleIMAPHandler):
def cmd_AUTHENTICATE(self, tag, args):
Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,15 @@ def test_import_raises_ModuleNotFoundError(self):
with self.assertRaises(ModuleNotFoundError):
import something_that_should_not_exist_anywhere

def test_import_null_byte_in_name_raises_ModuleNotFoundError(self):
# gh-150633: module names containing null bytes should not
# lead to duplicates in sys.modules
before = set(sys.modules.keys())
with self.assertRaises(ModuleNotFoundError):
__import__('zipimport\x00junk')

self.assertEqual(set(sys.modules.keys()), before)

def test_from_import_missing_module_raises_ModuleNotFoundError(self):
with self.assertRaises(ModuleNotFoundError):
from something_that_should_not_exist_anywhere import blah
Expand Down
34 changes: 34 additions & 0 deletions Lib/test/test_listcomps.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ def test_references___class__(self):
"""
self._check_in_scopes(code, raises=NameError)

def test_references___class___nested(self):
code = """
res = [(lambda: __class__)() for _ in [1]]
"""
self._check_in_scopes(code, raises=NameError)

def test_references___class___nested_used(self):
class _C:
res = [lambda: __class__ for _ in [1]]
self.assertIs(_C.res[0](), _C)

def test_references___class___defined(self):
code = """
__class__ = 2
Expand All @@ -180,18 +191,41 @@ def test_references___class___defined(self):
code, outputs={"res": [2]}, scopes=["module", "function"])
self._check_in_scopes(code, raises=NameError, scopes=["class"])

def test_references___class___defined_nested(self):
code = """
__class__ = 2
res = [(lambda: __class__)() for x in [1]]
"""
self._check_in_scopes(
code, outputs={"res": [2]}, scopes=["module", "function"])
self._check_in_scopes(code, raises=NameError, scopes=["class"])

def test_references___classdict__(self):
code = """
class i: [__classdict__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

@unittest.expectedFailure # TODO: RUSTPYTHON; SyntaxError: compiler_make_closure: cannot find '__classdict__' in parent vars
def test_references___classdict___nested(self):
class _C:
# res = [(lambda: __classdict__)() for _ in [1]] # TODO: RUSTPYTHON
pass # TODO: RUSTPYTHON
self.assertIn("res", _C.res[0])

def test_references___conditional_annotations__(self):
code = """
class i: [__conditional_annotations__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

@unittest.expectedFailure # TODO: RUSTPYTHON; SyntaxError: compiler_make_closure: cannot find '__conditional_annotations__' in parent vars
def test_references___conditional_annotations___nested(self):
code = """
class i: [lambda: __conditional_annotations__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

def test_references___class___enclosing(self):
code = """
__class__ = 2
Expand Down
19 changes: 19 additions & 0 deletions Lib/test/test_memoryio.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,25 @@ def test_setstate(self):
memio.close()
self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None))

def test_write_str_subclass(self):
# Writing a str subclass should use the subclass's unicode data
# directly, not call __str__ on it (which may return a different
# value). gh-149047
class MyStr(str):
def __str__(self):
return "WRONG"

s = MyStr("correct")
memio = self.ioclass()
memio.write(s)
self.assertEqual(memio.getvalue(), "correct")

# Also test the fast path where pos == string_size (STATE_ACCUMULATING)
memio2 = self.ioclass()
memio2.write(MyStr("hello "))
memio2.write(MyStr("world"))
self.assertEqual(memio2.getvalue(), "hello world")

@unittest.expectedFailure # TODO: RUSTPYTHON; +
def test_issue5265(self):
return super().test_issue5265()
Expand Down
Loading