summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_ast.py
diff options
context:
space:
mode:
authorBatuhan Taskaya <batuhan@python.org>2021-07-28 17:14:45 (GMT)
committerGitHub <noreply@github.com>2021-07-28 17:14:45 (GMT)
commit31bec6f1b178dadec3cb43353274b4e958a8f015 (patch)
tree007bb1ecbe4c69a0719a42076a18aa2fb8e098b6 /Lib/test/test_ast.py
parent53b9458f2e9314703a5406ca817d757f1509882a (diff)
downloadcpython-31bec6f1b178dadec3cb43353274b4e958a8f015.zip
cpython-31bec6f1b178dadec3cb43353274b4e958a8f015.tar.gz
cpython-31bec6f1b178dadec3cb43353274b4e958a8f015.tar.bz2
bpo-43897: AST validation for pattern matching nodes (GH24771)
Diffstat (limited to 'Lib/test/test_ast.py')
-rw-r--r--Lib/test/test_ast.py143
1 files changed, 142 insertions, 1 deletions
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 5f1ee75..925bb88 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -696,7 +696,7 @@ class AST_Tests(unittest.TestCase):
for constant in "True", "False", "None":
expr = ast.Expression(ast.Name(constant, ast.Load()))
ast.fix_missing_locations(expr)
- with self.assertRaisesRegex(ValueError, f"Name node can't be used with '{constant}' constant"):
+ with self.assertRaisesRegex(ValueError, f"identifier field can't represent '{constant}' constant"):
compile(expr, "<test>", "eval")
def test_precedence_enum(self):
@@ -1507,6 +1507,147 @@ class ASTValidatorTests(unittest.TestCase):
mod = ast.parse(source, fn)
compile(mod, fn, "exec")
+ constant_1 = ast.Constant(1)
+ pattern_1 = ast.MatchValue(constant_1)
+
+ constant_x = ast.Constant('x')
+ pattern_x = ast.MatchValue(constant_x)
+
+ constant_true = ast.Constant(True)
+ pattern_true = ast.MatchSingleton(True)
+
+ name_carter = ast.Name('carter', ast.Load())
+
+ _MATCH_PATTERNS = [
+ ast.MatchValue(
+ ast.Attribute(
+ ast.Attribute(
+ ast.Name('x', ast.Store()),
+ 'y', ast.Load()
+ ),
+ 'z', ast.Load()
+ )
+ ),
+ ast.MatchValue(
+ ast.Attribute(
+ ast.Attribute(
+ ast.Name('x', ast.Load()),
+ 'y', ast.Store()
+ ),
+ 'z', ast.Load()
+ )
+ ),
+ ast.MatchValue(
+ ast.Constant(...)
+ ),
+ ast.MatchValue(
+ ast.Constant(True)
+ ),
+ ast.MatchValue(
+ ast.Constant((1,2,3))
+ ),
+ ast.MatchSingleton('string'),
+ ast.MatchSequence([
+ ast.MatchSingleton('string')
+ ]),
+ ast.MatchSequence(
+ [
+ ast.MatchSequence(
+ [
+ ast.MatchSingleton('string')
+ ]
+ )
+ ]
+ ),
+ ast.MatchMapping(
+ [constant_1, constant_true],
+ [pattern_x]
+ ),
+ ast.MatchMapping(
+ [constant_true, constant_1],
+ [pattern_x, pattern_1],
+ rest='True'
+ ),
+ ast.MatchMapping(
+ [constant_true, ast.Starred(ast.Name('lol', ast.Load()), ast.Load())],
+ [pattern_x, pattern_1],
+ rest='legit'
+ ),
+ ast.MatchClass(
+ ast.Attribute(
+ ast.Attribute(
+ constant_x,
+ 'y', ast.Load()),
+ 'z', ast.Load()),
+ patterns=[], kwd_attrs=[], kwd_patterns=[]
+ ),
+ ast.MatchClass(
+ name_carter,
+ patterns=[],
+ kwd_attrs=['True'],
+ kwd_patterns=[pattern_1]
+ ),
+ ast.MatchClass(
+ name_carter,
+ patterns=[],
+ kwd_attrs=[],
+ kwd_patterns=[pattern_1]
+ ),
+ ast.MatchClass(
+ name_carter,
+ patterns=[ast.MatchSingleton('string')],
+ kwd_attrs=[],
+ kwd_patterns=[]
+ ),
+ ast.MatchClass(
+ name_carter,
+ patterns=[ast.MatchStar()],
+ kwd_attrs=[],
+ kwd_patterns=[]
+ ),
+ ast.MatchClass(
+ name_carter,
+ patterns=[],
+ kwd_attrs=[],
+ kwd_patterns=[ast.MatchStar()]
+ ),
+ ast.MatchSequence(
+ [
+ ast.MatchStar("True")
+ ]
+ ),
+ ast.MatchAs(
+ name='False'
+ ),
+ ast.MatchOr(
+ []
+ ),
+ ast.MatchOr(
+ [pattern_1]
+ ),
+ ast.MatchOr(
+ [pattern_1, pattern_x, ast.MatchSingleton('xxx')]
+ )
+ ]
+
+ def test_match_validation_pattern(self):
+ name_x = ast.Name('x', ast.Load())
+ for pattern in self._MATCH_PATTERNS:
+ with self.subTest(ast.dump(pattern, indent=4)):
+ node = ast.Match(
+ subject=name_x,
+ cases = [
+ ast.match_case(
+ pattern=pattern,
+ body = [ast.Pass()]
+ )
+ ]
+ )
+ node = ast.fix_missing_locations(node)
+ module = ast.Module([node], [])
+ with self.assertRaises(ValueError):
+ compile(module, "<test>", "exec")
+
class ConstantTests(unittest.TestCase):
"""Tests on the ast.Constant node type."""