`QualifiedNameProvider` assigns incorrect qualname to return value from a decorator
- 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
Assessment
This issue has not been assessed yet.