Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation: never use updated_node to access node metadata #882

Open
bengsparks opened this issue Mar 4, 2023 · 1 comment
Open

Documentation: never use updated_node to access node metadata #882

bengsparks opened this issue Mar 4, 2023 · 1 comment
Labels
documentation Improvements or additions to documentation

Comments

@bengsparks
Copy link

bengsparks commented Mar 4, 2023

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'
@bengsparks
Copy link
Author

Upon further inspection, it becomes clear this behavior stems from calling self.get_metadata with updated_node , which is a copy of the original_node argument, and therefore cannot be found in the metadata maps.
This behavior is kind of intuitive, and can be inferred from the LibCST documentation:

The original_node parameter on any leave_<Node> method is provided for bookkeeping and is guaranteed to be equal via == and is checks to the node parameter in the corresponding visit_<Node> method.

However, the tutorial for accessing metadata only shows how to load metadata within a cst.CSTVisitor, where such a mistake cannot occur due to immutability.
The same goes for the documentation for accessing metadata.

Perhaps this would be a suitable opportunity to extend the documentation on these pages to underline that updated_node cannot be used for metadata lookups, even when no changes have been made to the CST?

@zsol zsol added the documentation Improvements or additions to documentation label May 25, 2023
@zsol zsol changed the title Unable to retrieve metadata in codemod.ContextAwareTransformer Documentation: never use updated_node to access node metadata May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants