diff options
author | Massimiliano Culpo <massimiliano.culpo@gmail.com> | 2022-11-05 15:59:12 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-05 15:59:12 +0100 |
commit | 5558940ce6fee399155bd31be7f1c8c361691979 (patch) | |
tree | 9caf76796896087b0f1b127152996d9e891cd3fe | |
parent | c9fcb8aadc2ded5bcaa999f108f0c92213824ee2 (diff) | |
download | spack-5558940ce6fee399155bd31be7f1c8c361691979.tar.gz spack-5558940ce6fee399155bd31be7f1c8c361691979.tar.bz2 spack-5558940ce6fee399155bd31be7f1c8c361691979.tar.xz spack-5558940ce6fee399155bd31be7f1c8c361691979.zip |
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
-rw-r--r-- | .github/workflows/audit.yaml | 2 | ||||
-rw-r--r-- | .github/workflows/unit_tests.yaml | 15 | ||||
-rw-r--r-- | .github/workflows/valid-style.yml | 6 | ||||
-rw-r--r-- | lib/spack/docs/tables/system_prerequisites.csv | 2 | ||||
-rw-r--r-- | lib/spack/spack/main.py | 26 | ||||
-rw-r--r-- | lib/spack/spack/test/util/unparse/unparse.py | 74 | ||||
-rw-r--r-- | lib/spack/spack/util/unparse/unparser.py | 92 |
7 files changed, 195 insertions, 22 deletions
diff --git a/.github/workflows/audit.yaml b/.github/workflows/audit.yaml index 5b463a3e0c..275abb2d53 100644 --- a/.github/workflows/audit.yaml +++ b/.github/workflows/audit.yaml @@ -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: | diff --git a/.github/workflows/unit_tests.yaml b/.github/workflows/unit_tests.yaml index 80b4593c23..6a21d166f8 100644 --- a/.github/workflows/unit_tests.yaml +++ b/.github/workflows/unit_tests.yaml @@ -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 diff --git a/.github/workflows/valid-style.yml b/.github/workflows/valid-style.yml index d91f6e958a..a82c786b44 100644 --- a/.github/workflows/valid-style.yml +++ b/.github/workflows/valid-style.yml @@ -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' diff --git a/lib/spack/docs/tables/system_prerequisites.csv b/lib/spack/docs/tables/system_prerequisites.csv index 5f661883d3..af8dcafffa 100644 --- a/lib/spack/docs/tables/system_prerequisites.csv +++ b/lib/spack/docs/tables/system_prerequisites.csv @@ -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 diff --git a/lib/spack/spack/main.py b/lib/spack/spack/main.py index 4c3f19d75d..a9a9d20df7 100644 --- a/lib/spack/spack/main.py +++ b/lib/spack/spack/main.py @@ -343,17 +343,21 @@ class SpackArgumentParser(argparse.ArgumentParser): 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) - - # 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) + 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] + + 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) diff --git a/lib/spack/spack/test/util/unparse/unparse.py b/lib/spack/spack/test/util/unparse/unparse.py index 49009ae98e..82148c9dc8 100644 --- a/lib/spack/spack/test/util/unparse/unparse.py +++ b/lib/spack/spack/test/util/unparse/unparse.py @@ -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) diff --git a/lib/spack/spack/util/unparse/unparser.py b/lib/spack/spack/util/unparse/unparser.py index a46d19fa76..c204aea25a 100644 --- a/lib/spack/spack/util/unparse/unparser.py +++ b/lib/spack/spack/util/unparse/unparser.py @@ -1243,3 +1243,95 @@ class Unparser: 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) |