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.56k stars 192 forks source link

SimpleStatementLine._codegen_impl() got an unexpected keyword argument 'default_semicolon' #1209

Closed straz closed 2 months ago

straz commented 2 months ago

I seem to get an error rendering a SimpleStatementLine. Its body seems like it's fine, and I seem to be able to create an instance of SimpleStatementLine without any errors (see ssl below).

When I try to render the instance, that's when I get the error. codegen seems to be calling it with an unexpected keyword argument default_semicolon.

Am I missing a constructor parameter here?

I don't see constructor parameters anywhere in the documentation - where are these documented?

>>> import libcst as cst

>>> assignment = cst.parse_statement("self.context = context")
>>> cst.parse_module("").code_for_node(assignment)
'self.context = context\n'

>>> ssl = cst.SimpleStatementLine(body=[assignment])

>>> cst.parse_module("").code_for_node(ssl)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/straz/src/insurance_platform/src/services/adjudicator/.direnv/python-3.11/lib/python3.11/site-packages/libcst/_nodes/module.py", line 136, in code_for_node
    node._codegen(state)
  File "/Users/straz/src/insurance_platform/src/services/adjudicator/.direnv/python-3.11/lib/python3.11/site-packages/libcst/_nodes/base.py", line 300, in _codegen
    self._codegen_impl(state, **kwargs)
  File "/Users/straz/src/insurance_platform/src/services/adjudicator/.direnv/python-3.11/lib/python3.11/site-packages/libcst/_nodes/statement.py", line 458, in _codegen_impl
    _BaseSimpleStatement._codegen_impl(self, state)
  File "/Users/straz/src/insurance_platform/src/services/adjudicator/.direnv/python-3.11/lib/python3.11/site-packages/libcst/_nodes/statement.py", line 404, in _codegen_impl
    stmt._codegen(state, default_semicolon=(idx != laststmt))
  File "/Users/straz/src/insurance_platform/src/services/adjudicator/.direnv/python-3.11/lib/python3.11/site-packages/libcst/_nodes/base.py", line 300, in _codegen
    self._codegen_impl(state, **kwargs)
TypeError: SimpleStatementLine._codegen_impl() got an unexpected keyword argument 'default_semicolon'
yowoda commented 2 months ago

Well first off, libcst doesn't seem to do any children-node validation upon on node initialization which is why the constructor is valid at runtime, although at type check time, tools like pyright or mypy definitely do raise an error (I strongly recommend using a type checker with libcst). Essentially what you are doing right now is wrap a SimpleStatementLine node in another SimpleStatementLine, which given pythons grammar, is not a valid CST. Could you elaborate on what your intention is?

Also, if you want to generate code for a single node without any context in regards to the module it was defined in and the default whitespace config, you can instantiate the module like this cst.Module(body=()) instead of cst.parse_module("").

straz commented 2 months ago

Thank you. I didn't realize I was nesting two SimpleStatementLines. Removing the outer one solves my problem.

Thank you for the cst.Module(body=()) tip.

My last question: is there any documentation for constructor parameters? It would be very helpful!

I don't see constructor parameters anywhere in the documentation - where are these documented?

yowoda commented 2 months ago

Are you referring to the node constructor or what kind of parameters the codegen implementation takes?

For the former, nodes are nothing more than a dataclass, which means all the attributes you see listed on the docs page you linked can (usually) also be passed to the node constructor. For the latter: No, I don't believe they are documented explicitly since any _codegen or _codegen_impl method seems to be internal to libcst (as one can tell by their underscore prefix)