Documentation: never use `updated_node` to access node metadata
- Dominant language
- Python
- Stars
- 1.9k
- Forks
- 229
- PR merge metrics
- No merged PRs in 30d
Description
```py
class BugRepro(codemod.ContextAwareTransformer):
METADATA_DEPENDENCIES = (metadata.ScopeProvider,)
def leave_AnnAssign(
self, _: libcst.AnnAssign, updated_node: libcst.AnnAssign
) -> libcst.AnnAssign:
print(self.get_metadata(metadata.ScopeProvider, updated_node))
return updated_node.with_changes(target=libcst.Name("aλ1"))
class Test_MRE(codemod.CodemodTest):
TRANSFORM = BugRepro
def test_repro(self):
before = "a: int = 1"
after = "aλ1: int = 1"
self.assertCodemod(before, after)
```
* How was this snippet executed:
`python -m pytest test_main.py`
* What was expected to happen:
The test runs and succeeds, with the print statement echoing something along the lines of `metadata.GlobalScope`
* What actually happened:
The test fails, with an error related to not being able to lookup the scopage of the `libcst.AnnAssign`.
```
> if default is not _UNDEFINED_DEFAULT:
> value = self.metadata[key].get(node, default)
> else:
> value = self.metadata[key][node]
KeyError: AnnAssign(
target=Name(
value='a',
lpar=[],
rpar=[],
),
annotation=Annotation(
annotation=Name(
value='int',
lpar=[],
rpar=[],
),
whitespace_before_indicator=SimpleWhitespace(
value='',
),
whitespace_after_indicator=SimpleWhitespace(
value=' ',
),
),
value=Integer(
value='1',
lpar=[],
rpar=[],
),
equal=AssignEqual(
whitespace_before=SimpleWhitespace(
value=' ',
),
whitespace_after=SimpleWhitespace(
value=' ',
),
),
semicolon=MaybeSentinel.DEFAULT,
)
```
This happens similarly for `PositionProvider` , and presumably for all metadata providers and all derivates of `libcst.CSTNode`.
Without reading into it too much, I assume that some copying takes place after calculating the metadata for the passed `Module`, which causes lookups to fail as they are driven by object identity?
Stepping into the `leave_AnnAssign` method reveals that there is a suitable `libcst.AnnAssign` node stored in the metadata from `ScopeProvider`, but the lookup will fail nonetheless.
Of course, perhaps I am simply approaching this wrong, and would be glad to correct any bug I have introduced here!
* Versions:
```
λ python
Python 3.10.9 (main, Dec 19 2022, 17:35:49) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import libcst
>>> libcst._version.version
'0.4.9'
```
Contributor guide
Assessment
This issue has not been assessed yet.