Add support for Python 3.11 (#33505)

Argparse started raising ArgumentError exceptions
when the same parser is added twice. Therefore, we
perform the addition only if the parser is not there
already

Port match syntax to our unparser
This commit is contained in:
Massimiliano Culpo 2022-11-05 15:59:12 +01:00 committed by GitHub
parent c9fcb8aadc
commit 5558940ce6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 193 additions and 20 deletions

View File

@ -25,7 +25,7 @@ jobs:
python-version: ${{inputs.python_version}}
- name: Install Python packages
run: |
pip install --upgrade pip six setuptools pytest codecov 'coverage[toml]<=6.2'
pip install --upgrade pip six setuptools pytest codecov coverage[toml]
- name: Package audits (with coverage)
if: ${{ inputs.with_coverage == 'true' }}
run: |

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10']
python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11']
concretizer: ['clingo']
on_develop:
- ${{ github.ref == 'refs/heads/develop' }}
@ -22,7 +22,7 @@ jobs:
- python-version: 2.7
concretizer: original
on_develop: ${{ github.ref == 'refs/heads/develop' }}
- python-version: '3.10'
- python-version: '3.11'
concretizer: original
on_develop: ${{ github.ref == 'refs/heads/develop' }}
exclude:
@ -35,6 +35,9 @@ jobs:
- python-version: '3.9'
concretizer: 'clingo'
on_develop: false
- python-version: '3.10'
concretizer: 'clingo'
on_develop: false
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # @v2
@ -86,7 +89,7 @@ jobs:
SPACK_TEST_SOLVER: ${{ matrix.concretizer }}
SPACK_TEST_PARALLEL: 2
COVERAGE: true
UNIT_TEST_COVERAGE: ${{ (matrix.python-version == '3.10') }}
UNIT_TEST_COVERAGE: ${{ (matrix.python-version == '3.11') }}
run: |
share/spack/qa/run-unit-tests
- uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70
@ -101,7 +104,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2
with:
python-version: '3.10'
python-version: '3.11'
- name: Install System packages
run: |
sudo apt-get -y update
@ -109,7 +112,7 @@ jobs:
sudo apt-get install -y coreutils kcov csh zsh tcsh fish dash bash
- name: Install Python packages
run: |
pip install --upgrade pip six setuptools pytest codecov coverage[toml]==6.2 pytest-xdist
pip install --upgrade pip six setuptools pytest codecov coverage[toml] pytest-xdist
- name: Setup git configuration
run: |
# Need this for the git tests to succeed.
@ -158,7 +161,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2
with:
python-version: '3.10'
python-version: '3.11'
- name: Install System packages
run: |
sudo apt-get -y update

View File

@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # @v2
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2
with:
python-version: '3.10'
python-version: '3.11'
cache: 'pip'
- name: Install Python Packages
run: |
@ -40,7 +40,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-python@13ae5bb136fac2878aff31522b9efb785519f984 # @v2
with:
python-version: '3.10'
python-version: '3.11'
cache: 'pip'
- name: Install Python packages
run: |
@ -57,4 +57,4 @@ jobs:
uses: ./.github/workflows/audit.yaml
with:
with_coverage: ${{ inputs.with_coverage }}
python_version: '3.10'
python_version: '3.11'

View File

@ -1,5 +1,5 @@
Name, Supported Versions, Notes, Requirement Reason
Python, 2.7/3.6-3.10, , Interpreter for Spack
Python, 2.7/3.6-3.11, , Interpreter for Spack
C/C++ Compilers, , , Building software
make, , , Build software
patch, , , Build software

1 Name Supported Versions Notes Requirement Reason
2 Python 2.7/3.6-3.10 2.7/3.6-3.11 Interpreter for Spack
3 C/C++ Compilers Building software
4 make Build software
5 patch Build software

View File

@ -343,17 +343,21 @@ def add_command(self, cmd_name):
self._remove_action(self._actions[-1])
self.subparsers = self.add_subparsers(metavar="COMMAND", dest="command")
# each command module implements a parser() function, to which we
# pass its subparser for setup.
module = spack.cmd.get_module(cmd_name)
if cmd_name not in self.subparsers._name_parser_map:
# each command module implements a parser() function, to which we
# pass its subparser for setup.
module = spack.cmd.get_module(cmd_name)
# build a list of aliases
alias_list = [k for k, v in aliases.items() if v == cmd_name]
# build a list of aliases
alias_list = [k for k, v in aliases.items() if v == cmd_name]
subparser = self.subparsers.add_parser(
cmd_name, aliases=alias_list, help=module.description, description=module.description
)
module.setup_parser(subparser)
subparser = self.subparsers.add_parser(
cmd_name,
aliases=alias_list,
help=module.description,
description=module.description,
)
module.setup_parser(subparser)
# return the callable function for the command
return spack.cmd.get_command(cmd_name)

View File

@ -178,6 +178,71 @@ async def f():
"""
match_literal = """\
match status:
case 400:
return "Bad request"
case 404 | 418:
return "Not found"
case _:
return "Something's wrong with the internet"
"""
match_with_noop = """\
match status:
case 400:
return "Bad request"
"""
match_literal_and_variable = """\
match point:
case (0, 0):
print("Origin")
case (0, y):
print(f"Y={y}")
case (x, 0):
print(f"X={x}")
case (x, y):
print(f"X={x}, Y={y}")
case _:
raise ValueError("Not a point")
"""
match_classes = """\
class Point:
x: int
y: int
def location(point):
match point:
case Point(x=0, y=0):
print("Origin is the point's location.")
case Point(x=0, y=y):
print(f"Y={y} and the point is on the y-axis.")
case Point(x=x, y=0):
print(f"X={x} and the point is on the x-axis.")
case Point():
print("The point is located somewhere else on the plane.")
case _:
print("Not a point")
"""
match_nested = """\
match points:
case []:
print("No points in the list.")
case [Point(0, 0)]:
print("The origin is the only point in the list.")
case [Point(x, y)]:
print(f"A single point {x}, {y} is in the list.")
case [Point(0, y1), Point(0, y2)]:
print(f"Two points on the Y axis at {y1}, {y2} are in the list.")
case _:
print("Something else is found in the list.")
"""
def check_ast_roundtrip(code1, filename="internal", mode="exec"):
ast1 = compile(str(code1), filename, mode, ast.PyCF_ONLY_AST)
code2 = spack.util.unparse.unparse(ast1)
@ -512,3 +577,12 @@ def test_async_with():
@pytest.mark.skipif(sys.version_info < (3, 5), reason="Not supported < 3.5")
def test_async_with_as():
check_ast_roundtrip(async_with_as)
@pytest.mark.skipif(sys.version_info < (3, 10), reason="Not supported < 3.10")
@pytest.mark.parametrize(
"literal",
[match_literal, match_with_noop, match_literal_and_variable, match_classes, match_nested],
)
def test_match_literal(literal):
check_ast_roundtrip(literal)

View File

@ -1243,3 +1243,95 @@ def visit_withitem(self, node):
if node.optional_vars:
self.write(" as ")
self.dispatch(node.optional_vars)
def visit_Match(self, node):
self.fill("match ")
self.dispatch(node.subject)
with self.block():
for case in node.cases:
self.dispatch(case)
def visit_match_case(self, node):
self.fill("case ")
self.dispatch(node.pattern)
if node.guard:
self.write(" if ")
self.dispatch(node.guard)
with self.block():
self.dispatch(node.body)
def visit_MatchValue(self, node):
self.dispatch(node.value)
def visit_MatchSingleton(self, node):
self._write_constant(node.value)
def visit_MatchSequence(self, node):
with self.delimit("[", "]"):
interleave(lambda: self.write(", "), self.dispatch, node.patterns)
def visit_MatchStar(self, node):
name = node.name
if name is None:
name = "_"
self.write("*{}".format(name))
def visit_MatchMapping(self, node):
def write_key_pattern_pair(pair):
k, p = pair
self.dispatch(k)
self.write(": ")
self.dispatch(p)
with self.delimit("{", "}"):
keys = node.keys
interleave(
lambda: self.write(", "),
write_key_pattern_pair,
zip(keys, node.patterns),
)
rest = node.rest
if rest is not None:
if keys:
self.write(", ")
self.write("**{}".format(rest))
def visit_MatchClass(self, node):
self.set_precedence(_Precedence.ATOM, node.cls)
self.dispatch(node.cls)
with self.delimit("(", ")"):
patterns = node.patterns
interleave(lambda: self.write(", "), self.dispatch, patterns)
attrs = node.kwd_attrs
if attrs:
def write_attr_pattern(pair):
attr, pattern = pair
self.write("{}=".format(attr))
self.dispatch(pattern)
if patterns:
self.write(", ")
interleave(
lambda: self.write(", "),
write_attr_pattern,
zip(attrs, node.kwd_patterns),
)
def visit_MatchAs(self, node):
name = node.name
pattern = node.pattern
if name is None:
self.write("_")
elif pattern is None:
self.write(node.name)
else:
with self.require_parens(_Precedence.TEST, node):
self.set_precedence(_Precedence.BOR, node.pattern)
self.dispatch(node.pattern)
self.write(" as {}".format(node.name))
def visit_MatchOr(self, node):
with self.require_parens(_Precedence.BOR, node):
self.set_precedence(pnext(_Precedence.BOR), *node.patterns)
interleave(lambda: self.write(" | "), self.dispatch, node.patterns)