Instagram / LibCST

A concrete syntax tree parser and serializer library for Python that preserves many aspects of Python's abstract syntax tree
https://libcst.readthedocs.io/
Other
1.57k stars 192 forks source link

Accessing .code attribute fails with "TypeError: CSTNode._codegen() missing 1 required positional argument: 'state'" #1172

Closed ngie-eign closed 4 months ago

ngie-eign commented 4 months ago

Note: All potentially sensitive information has been removed.

Repro

% python libcst_crashes.py
Traceback (most recent call last):
  File "libcst_crashes.py", line 11, in <module>
    output = new_py_module.code
             ^^^^^^^^^^^^^^^^^^
  File "$VENV/lib64/python3.11/site-packages/libcst/_nodes/module.py", line 116, in code
    return self.code_for_node(self)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "$VENV/lib64/python3.11/site-packages/libcst/_nodes/module.py", line 136, in code_for_node
    node._codegen(state)
  File "$VENV/lib64/python3.11/site-packages/libcst/_nodes/base.py", line 300, in _codegen
    self._codegen_impl(state, **kwargs)
  File "$VENV/lib64/python3.11/site-packages/libcst/_nodes/module.py", line 99, in _codegen_impl
    stmt._codegen(state)
TypeError: CSTNode._codegen() missing 1 required positional argument: 'state'

More details

% python -m pip freeze | grep -i cst
libcst==1.4.0
% python -V
Python 3.11.9

libcst_crashes.py.txt

ngie-eign commented 4 months ago

This code snippet was based in part on the Best Practices doc.

ngie-eign commented 4 months ago

Ok, I figured it out. The core problem was that I used the libcst.EmptyLine class instead of creating an instance of libcst.EmptyLine and mutating that. Once I did that and addressed the other issue with directly setting the .comment attribute, things just worked. I can definitely tell that this heat wave/climate change is mucking with my cognitive abilities... sighs

import libcst

input_str = open(__file__).read()

py_module = libcst.parse_module(input_str)
copyright_line = libcst.EmptyLine().with_changes(
    comment=libcst.Comment(value="# A new comment"),
)
new_py_module = py_module.with_changes(
    body=(copyright_line, *py_module.body, )
)
output = new_py_module.code
zsol commented 4 months ago

You can also just libcst.EmptyLine(comment=libcst.Comment(value="# A new comment"))