Skip to content

Commit

Permalink
Merge branch 'main' into fix-44864
Browse files Browse the repository at this point in the history
  • Loading branch information
encukou authored Sep 24, 2024
2 parents 27391df + 17b3bc9 commit 8dd8ae4
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 54 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/jit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,15 @@ jobs:
- name: Native Windows
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
run: |
choco upgrade llvm -y
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '--pgo' }} -p ${{ matrix.architecture }}
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# No PGO or tests (yet):
- name: Emulated Windows
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
run: |
choco upgrade llvm -y
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
- name: Native macOS
Expand Down
12 changes: 8 additions & 4 deletions Doc/library/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,12 @@ The following sections describe how each of these are used.
prog
^^^^

By default, :class:`ArgumentParser` objects use ``sys.argv[0]`` to determine
By default, :class:`ArgumentParser` objects use the base name
(see :func:`os.path.basename`) of ``sys.argv[0]`` to determine
how to display the name of the program in help messages. This default is almost
always desirable because it will make the help messages match how the program was
invoked on the command line. For example, consider a file named
``myprogram.py`` with the following code::
always desirable because it will make the help messages match the name that was
used to invoke the program on the command line. For example, consider a file
named ``myprogram.py`` with the following code::

import argparse
parser = argparse.ArgumentParser()
Expand Down Expand Up @@ -1122,6 +1123,9 @@ is used when no command-line argument was present::
>>> parser.parse_args([])
Namespace(foo=42)

For required_ arguments, the ``default`` value is ignored. For example, this
applies to positional arguments with nargs_ values other than ``?`` or ``*``,
or optional arguments marked as ``required=True``.

Providing ``default=argparse.SUPPRESS`` causes no attribute to be added if the
command-line argument was not present::
Expand Down
17 changes: 9 additions & 8 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,12 @@ def _get_actions_usage_parts(self, actions, groups):
continue

try:
start = actions.index(group._group_actions[0])
start = min(actions.index(item) for item in group._group_actions)
except ValueError:
continue
else:
end = start + len(group._group_actions)
if actions[start:end] == group._group_actions:
if set(actions[start:end]) == set(group._group_actions):
group_actions.update(group._group_actions)
inserts[start, end] = group

Expand Down Expand Up @@ -2227,18 +2227,19 @@ def _match_argument(self, action, arg_strings_pattern):
def _match_arguments_partial(self, actions, arg_strings_pattern):
# progressively shorten the actions list by slicing off the
# final actions until we find a match
result = []
for i in range(len(actions), 0, -1):
actions_slice = actions[:i]
pattern = ''.join([self._get_nargs_pattern(action)
for action in actions_slice])
match = _re.match(pattern, arg_strings_pattern)
if match is not None:
result.extend([len(string) for string in match.groups()])
break

# return the list of arg string counts
return result
result = [len(string) for string in match.groups()]
if (match.end() < len(arg_strings_pattern)
and arg_strings_pattern[match.end()] == 'O'):
while result and not result[-1]:
del result[-1]
return result
return []

def _parse_optional(self, arg_string):
# if it's an empty string, it was meant to be a positional
Expand Down
4 changes: 2 additions & 2 deletions Lib/pty.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def openpty():
except ImportError:
return master_fd, slave_fd
try:
ioctl(result, I_PUSH, "ptem")
ioctl(result, I_PUSH, "ldterm")
ioctl(slave_fd, I_PUSH, "ptem")
ioctl(slave_fd, I_PUSH, "ldterm")
except OSError:
pass
return master_fd, slave_fd
Expand Down
152 changes: 116 additions & 36 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,16 +280,18 @@ def test_failures(self, tester):
parser = self._get_parser(tester)
for args_str in tester.failures:
args = args_str.split()
with tester.assertRaises(ArgumentParserError, msg=args):
parser.parse_args(args)
with tester.subTest(args=args):
with tester.assertRaises(ArgumentParserError, msg=args):
parser.parse_args(args)

def test_successes(self, tester):
parser = self._get_parser(tester)
for args, expected_ns in tester.successes:
if isinstance(args, str):
args = args.split()
result_ns = self._parse_args(parser, args)
tester.assertEqual(expected_ns, result_ns)
with tester.subTest(args=args):
result_ns = self._parse_args(parser, args)
tester.assertEqual(expected_ns, result_ns)

# add tests for each combination of an optionals adding method
# and an arg parsing method
Expand Down Expand Up @@ -1089,57 +1091,87 @@ class TestPositionalsNargs2None(ParserTestCase):
class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
"""Test a Positional with no nargs followed by one with unlimited"""

argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
failures = ['', '--foo']
argument_signatures = [Sig('-x'), Sig('foo'), Sig('bar', nargs='*')]
failures = ['', '--foo', 'a b -x X c']
successes = [
('a', NS(foo='a', bar=[])),
('a b', NS(foo='a', bar=['b'])),
('a b c', NS(foo='a', bar=['b', 'c'])),
('a', NS(x=None, foo='a', bar=[])),
('a b', NS(x=None, foo='a', bar=['b'])),
('a b c', NS(x=None, foo='a', bar=['b', 'c'])),
('-x X a', NS(x='X', foo='a', bar=[])),
('a -x X', NS(x='X', foo='a', bar=[])),
('-x X a b', NS(x='X', foo='a', bar=['b'])),
('a -x X b', NS(x='X', foo='a', bar=['b'])),
('a b -x X', NS(x='X', foo='a', bar=['b'])),
('-x X a b c', NS(x='X', foo='a', bar=['b', 'c'])),
('a -x X b c', NS(x='X', foo='a', bar=['b', 'c'])),
('a b c -x X', NS(x='X', foo='a', bar=['b', 'c'])),
]


class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
"""Test a Positional with no nargs followed by one with one or more"""

argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
failures = ['', '--foo', 'a']
argument_signatures = [Sig('-x'), Sig('foo'), Sig('bar', nargs='+')]
failures = ['', '--foo', 'a', 'a b -x X c']
successes = [
('a b', NS(foo='a', bar=['b'])),
('a b c', NS(foo='a', bar=['b', 'c'])),
('a b', NS(x=None, foo='a', bar=['b'])),
('a b c', NS(x=None, foo='a', bar=['b', 'c'])),
('-x X a b', NS(x='X', foo='a', bar=['b'])),
('a -x X b', NS(x='X', foo='a', bar=['b'])),
('a b -x X', NS(x='X', foo='a', bar=['b'])),
('-x X a b c', NS(x='X', foo='a', bar=['b', 'c'])),
('a -x X b c', NS(x='X', foo='a', bar=['b', 'c'])),
('a b c -x X', NS(x='X', foo='a', bar=['b', 'c'])),
]


class TestPositionalsNargsNoneOptional(ParserTestCase):
"""Test a Positional with no nargs followed by one with an Optional"""

argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
argument_signatures = [Sig('-x'), Sig('foo'), Sig('bar', nargs='?')]
failures = ['', '--foo', 'a b c']
successes = [
('a', NS(foo='a', bar=None)),
('a b', NS(foo='a', bar='b')),
('a', NS(x=None, foo='a', bar=None)),
('a b', NS(x=None, foo='a', bar='b')),
('-x X a', NS(x='X', foo='a', bar=None)),
('a -x X', NS(x='X', foo='a', bar=None)),
('-x X a b', NS(x='X', foo='a', bar='b')),
('a -x X b', NS(x='X', foo='a', bar='b')),
('a b -x X', NS(x='X', foo='a', bar='b')),
]


class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
"""Test a Positional with unlimited nargs followed by one with none"""

argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
failures = ['', '--foo']
argument_signatures = [Sig('-x'), Sig('foo', nargs='*'), Sig('bar')]
failures = ['', '--foo', 'a -x X b', 'a -x X b c', 'a b -x X c']
successes = [
('a', NS(foo=[], bar='a')),
('a b', NS(foo=['a'], bar='b')),
('a b c', NS(foo=['a', 'b'], bar='c')),
('a', NS(x=None, foo=[], bar='a')),
('a b', NS(x=None, foo=['a'], bar='b')),
('a b c', NS(x=None, foo=['a', 'b'], bar='c')),
('-x X a', NS(x='X', foo=[], bar='a')),
('a -x X', NS(x='X', foo=[], bar='a')),
('-x X a b', NS(x='X', foo=['a'], bar='b')),
('a b -x X', NS(x='X', foo=['a'], bar='b')),
('-x X a b c', NS(x='X', foo=['a', 'b'], bar='c')),
('a b c -x X', NS(x='X', foo=['a', 'b'], bar='c')),
]


class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
"""Test a Positional with one or more nargs followed by one with none"""

argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
failures = ['', '--foo', 'a']
argument_signatures = [Sig('-x'), Sig('foo', nargs='+'), Sig('bar')]
failures = ['', '--foo', 'a', 'a -x X b c', 'a b -x X c']
successes = [
('a b', NS(foo=['a'], bar='b')),
('a b c', NS(foo=['a', 'b'], bar='c')),
('a b', NS(x=None, foo=['a'], bar='b')),
('a b c', NS(x=None, foo=['a', 'b'], bar='c')),
('-x X a b', NS(x='X', foo=['a'], bar='b')),
('a -x X b', NS(x='X', foo=['a'], bar='b')),
('a b -x X', NS(x='X', foo=['a'], bar='b')),
('-x X a b c', NS(x='X', foo=['a', 'b'], bar='c')),
('a b c -x X', NS(x='X', foo=['a', 'b'], bar='c')),
]


Expand Down Expand Up @@ -1224,44 +1256,66 @@ class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
"""Test three Positionals: no nargs, unlimited nargs and 1 nargs"""

argument_signatures = [
Sig('-x'),
Sig('foo'),
Sig('bar', nargs='*'),
Sig('baz', nargs=1),
]
failures = ['', '--foo', 'a']
failures = ['', '--foo', 'a', 'a b -x X c']
successes = [
('a b', NS(foo='a', bar=[], baz=['b'])),
('a b c', NS(foo='a', bar=['b'], baz=['c'])),
('a b', NS(x=None, foo='a', bar=[], baz=['b'])),
('a b c', NS(x=None, foo='a', bar=['b'], baz=['c'])),
('-x X a b', NS(x='X', foo='a', bar=[], baz=['b'])),
('a -x X b', NS(x='X', foo='a', bar=[], baz=['b'])),
('a b -x X', NS(x='X', foo='a', bar=[], baz=['b'])),
('-x X a b c', NS(x='X', foo='a', bar=['b'], baz=['c'])),
('a -x X b c', NS(x='X', foo='a', bar=['b'], baz=['c'])),
('a b c -x X', NS(x='X', foo='a', bar=['b'], baz=['c'])),
]


class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
"""Test three Positionals: no nargs, one or more nargs and 1 nargs"""

argument_signatures = [
Sig('-x'),
Sig('foo'),
Sig('bar', nargs='+'),
Sig('baz', nargs=1),
]
failures = ['', '--foo', 'a', 'b']
failures = ['', '--foo', 'a', 'b', 'a b -x X c d', 'a b c -x X d']
successes = [
('a b c', NS(foo='a', bar=['b'], baz=['c'])),
('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
('a b c', NS(x=None, foo='a', bar=['b'], baz=['c'])),
('a b c d', NS(x=None, foo='a', bar=['b', 'c'], baz=['d'])),
('-x X a b c', NS(x='X', foo='a', bar=['b'], baz=['c'])),
('a -x X b c', NS(x='X', foo='a', bar=['b'], baz=['c'])),
('a b -x X c', NS(x='X', foo='a', bar=['b'], baz=['c'])),
('a b c -x X', NS(x='X', foo='a', bar=['b'], baz=['c'])),
('-x X a b c d', NS(x='X', foo='a', bar=['b', 'c'], baz=['d'])),
('a -x X b c d', NS(x='X', foo='a', bar=['b', 'c'], baz=['d'])),
('a b c d -x X', NS(x='X', foo='a', bar=['b', 'c'], baz=['d'])),
]


class TestPositionalsNargsNoneOptional1(ParserTestCase):
"""Test three Positionals: no nargs, optional narg and 1 nargs"""

argument_signatures = [
Sig('-x'),
Sig('foo'),
Sig('bar', nargs='?', default=0.625),
Sig('baz', nargs=1),
]
failures = ['', '--foo', 'a']
failures = ['', '--foo', 'a', 'a b -x X c']
successes = [
('a b', NS(foo='a', bar=0.625, baz=['b'])),
('a b c', NS(foo='a', bar='b', baz=['c'])),
('a b', NS(x=None, foo='a', bar=0.625, baz=['b'])),
('a b c', NS(x=None, foo='a', bar='b', baz=['c'])),
('-x X a b', NS(x='X', foo='a', bar=0.625, baz=['b'])),
('a -x X b', NS(x='X', foo='a', bar=0.625, baz=['b'])),
('a b -x X', NS(x='X', foo='a', bar=0.625, baz=['b'])),
('-x X a b c', NS(x='X', foo='a', bar='b', baz=['c'])),
('a -x X b c', NS(x='X', foo='a', bar='b', baz=['c'])),
('a b c -x X', NS(x='X', foo='a', bar='b', baz=['c'])),
]


Expand Down Expand Up @@ -1477,6 +1531,9 @@ class TestNargsRemainder(ParserTestCase):
successes = [
('X', NS(x='X', y=[], z=None)),
('-z Z X', NS(x='X', y=[], z='Z')),
('-z Z X A B', NS(x='X', y=['A', 'B'], z='Z')),
('X -z Z A B', NS(x='X', y=['-z', 'Z', 'A', 'B'], z=None)),
('X A -z Z B', NS(x='X', y=['A', '-z', 'Z', 'B'], z=None)),
('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
]
Expand Down Expand Up @@ -2845,6 +2902,29 @@ def test_help(self):
'''
self.assertEqual(parser.format_help(), textwrap.dedent(expected))

def test_optional_order(self):
parser = ErrorRaisingArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--foo')
group.add_argument('bar', nargs='?')
expected = '''\
usage: PROG [-h] (--foo FOO | bar)
positional arguments:
bar
options:
-h, --help show this help message and exit
--foo FOO
'''
self.assertEqual(parser.format_help(), textwrap.dedent(expected))

parser = ErrorRaisingArgumentParser(prog='PROG')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('bar', nargs='?')
group.add_argument('--foo')
self.assertEqual(parser.format_help(), textwrap.dedent(expected))

def test_help_subparser_all_mutually_exclusive_group_members_suppressed(self):
self.maxDiff = None
parser = ErrorRaisingArgumentParser(prog='PROG')
Expand Down Expand Up @@ -6018,8 +6098,8 @@ def test_basic(self):

args, extras = parser.parse_known_args(argv)
# cannot parse the '1,2,3'
self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[]), args)
self.assertEqual(["1", "2", "3"], extras)
self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1]), args)
self.assertEqual(["2", "3"], extras)

argv = 'cmd --foo x 1 --error 2 --bar y 3'.split()
args, extras = parser.parse_known_intermixed_args(argv)
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_free_threading/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from threading import Thread
from unittest import TestCase

from test import support
from test.support import threading_helper


Expand All @@ -13,6 +14,7 @@ def __init__(self, v):

@threading_helper.requires_working_threading()
class TestList(TestCase):
@support.requires_resource('cpu')
def test_racing_iter_append(self):

l = []
Expand Down Expand Up @@ -42,6 +44,7 @@ def reader_func():
for reader in readers:
reader.join()

@support.requires_resource('cpu')
def test_racing_iter_extend(self):
iters = [
lambda x: [x],
Expand Down
Loading

0 comments on commit 8dd8ae4

Please sign in to comment.