Skip to content

Fix unexpected ExpressionContext.LOAD for keyword arguments - #1478

Open
reginaldalfret wants to merge 1 commit into
Instagram:mainfrom
reginaldalfret:fix/keyword-arg-expression-context
Open

reginaldalfret wants to merge 1 commit into
Instagram:mainfrom
reginaldalfret:fix/keyword-arg-expression-context

Conversation

@reginaldalfret

Copy link
Copy Markdown

Summary

Fixes #1217.

In Python's ast module, keyword argument names in Call(func, args, keywords=[keyword(arg="kwarg", value=...)]) are plain identifiers (str), not expression nodes, and do not carry an expr_context (ast.Load, ast.Store, etc.).

In LibCST, Arg.keyword is an Optional[Name]. Previously, ExpressionContextVisitor did not implement visit_Arg. Because default traversal visits all child fields, visit_Name was invoked on Arg.keyword and mistakenly assigned ExpressionContext.LOAD to the argument name. This produced unexpected results for codemods and linters inspecting unqualified variable loads (e.g. interpreting kwarg=1 as a load of kwarg).

Changes

  1. libcst/metadata/expression_context_provider.py:
    • Added visit_Arg(self, node: cst.Arg) -> bool to ExpressionContextVisitor, ensuring only node.value is visited for expression context resolution while leaving node.keyword uncontexted (matching the rationale for Attribute.attr already documented in ExpressionContextProvider).
  2. libcst/metadata/tests/test_expression_context_provider.py:
    • Added unit test test_call_keyword_argument verifying that in fn(kwarg=x, other=1), fn and x receive ExpressionContext.LOAD, whereas kwarg and other do not receive an expression context.

Verification

  • Ran unit tests:
    python -m unittest libcst.metadata.tests.test_expression_context_provider
    python -m unittest discover -s libcst.metadata.tests
    python -m unittest discover -s libcst.matchers.tests
    All 23 tests in test_expression_context_provider, 177 tests in libcst.metadata.tests, and 144 tests in libcst.matchers.tests passed cleanly.
  • Verified formatting using ufmt check.

In Python's ast module, keyword argument names in Call nodes are
identifiers (`ast.keyword.arg`), not expression nodes, and do not
carry an expression context (`ast.expr_context`).

In LibCST, `Arg.keyword` is an `Optional[Name]`. Previously,
`ExpressionContextVisitor` did not implement `visit_Arg`, causing
the AST traversal to walk into `Arg.keyword` and mistakenly assign
`ExpressionContext.LOAD` to the argument's name.

Add `visit_Arg` to `ExpressionContextVisitor` so that only `Arg.value`
is visited for expression contexts while leaving `Arg.keyword` uncontexted,
matching the behavior documented in `ExpressionContextProvider` and
analogous to `Attribute.attr`. Add a unit regression test verifying
keyword arguments in Call expressions.

Closes Instagram#1217.

Signed-off-by: reginaldalfret <reginaldalfret@gmail.com>
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected ExpressionContext.LOAD for names of keyword arguments

1 participant