Instagram / Instagram/LibCST

`QualifiedNameProvider` assigns incorrect qualname to return value from a decorator

Open
#437 0 comments 0 reactions 0 assignees View on GitHub
codemod
Dominant language
Python
Stars
1.9k
Forks
229
PR merge metrics
No merged PRs in 30d

Description

This is probably easier to explain with a demo that I extracted from https://github.com/HypothesisWorks/hypothesis/pull/2712

```python
import libcst as cst
from libcst.codemod import VisitorBasedCodemodCommand

code = """
from example import decorator
decorator()(lambda x: x)
"""

class FixPositionalKeywonlyArgs(VisitorBasedCodemodCommand):
DESCRIPTION = "Demonstrate potential qualname resolution bug."
METADATA_DEPENDENCIES = (cst.metadata.QualifiedNameProvider,)

def leave_Call(self, original_node, updated_node):
# Collect the qualified names for this Call node. If it's not exactly
# "example.decorator", return without modifying anything.
metadata = self.get_metadata(cst.metadata.QualifiedNameProvider, original_node)
if {qn.name for qn in metadata} != {"example.decorator"}:
return updated_node

# So at this point, given the `decorator()(lambda x: x)` input,
# we should have no args. However, we DO have args, because the
# the *return value of example.decorator* is given the same qualname!
assert not updated_node.args, updated_node

# Return the good call node; the other will fail above
return updated_node

if __name__ == "__main__":
transformer = FixPositionalKeywonlyArgs(cst.codemod.CodemodContext())
transformer.transform_module(cst.parse_module(code))
```

I have no idea what's happening here... for now I'm just checking `m.matches(updated_node, m.Call(func=m.DoesNotMatch(m.Call())))` as a workaround, but it would be great to get confirmation that I've either found a bug or done something wrong.

And I should also say thanks for LibCST! Writing codemods is way easier, and way more fun, than I had expected 🥰

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.