You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PEP-695: Potentially breaking changes made to __match_args__ attributes of AST nodes #104799
importastdeftest(node):
matchnode:
caseast.FunctionDef("foo", ast.arguments(args=[ast.arg("bar")])):
print('matched! :)')
case _:
print("Didn't match :(")
source=ast.parse("def foo(bar): pass")
node=source.body[0]
assertisinstance(node, ast.FunctionDef)
test(node)
Running this script on 3.11 gets you this output:
>python repro.py
matched! :)
Running this script on CPython main, however, gets you this output:
>python repro.py
Didn't match :(
The reason for this is that the implementation of PEP-695 (new in Python 3.12) added a number of new AST nodes to Python, and as a result, the __match_args__ attributes of ast.FunctionDef, ast.AsyncFunctionDef and ast.ClassDef are all different on 3.12 compared to what they were on 3.11.
This feels like it has the potential to be quite a breaking change for people using pattern-matching to parse ASTs. It would probably be okay if type_params had been added as the final item in the __match_args__ tuples, but at the moment it comes in second place.
Nice catch. Even though the AST has murky stability guarantees, I agree that the right thing to do here is to move the new arguments to the "end" (in the AST def, which generates both the constructor and __match_args__). That way, we can gracefully handle anybody matching on or building these nodes.
Reacted by Alex Waygood, Kirill Podoprigora, Carl Meyer and sobolevn
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in make
TypeError: required field "type_params" missing from FunctionDef
I'm not sure this is fixable without bigger changes to how we generate the AST classes.
I suspect of 2 breaking changes match args vs building ast nodes, the latter is more common. Especially as matching ast node I would expect to commonly use node visitor. It does produce a good number of hits
This is small fix to upgrade as I’d guess most of time empty type params is fix. And unsure AST typical compatibility expectation as seems like any new attribute would trigger this. Were there similar ast incompatibilities in last couple minor releases?
FWIW, while it would be ideal if we could avoid both, I think the pattern-matching breakage is worse than the direct-construction breakage. Calls to the constructors of these classes will immediately raise an exception on 3.12, so it will be immediately obvious what the cause of the breakage is, and how to fix it. But if you have a function like the one in my opening comment for this issue, it won't start raising an exception on 3.12 -- it will just silently start doing the wrong thing. That could make it hard for users to track down where the bug is, and what they need to do to fix it.
^EDIT: That rationale is all misguided; @JelleZijlstra corrected me below.
Not sure if I should make a new issue for this as it seems related. While #104834 seems to have fixed the issue for compile and presumably match, ast.unparse at least still requires "type_params" in 3.12.0b2
The original version with compile now works, but using unparse you still get the error.
Should be fixed now following #105846 — @DavidCEllis let us know if anything else isn't working as you'd expect!
I ran into this as a bunch of tests that were fine against some of the alphas were failing on the first beta. Looking up the error message took me to the first patch. Waiting and retesting on 3.12.0b2 had most of them passing again apart from the ones that used unparse.
Activity
brandtbucher commentedon May 23, 2023
Nice catch. Even though the AST has murky stability guarantees, I agree that the right thing to do here is to move the new arguments to the "end" (in the AST def, which generates both the constructor and
__match_args__). That way, we can gracefully handle anybody matching on or building these nodes.pythongh-104799: Move location of type_params AST fields
JelleZijlstra commentedon May 24, 2023
Submitted a PR. There is still a compatibility break when you create a FunctionDef node. Consider this code:
On 3.11 this works.
On main I get:
I'm not sure this is fixable without bigger changes to how we generate the AST classes.
hmc-cs-mdrissi commentedon May 24, 2023
I suspect of 2 breaking changes match args vs building ast nodes, the latter is more common. Especially as matching ast node I would expect to commonly use node visitor. It does produce a good number of hits
This is small fix to upgrade as I’d guess most of time empty type params is fix. And unsure AST typical compatibility expectation as seems like any new attribute would trigger this. Were there similar ast incompatibilities in last couple minor releases?
JelleZijlstra commentedon May 24, 2023
#104834 is a suggested way to restore compatibility for creation of AST nodes. It's more invasive, though, so not sure it's a good idea.
AlexWaygood commentedon May 24, 2023
@hmc-cs-mdrissi, pattern-matching works very well in combination with an
ast.NodeVisitorsubclass! I do this intypeshed-stats: https://github.com/AlexWaygood/typeshed-stats/blob/c01af7517d23678a1e1050640a1934dcc1b8284d/src/typeshed_stats/gather.py#L105-L132.FWIW, while it would be ideal if we could avoid both, I think the pattern-matching breakage is worse than the direct-construction breakage. Calls to the constructors of these classes will immediately raise an exception on 3.12, so it will be immediately obvious what the cause of the breakage is, and how to fix it. But if you have a function like the one in my opening comment for this issue, it won't start raising an exception on 3.12 -- it will just silently start doing the wrong thing. That could make it hard for users to track down where the bug is, and what they need to do to fix it.^EDIT: That rationale is all misguided; @JelleZijlstra corrected me below.
My preference would be:
type_paramsnode to the end (in the AST def), as gh-104799: Move location of type_params AST fields #104828 proposes.JelleZijlstra commentedon May 24, 2023
That's not true. The AST node constructors accept almost anything, you only get errors later when you use the node, and then only if you're lucky.
AlexWaygood commentedon May 24, 2023
Oh, sorry. I misread/misunderstood your previous comment. My bad — that seems worse, in that case :)
But my opinion would still be "definitely do the easier thing, maybe also do the more invasive thing as well".
gh-104799: Move location of type_params AST fields (#104828)
pythongh-104799: Move location of type_params AST fields (pythonGH-10…
JelleZijlstra commentedon May 26, 2023
Seems like the fix changes the ABI. Please comment on #104974 if you have insights into whether we should change the ABI here.
4 remaining items
AlexWaygood commentedon Jun 4, 2023
I think this is now fixed. Thanks @JelleZijlstra!
DavidCEllis commentedon Jun 12, 2023
Not sure if I should make a new issue for this as it seems related. While #104834 seems to have fixed the issue for compile and presumably match,
ast.unparseat least still requires "type_params" in 3.12.0b2The original version with compile now works, but using
unparseyou still get the error.3.11.4
3.12.0b2 (3.12-dev from this morning also)
Adding
type_params=[]to the functiondef prevents the error but it looked like that was supposed to be made the default with the patch?pythongh-104799: PEP 695 backward compatibility for ast.unparse
JelleZijlstra commentedon Jun 16, 2023
Thanks @DavidCEllis, fixing this in #105846.
gh-104799: PEP 695 backward compatibility for ast.unparse (#105846)
pythongh-104799: PEP 695 backward compatibility for ast.unparse (pyth…
[3.12] gh-104799: PEP 695 backward compatibility for ast.unparse (GH-…
AlexWaygood commentedon Jun 16, 2023
Should be fixed now following #105846 — @DavidCEllis let us know if anything else isn't working as you'd expect!
Merge branch 'main' into modulelocals
DavidCEllis commentedon Jun 16, 2023
I ran into this as a bunch of tests that were fine against some of the alphas were failing on the first beta. Looking up the error message took me to the first patch. Waiting and retesting on 3.12.0b2 had most of them passing again apart from the ones that used unparse.
It looks like they all now pass against a new 3.12-dev build - Thanks @JelleZijlstra and @AlexWaygood !
JelleZijlstra commentedon Jun 16, 2023
Thanks! You might be interested in #105858 which will hopefully provide a more general solution; let me know on that issue if you have any feedback.
pythongh-104799: PEP 695 backward compatibility for ast.unparse (pyth…