Skip to content

Commit

Permalink
Upgrade to py3.13 support
Browse files Browse the repository at this point in the history
All tests pass with an adjustment to the default behavior of gast.dump.
The changelog also mentions changes in the way nodes are created, but
it's not critical for gast.

Fix #85
  • Loading branch information
serge-sans-paille committed Jun 1, 2024
1 parent 7063ea7 commit 6e35636
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
build:
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13.0-beta.1"]
include:
- python-version: 3.6
os: ubuntu-20.04
Expand Down
17 changes: 13 additions & 4 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

import ast
import gast
import sys


if sys.version_info >= (3, 13):
def dump(node):
return gast.dump(node, show_empty=True)
else:
def dump(node):
return gast.dump(node)


class APITestCase(unittest.TestCase):
Expand Down Expand Up @@ -33,24 +42,24 @@ def test_unparse(self):
def test_dump(self):
code = 'lambda x: x'
tree = gast.parse(code, mode='eval')
dump = gast.dump(tree)
zdump = dump(tree)
norm = ("Expression(body=Lambda(args=arguments(args=[Name("
"id='x', ctx=Param(), "
"annotation=None, type_comment=None)], posonlyargs=[], "
"vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, "
"defaults=[]), body=Name(id='x', ctx=Load(), "
"annotation=None, type_comment=None)"
"))")
self.assertEqual(dump, norm)
self.assertEqual(zdump, norm)

def test_walk(self):
code = 'x + 1'
tree = gast.parse(code, mode='eval')
dump = gast.dump(tree)
zdump = dump(tree)
norm = ("Expression(body=BinOp(left=Name(id='x', ctx=Load(), "
"annotation=None, type_comment=None), op=Add(), "
"right=Constant(value=1, kind=None)))")
self.assertEqual(dump, norm)
self.assertEqual(zdump, norm)
self.assertEqual(len(list(gast.walk(tree))), 6)

def test_iter_fields(self):
Expand Down
68 changes: 38 additions & 30 deletions tests/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
import sys


if sys.version_info >= (3, 13):
def dump(node):
return gast.dump(node, show_empty=True)
else:
def dump(node):
return gast.dump(node)


class CompatTestCase(unittest.TestCase):

def __init__(self, *args, **kwargs):
Expand All @@ -29,7 +37,7 @@ def test_FunctionDef(self):
")], ctx=Load()))], decorator_list="
"[], returns=None, type_comment=None, type_params=[])], "
"type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

else:

Expand All @@ -45,7 +53,7 @@ def test_ArgAnnotation(self):
"None, defaults=[]), body=[Pass()], decorator_list=[], "
"returns=None, type_comment=None, type_params=[])], "
"type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_KeywordOnlyArgument(self):
code = 'def foo(*, x=1): pass'
Expand All @@ -58,7 +66,7 @@ def test_KeywordOnlyArgument(self):
"None, defaults=[]), body=[Pass()], decorator_list=[], "
"returns=None, type_comment=None, type_params=[])], "
"type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

if sys.version_info.minor >= 6:

Expand All @@ -74,7 +82,7 @@ def test_FormattedValue(self):
"ctx=Load(), annotation=None, type_comment=None), "
"conversion=-1, format_spec=None)]))], "
"type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_JoinedStr(self):
code = 'e = 1; f"e = {e}"'
Expand All @@ -89,7 +97,7 @@ def test_JoinedStr(self):
"annotation=None, type_comment=None), "
"conversion=-1, format_spec=None)]))], "
"type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

if sys.version_info.minor >= 8:

Expand All @@ -103,7 +111,7 @@ def test_TypeIgnore(self):
"Pass()], decorator_list=[], returns=None, "
"type_comment=None, type_params=[])], type_ignores="
"[TypeIgnore(lineno=1, tag='[excuse]')])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_PosonlyArgs(self):
code = 'def foo(a, /, b): pass'
Expand All @@ -117,7 +125,7 @@ def test_PosonlyArgs(self):
"kwarg=None, defaults=[]), body=[Pass()], "
"decorator_list=[], returns=None, type_comment=None, "
"type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_NamedExpr(self):
code = '(x := 1) '
Expand All @@ -127,7 +135,7 @@ def test_NamedExpr(self):
" ctx=Store(), annotation=None, type_comment=None), "
"value=Constant(value=1, kind=None)))], type_ignores="
"[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

if sys.version_info.minor >= 10:

Expand All @@ -142,7 +150,7 @@ def test_MatchValue(self):
"[Expr(value=Constant(value=Ellipsis, kind=None))]"
")])], type_ignores=[])"
)
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchSingleton(self):
code = 'match v:\n case None:...'
Expand All @@ -153,7 +161,7 @@ def test_MatchSingleton(self):
"match_case(pattern=MatchSingleton(value=None), "
"guard=None, body=[Expr(value=Constant(value="
"Ellipsis, kind=None))])])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchSequence(self):
code = 'match v:\n case a, b:...'
Expand All @@ -166,7 +174,7 @@ def test_MatchSequence(self):
"=None, name='b')]), guard=None, body=[Expr(value"
"=Constant(value=Ellipsis, kind=None))])])], "
"type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchMapping(self):
code = 'match v:\n case {1: a}:...'
Expand All @@ -179,7 +187,7 @@ def test_MatchMapping(self):
"=None, name='a')], rest=None), guard=None, body="
"[Expr(value=Constant(value=Ellipsis, kind=None))]"
")])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchClass(self):
code = 'match v:\n case Cls(attr=1):...'
Expand All @@ -193,7 +201,7 @@ def test_MatchClass(self):
"=[MatchValue(value=Constant(value=1, kind=None))"
"]), guard=None, body=[Expr(value=Constant(value="
"Ellipsis, kind=None))])])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchStar(self):
code = 'match v:\n case [1, *other]:...'
Expand All @@ -206,7 +214,7 @@ def test_MatchStar(self):
"MatchStar(name='other')]), guard=None, body="
"[Expr(value=Constant(value=Ellipsis, kind=None)"
")])])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchAs(self):
code = 'match v:\n case 1, other:...'
Expand All @@ -219,7 +227,7 @@ def test_MatchAs(self):
"MatchAs(pattern=None, name='other')]), guard=None"
", body=[Expr(value=Constant(value=Ellipsis, kind"
"=None))])])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_MatchOr(self):
code = 'match v:\n case 1 | 2:...'
Expand All @@ -232,7 +240,7 @@ def test_MatchOr(self):
"value=Constant(value=2, kind=None))]), guard="
"None, body=[Expr(value=Constant(value=Ellipsis, "
"kind=None))])])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)


if sys.version_info.minor >= 11:
Expand All @@ -257,7 +265,7 @@ def test_Bytes(self):
compile(gast.gast_to_ast(tree), '<test>', 'exec')
norm = ("Module(body=[Expr(value=Constant(value=b'0012', "
"kind=None))], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

# common

Expand All @@ -269,7 +277,7 @@ def test_TryExcept(self):
"type=Name(id='e', ctx=Load(), annotation=None, "
"type_comment=None), name=None, body=[Pass()])]"
", orelse=[Pass()], finalbody=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_TryExceptNamed(self):
code = 'try:pass\nexcept e as f:pass\nelse:pass'
Expand All @@ -280,7 +288,7 @@ def test_TryExceptNamed(self):
"type_comment=None), name=Name(id='f', ctx="
"Store(), annotation=None, type_comment=None), body=[Pass()])]"
", orelse=[Pass()], finalbody=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_Raise(self):
codes = ('raise Exception',
Expand Down Expand Up @@ -321,7 +329,7 @@ def test_Raise(self):
for code, norm in zip(codes, norms):
tree = gast.parse(code)
compile(gast.gast_to_ast(tree), '<test>', 'exec')
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_Call(self):
code = 'foo(x, y=1, *args, **kwargs)'
Expand All @@ -336,7 +344,7 @@ def test_Call(self):
"arg='y', value=Constant(value=1, kind=None)), keyword(arg"
"=None, value=Name(id='kwargs', ctx=Load(), annotation=None, "
"type_comment=None))]))], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_With(self):
code = 'with open("any"): pass'
Expand All @@ -347,15 +355,15 @@ def test_With(self):
"type_comment=None), args=[Constant(value='any', "
"kind=None)], keywords=[]), optional_vars=None)], body=["
"Pass()], type_comment=None)], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_TryFinally(self):
code = 'try:pass\nfinally:pass'
tree = gast.parse(code)
compile(gast.gast_to_ast(tree), '<test>', 'exec')
norm = ("Module(body=[Try(body=[Pass()], handlers=[], orelse=[], "
"finalbody=[Pass()])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_star_argument(self):
code = 'def foo(*a): pass'
Expand All @@ -367,7 +375,7 @@ def test_star_argument(self):
"kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), "
"body=[Pass()], decorator_list=[], returns=None, "
"type_comment=None, type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_keyword_argument(self):
code = 'def foo(**a): pass'
Expand All @@ -379,7 +387,7 @@ def test_keyword_argument(self):
"type_comment=None), defaults=[]), body=[Pass()], "
"decorator_list=[], returns=None, type_comment=None, "
"type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_Index(self):
code = 'def foo(a): a[1]'
Expand All @@ -393,7 +401,7 @@ def test_Index(self):
", slice=Constant(value=1, kind=None), ctx=Load()"
"))], decorator_list=[], returns=None, type_comment=None, "
"type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_ExtSlice(self):
code = 'def foo(a): a[:,:]'
Expand All @@ -408,7 +416,7 @@ def test_ExtSlice(self):
"None), Slice(lower=None, upper=None, step=None)], ctx=Load())"
", ctx=Load()))], decorator_list=[], returns=None, "
"type_comment=None, type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_ExtSlices(self):
code = 'def foo(a): a[1,:]'
Expand All @@ -423,7 +431,7 @@ def test_ExtSlices(self):
"None), Slice(lower=None, upper=None, step=None)], ctx=Load())"
", ctx=Load()))], decorator_list=[], returns=None, "
"type_comment=None, type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_Ellipsis(self):
code = 'def foo(a): a[...]'
Expand All @@ -437,7 +445,7 @@ def test_Ellipsis(self):
", slice=Constant(value=Ellipsis, kind=None), ctx=Load()))], "
"decorator_list=[], returns=None, type_comment=None, "
"type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_ExtSliceEllipsis(self):
code = 'def foo(a): a[1, ...]'
Expand All @@ -452,7 +460,7 @@ def test_ExtSliceEllipsis(self):
", Constant(value=Ellipsis, kind=None)], ctx=Load()), ctx="
"Load()))], decorator_list=[], returns=None, type_comment="
"None, type_params=[])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)


if __name__ == '__main__':
Expand Down
14 changes: 10 additions & 4 deletions tests/test_py3_12.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import gast
import sys

if sys.version_info >= (3, 13):
def dump(node):
return gast.dump(node, show_empty=True)
else:
def dump(node):
return gast.dump(node)


class Python3_12TestCase(unittest.TestCase):
Expand All @@ -24,7 +30,7 @@ def test_type_alias(self):
"type_comment=None), Name(id='float', ctx=Load(), "
"annotation=None, type_comment=None)], ctx=Load()), "
"ctx=Load()))], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_generic_type_alias(self):
code = "type Point[T] = tuple[T, float]"
Expand All @@ -38,7 +44,7 @@ def test_generic_type_alias(self):
"type_comment=None), Name(id='float', ctx=Load(), "
"annotation=None, type_comment=None)], ctx=Load()), ctx=Load()"
"))], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_generic_function(self):
code = "def foo[T]():..."
Expand All @@ -50,7 +56,7 @@ def test_generic_function(self):
"Ellipsis, kind=None))], decorator_list=[], returns=None, "
"type_comment=None, type_params=[TypeVar(name='T', "
"bound=None)])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

def test_generic_class(self):
code = "class foo[T]:..."
Expand All @@ -60,7 +66,7 @@ def test_generic_class(self):
"body=[Expr(value=Constant(value=Ellipsis, kind=None))], "
"decorator_list=[], type_params=[TypeVar(name='T', bound=None)"
"])], type_ignores=[])")
self.assertEqual(gast.dump(tree), norm)
self.assertEqual(dump(tree), norm)

if sys.version_info < (3, 12):
del Python3_12TestCase
Expand Down

0 comments on commit 6e35636

Please sign in to comment.