fst

Version 0.2.6

Overview

This module exists in order to facilitate quick and easy high level editing of Python source in the form of an AST tree while preserving formatting. It is meant to allow you to change Python code functionality while not having to deal with the details of:

  • Operator precedence and parentheses
  • Indentation and line continuations
  • Commas, semicolons, and tuple edge cases
  • Comments and docstrings
  • Various Python version-specific syntax quirks
  • Lots more...

See Example Recipes for more in-depth examples.

>>> import fst  # pip install pfst, import fst

>>> ext_ast = fst.parse('''
... logger.info(  # just checking
...     f'not a {thing}', extra=extra,  # blah
... )'''.strip())

>>> ext_ast.f.body[0].value.insert('\nid=CID  # comment', -1, trivia=(False, False))

>>> print(fst.unparse(ext_ast))
logger.info(  # just checking
    f'not a {thing}',
    id=CID,  # comment
    extra=extra,  # blah
)

The tree is just normal AST with metadata, so if you know AST, you know FST.

>>> import ast

>>> print(ast.unparse(ext_ast))
logger.info(f'not a {thing}', id=CID, extra=extra)

fst works by adding FST nodes to existing standard Python AST nodes as an .f attribute (type-safe accessor castf() provided) which keep extra structure information, the original source, and provide the interface to format-preserving operations. Each operation through fst is a simultaneous edit of the AST tree and the source code and those are kept synchronized so that the current source will always parse to the current tree.

Index

Links

Notes

Disclaimer: You can reformat a large codebase with fst but it won't be quite as spritely as other libraries more apt to the task. The main focus of fst is not necessarily to be fast but rather easy and to handle all the weird cases of python syntax correctly so that functional code always results. Use a formatter as needed afterwards.

fst was written and tested on Python versions 3.10 through 3.14.

fst works by keeping a copy of the entire source at the root FST node of a tree and modifying this source alongside the node tree anytime an operation is performed natively. It is meant to be a drop-in replacement for the python ast module. It provices its own versions of the parse and unparse functions as well as passing through all symbols available from ast. The parse function returns the same AST tree that ast.parse() would return except augmented with fst metadata.

fst does not do any parsing of its own but rather relies on the builtin Python parser. This means you get perfect parsing but also that it is limited to the syntax of the running Python version (many options exist for running any specific verison of Python).

fst validates for parsability, not compilability. This means that for fst, *a, *b = c and def f(a, a): pass are both valid even though they are uncompilable.

The aesthetics of multiline slice operation alignment are not concretized yet. The current alignment behavior basically just aligns, not necessarily always at the place you may want, it will get more standard and controllable in the future.

If you will be playing with this module then the FST.dump() method will be your friend.

If you will be looking through the code then apologies in advance.