Skip to content

Commit

Permalink
Merge branch 'main' into superopt
Browse files Browse the repository at this point in the history
* main:
  Remove `expert-*` from `project-updater` GH workflow (python#103579)
  pythongh-103583: Add codecs and maps to _codecs_* module state (python#103540)
  pythongh-48330: address review comments to PR-12271 (python#103209)
  pythongh-103527: Add multibytecodec.h as make dep for _codecs_* (python#103567)
  pythongh-103553: Improve `test_inspect`: add more assertions, remove unused (python#103554)
  pythonGH-103517: Improve tests for `pathlib.Path.walk()` (pythonGH-103518)
  pythongh-102114: Make dis print more concise tracebacks for syntax errors in str inputs (python#102115)
  pythonGH-78079: Fix UNC device path root normalization in pathlib (pythonGH-102003)
  pythongh-101517: Add regression test for a lineno bug in try/except* impacting pdb (python#103547)
  pythongh-103527: Add make deps for _codecs_* and _multibytecodec (python#103528)
  pythongh-103532: Fix reST syntax in NEWS entry (pythonGH-103544)
  pythongh-103532: Add NEWS entry (python#103542)
  • Loading branch information
carljm committed Apr 17, 2023
2 parents 94399c2 + 76933df commit 5136459
Show file tree
Hide file tree
Showing 24 changed files with 313 additions and 162 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/project-updater.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ jobs:
# if an issue has any of these labels, it will be added
# to the corresponding project
- { project: 2, label: "release-blocker, deferred-blocker" }
- { project: 3, label: expert-subinterpreters }
- { project: 29, label: expert-asyncio }
- { project: 32, label: sprint }

steps:
Expand Down
4 changes: 0 additions & 4 deletions Doc/library/unittest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2191,10 +2191,6 @@ Loading and running tests
.. versionadded:: 3.12
Added *durations* keyword argument.

.. versionchanged:: 3.12
Subclasses should accept ``**kwargs`` to ensure compatibility as the
interface changes.

.. data:: defaultTestLoader

Instance of the :class:`TestLoader` class intended to be shared. If no
Expand Down
6 changes: 3 additions & 3 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ def _try_compile(source, name):
expect code objects
"""
try:
c = compile(source, name, 'eval')
return compile(source, name, 'eval')
except SyntaxError:
c = compile(source, name, 'exec')
return c
pass
return compile(source, name, 'exec')

def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False):
"""Disassemble classes, methods, functions, and other compiled objects.
Expand Down
11 changes: 8 additions & 3 deletions Lib/pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,14 @@ def _parse_path(cls, path):
if altsep:
path = path.replace(altsep, sep)
drv, root, rel = cls._flavour.splitroot(path)
if drv.startswith(sep):
# pathlib assumes that UNC paths always have a root.
root = sep
if not root and drv.startswith(sep) and not drv.endswith(sep):
drv_parts = drv.split(sep)
if len(drv_parts) == 4 and drv_parts[2] not in '?.':
# e.g. //server/share
root = sep
elif len(drv_parts) == 6:
# e.g. //?/unc/server/share
root = sep
parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.']
return drv, root, parsed

Expand Down
7 changes: 7 additions & 0 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,13 @@ def check(expected, **kwargs):
check(dis_nested_2, depth=None)
check(dis_nested_2)

def test__try_compile_no_context_exc_on_error(self):
# see gh-102114
try:
dis._try_compile(")", "")
except Exception as e:
self.assertIsNone(e.__context__)

@staticmethod
def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY):
for _ in range(times):
Expand Down
24 changes: 9 additions & 15 deletions Lib/test/test_inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -1820,8 +1820,7 @@ def test_errors(self):
self.assertEqualException(f, '2, 3, 4')
self.assertEqualException(f, '1, 2, 3, a=1')
self.assertEqualException(f, '2, 3, 4, c=5')
# XXX: success of this one depends on dict order
## self.assertEqualException(f, '2, 3, 4, a=1, c=5')
self.assertEqualException(f, '2, 3, 4, a=1, c=5')
# f got an unexpected keyword argument
self.assertEqualException(f, 'c=2')
self.assertEqualException(f, '2, c=3')
Expand All @@ -1832,17 +1831,19 @@ def test_errors(self):
self.assertEqualException(f, '1, a=2')
self.assertEqualException(f, '1, **{"a":2}')
self.assertEqualException(f, '1, 2, b=3')
# XXX: Python inconsistency
# - for functions and bound methods: unexpected keyword 'c'
# - for unbound methods: multiple values for keyword 'a'
#self.assertEqualException(f, '1, c=3, a=2')
self.assertEqualException(f, '1, c=3, a=2')
# issue11256:
f3 = self.makeCallable('**c')
self.assertEqualException(f3, '1, 2')
self.assertEqualException(f3, '1, 2, a=1, b=2')
f4 = self.makeCallable('*, a, b=0')
self.assertEqualException(f3, '1, 2')
self.assertEqualException(f3, '1, 2, a=1, b=2')
self.assertEqualException(f4, '1, 2')
self.assertEqualException(f4, '1, 2, a=1, b=2')
self.assertEqualException(f4, 'a=1, a=3')
self.assertEqualException(f4, 'a=1, c=3')
self.assertEqualException(f4, 'a=1, a=3, b=4')
self.assertEqualException(f4, 'a=1, b=2, a=3, b=4')
self.assertEqualException(f4, 'a=1, a=2, a=3, b=4')

# issue #20816: getcallargs() fails to iterate over non-existent
# kwonlydefaults and raises a wrong TypeError
Expand Down Expand Up @@ -2872,8 +2873,6 @@ def foo(cls, *, arg):
def test_signature_on_partial(self):
from functools import partial

Parameter = inspect.Parameter

def test():
pass

Expand Down Expand Up @@ -2988,8 +2987,6 @@ def test(a, b, c:int) -> 42:
((('c', ..., int, "positional_or_keyword"),),
42))

psig = inspect.signature(partial(partial(test, 1), 2))

def foo(a):
return a
_foo = partial(partial(foo, a=10), a=20)
Expand Down Expand Up @@ -4153,8 +4150,6 @@ def test(a, *args, b, z=100, **kwargs):
self.assertEqual(ba.args, (10, 20))

def test_signature_bind_positional_only(self):
P = inspect.Parameter

def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs):
return a_po, b_po, c_po, foo, bar, kwargs

Expand Down Expand Up @@ -4578,7 +4573,6 @@ def test_qualname_source(self):
self.assertEqual(err, b'')

def test_builtins(self):
module = importlib.import_module('unittest')
_, out, err = assert_python_failure('-m', 'inspect',
'sys')
lines = err.decode().splitlines()
Expand Down
8 changes: 8 additions & 0 deletions Lib/test/test_ntpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def test_splitroot(self):

# gh-81790: support device namespace, including UNC drives.
tester('ntpath.splitroot("//?/c:")', ("//?/c:", "", ""))
tester('ntpath.splitroot("//./c:")', ("//./c:", "", ""))
tester('ntpath.splitroot("//?/c:/")', ("//?/c:", "/", ""))
tester('ntpath.splitroot("//?/c:/dir")', ("//?/c:", "/", "dir"))
tester('ntpath.splitroot("//?/UNC")', ("//?/UNC", "", ""))
Expand All @@ -179,8 +180,12 @@ def test_splitroot(self):
tester('ntpath.splitroot("//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam")',
('//?/VOLUME{00000000-0000-0000-0000-000000000000}', '/', 'spam'))
tester('ntpath.splitroot("//?/BootPartition/")', ("//?/BootPartition", "/", ""))
tester('ntpath.splitroot("//./BootPartition/")', ("//./BootPartition", "/", ""))
tester('ntpath.splitroot("//./PhysicalDrive0")', ("//./PhysicalDrive0", "", ""))
tester('ntpath.splitroot("//./nul")', ("//./nul", "", ""))

tester('ntpath.splitroot("\\\\?\\c:")', ("\\\\?\\c:", "", ""))
tester('ntpath.splitroot("\\\\.\\c:")', ("\\\\.\\c:", "", ""))
tester('ntpath.splitroot("\\\\?\\c:\\")', ("\\\\?\\c:", "\\", ""))
tester('ntpath.splitroot("\\\\?\\c:\\dir")', ("\\\\?\\c:", "\\", "dir"))
tester('ntpath.splitroot("\\\\?\\UNC")', ("\\\\?\\UNC", "", ""))
Expand All @@ -193,6 +198,9 @@ def test_splitroot(self):
tester('ntpath.splitroot("\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}\\spam")',
('\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}', '\\', 'spam'))
tester('ntpath.splitroot("\\\\?\\BootPartition\\")', ("\\\\?\\BootPartition", "\\", ""))
tester('ntpath.splitroot("\\\\.\\BootPartition\\")', ("\\\\.\\BootPartition", "\\", ""))
tester('ntpath.splitroot("\\\\.\\PhysicalDrive0")', ("\\\\.\\PhysicalDrive0", "", ""))
tester('ntpath.splitroot("\\\\.\\nul")', ("\\\\.\\nul", "", ""))

# gh-96290: support partial/invalid UNC drives
tester('ntpath.splitroot("//")', ("//", "", "")) # empty server & missing share
Expand Down
101 changes: 69 additions & 32 deletions Lib/test/test_pathlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,9 @@ def test_drive_root_parts(self):
check(('c:/a',), 'c:', '\\', ('c:\\', 'a'))
check(('/a',), '', '\\', ('\\', 'a'))
# UNC paths.
check(('//',), '\\\\', '', ('\\\\',))
check(('//a',), '\\\\a', '', ('\\\\a',))
check(('//a/',), '\\\\a\\', '', ('\\\\a\\',))
check(('//a/b',), '\\\\a\\b', '\\', ('\\\\a\\b\\',))
check(('//a/b/',), '\\\\a\\b', '\\', ('\\\\a\\b\\',))
check(('//a/b/c',), '\\\\a\\b', '\\', ('\\\\a\\b\\', 'c'))
Expand All @@ -823,12 +826,26 @@ def test_drive_root_parts(self):
# UNC paths.
check(('a', '//b/c//', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd'))
# Extended paths.
check(('//./c:',), '\\\\.\\c:', '', ('\\\\.\\c:',))
check(('//?/c:/',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\',))
check(('//?/c:/a',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'a'))
check(('//?/c:/a', '/b'), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'b'))
# Extended UNC paths (format is "\\?\UNC\server\share").
check(('//?',), '\\\\?', '', ('\\\\?',))
check(('//?/',), '\\\\?\\', '', ('\\\\?\\',))
check(('//?/UNC',), '\\\\?\\UNC', '', ('\\\\?\\UNC',))
check(('//?/UNC/',), '\\\\?\\UNC\\', '', ('\\\\?\\UNC\\',))
check(('//?/UNC/b',), '\\\\?\\UNC\\b', '', ('\\\\?\\UNC\\b',))
check(('//?/UNC/b/',), '\\\\?\\UNC\\b\\', '', ('\\\\?\\UNC\\b\\',))
check(('//?/UNC/b/c',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',))
check(('//?/UNC/b/c/',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',))
check(('//?/UNC/b/c/d',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\', 'd'))
# UNC device paths
check(('//./BootPartition/',), '\\\\.\\BootPartition', '\\', ('\\\\.\\BootPartition\\',))
check(('//?/BootPartition/',), '\\\\?\\BootPartition', '\\', ('\\\\?\\BootPartition\\',))
check(('//./PhysicalDrive0',), '\\\\.\\PhysicalDrive0', '', ('\\\\.\\PhysicalDrive0',))
check(('//?/Volume{}/',), '\\\\?\\Volume{}', '\\', ('\\\\?\\Volume{}\\',))
check(('//./nul',), '\\\\.\\nul', '', ('\\\\.\\nul',))
# Second part has a root but not drive.
check(('a', '/b', 'c'), '', '\\', ('\\', 'b', 'c'))
check(('Z:/a', '/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c'))
Expand Down Expand Up @@ -1371,6 +1388,13 @@ def test_join(self):
self.assertEqual(pp, P('C:/a/b/dd:s'))
pp = p.joinpath(P('E:d:s'))
self.assertEqual(pp, P('E:d:s'))
# Joining onto a UNC path with no root
pp = P('//').joinpath('server')
self.assertEqual(pp, P('//server'))
pp = P('//server').joinpath('share')
self.assertEqual(pp, P('//server/share'))
pp = P('//./BootPartition').joinpath('Windows')
self.assertEqual(pp, P('//./BootPartition/Windows'))

def test_div(self):
# Basically the same as joinpath().
Expand Down Expand Up @@ -2678,20 +2702,20 @@ def setUp(self):
del self.sub2_tree[1][:1]

def test_walk_topdown(self):
all = list(self.walk_path.walk())

self.assertEqual(len(all), 4)
# We can't know which order SUB1 and SUB2 will appear in.
# Not flipped: TESTFN, SUB1, SUB11, SUB2
# flipped: TESTFN, SUB2, SUB1, SUB11
flipped = all[0][1][0] != "SUB1"
all[0][1].sort()
all[3 - 2 * flipped][-1].sort()
all[3 - 2 * flipped][1].sort()
self.assertEqual(all[0], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"]))
self.assertEqual(all[1 + flipped], (self.sub1_path, ["SUB11"], ["tmp2"]))
self.assertEqual(all[2 + flipped], (self.sub11_path, [], []))
self.assertEqual(all[3 - 2 * flipped], self.sub2_tree)
walker = self.walk_path.walk()
entry = next(walker)
entry[1].sort() # Ensure we visit SUB1 before SUB2
self.assertEqual(entry, (self.walk_path, ["SUB1", "SUB2"], ["tmp1"]))
entry = next(walker)
self.assertEqual(entry, (self.sub1_path, ["SUB11"], ["tmp2"]))
entry = next(walker)
self.assertEqual(entry, (self.sub11_path, [], []))
entry = next(walker)
entry[1].sort()
entry[2].sort()
self.assertEqual(entry, self.sub2_tree)
with self.assertRaises(StopIteration):
next(walker)

def test_walk_prune(self, walk_path=None):
if walk_path is None:
Expand All @@ -2715,24 +2739,37 @@ def test_file_like_path(self):
self.test_walk_prune(FakePath(self.walk_path).__fspath__())

def test_walk_bottom_up(self):
all = list(self.walk_path.walk( top_down=False))

self.assertEqual(len(all), 4, all)
# We can't know which order SUB1 and SUB2 will appear in.
# Not flipped: SUB11, SUB1, SUB2, TESTFN
# flipped: SUB2, SUB11, SUB1, TESTFN
flipped = all[3][1][0] != "SUB1"
all[3][1].sort()
all[2 - 2 * flipped][-1].sort()
all[2 - 2 * flipped][1].sort()
self.assertEqual(all[3],
(self.walk_path, ["SUB1", "SUB2"], ["tmp1"]))
self.assertEqual(all[flipped],
(self.sub11_path, [], []))
self.assertEqual(all[flipped + 1],
(self.sub1_path, ["SUB11"], ["tmp2"]))
self.assertEqual(all[2 - 2 * flipped],
self.sub2_tree)
seen_testfn = seen_sub1 = seen_sub11 = seen_sub2 = False
for path, dirnames, filenames in self.walk_path.walk(top_down=False):
if path == self.walk_path:
self.assertFalse(seen_testfn)
self.assertTrue(seen_sub1)
self.assertTrue(seen_sub2)
self.assertEqual(sorted(dirnames), ["SUB1", "SUB2"])
self.assertEqual(filenames, ["tmp1"])
seen_testfn = True
elif path == self.sub1_path:
self.assertFalse(seen_testfn)
self.assertFalse(seen_sub1)
self.assertTrue(seen_sub11)
self.assertEqual(dirnames, ["SUB11"])
self.assertEqual(filenames, ["tmp2"])
seen_sub1 = True
elif path == self.sub11_path:
self.assertFalse(seen_sub1)
self.assertFalse(seen_sub11)
self.assertEqual(dirnames, [])
self.assertEqual(filenames, [])
seen_sub11 = True
elif path == self.sub2_path:
self.assertFalse(seen_testfn)
self.assertFalse(seen_sub2)
self.assertEqual(sorted(dirnames), sorted(self.sub2_tree[1]))
self.assertEqual(sorted(filenames), sorted(self.sub2_tree[2]))
seen_sub2 = True
else:
raise AssertionError(f"Unexpected path: {path}")
self.assertTrue(seen_testfn)

@os_helper.skip_unless_symlink
def test_walk_follow_symlinks(self):
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,26 @@ def test_pdb_issue_gh_103225():
(Pdb) continue
"""

def test_pdb_issue_gh_101517():
"""See GH-101517
Make sure pdb doesn't crash when the exception is caught in a try/except* block
>>> def test_function():
... try:
... raise KeyError
... except* Exception as e:
... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
>>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
... 'continue'
... ]):
... test_function()
--Return--
> <doctest test.test_pdb.test_pdb_issue_gh_101517[0]>(None)test_function()->None
(Pdb) continue
"""


@support.requires_subprocess()
class PdbTestCase(unittest.TestCase):
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_unittest/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1367,7 +1367,7 @@ def testSpecifiedStreamUsed(self):
self.assertTrue(runner.stream.stream is f)

def test_durations(self):
def run(test, expect_durations):
def run(test, *, expect_durations=True):
stream = BufferedWriter()
runner = unittest.TextTestRunner(stream=stream, durations=5, verbosity=2)
result = runner.run(test)
Expand All @@ -1389,21 +1389,21 @@ class Foo(unittest.TestCase):
def test_1(self):
pass

run(Foo('test_1'), True)
run(Foo('test_1'), expect_durations=True)

# failure
class Foo(unittest.TestCase):
def test_1(self):
self.assertEqual(0, 1)

run(Foo('test_1'), True)
run(Foo('test_1'), expect_durations=True)

# error
class Foo(unittest.TestCase):
def test_1(self):
1 / 0

run(Foo('test_1'), True)
run(Foo('test_1'), expect_durations=True)


# error in setUp and tearDown
Expand All @@ -1414,15 +1414,15 @@ def setUp(self):
def test_1(self):
pass

run(Foo('test_1'), True)
run(Foo('test_1'), expect_durations=True)

# skip (expect no durations)
class Foo(unittest.TestCase):
@unittest.skip("reason")
def test_1(self):
pass

run(Foo('test_1'), False)
run(Foo('test_1'), expect_durations=False)



Expand Down

0 comments on commit 5136459

Please sign in to comment.