Instagram / LibCST

A concrete syntax tree parser and serializer library for Python that preserves many aspects of Python's abstract syntax tree
https://libcst.readthedocs.io/
Other
1.57k stars 192 forks source link

Unexpected `ExpressionContext.LOAD` for names of keyword arguments #1217

Open Zac-HD opened 1 month ago

Zac-HD commented 1 month ago
import ast

import libcst as cst
from libcst.metadata import ExpressionContextProvider

src = "fn(kwarg=1)"
print(ast.dump(ast.parse(src).body[0].value, indent=4))

wrapper = cst.metadata.MetadataWrapper(cst.parse_module(src))
for node, ctx in wrapper.resolve(ExpressionContextProvider).items():
    print(ctx, node)
Call(
    func=Name(id='fn', ctx=Load()),
    args=[],
    keywords=[
        keyword(
            arg='kwarg',
            value=Constant(value=1))])

ExpressionContext.LOAD Name(
    value='fn',
    lpar=[],
    rpar=[],
)
ExpressionContext.LOAD Name(
    value='kwarg',         # <---- does not match the behavior of the AST module
    lpar=[],
    rpar=[],
)

This came up while I was working on https://github.com/HypothesisWorks/hypothesis/issues/4116, i.e. trying to turn undefined unqualified names in patches into the appropriate attribute access. In that context, it's quite surprising to see array=array(...) become np.array=np.array(...)!

It was easy enough to work around this once I worked out what was happening, but I think that the reasoning here (to honor ast implementation, we don’t assign context to attr) suggests that .keyword should not be assigned context either.