Package: refex
Refex - refactoring expressionsRefex is a syntactically aware search-and-replace tool for Python, which allows you to specify code searches and rewrites using templates, or a
more complexClang-LibASTMatcher-like
matcher interface.ExamplesAutomatic parenthesis insertion:Refex will automatically insert parentheses
to preserve the intended code structure:$echo"a = b.foo() * c">test.py
$refex--mode=py.expr'$x.foo()'--sub='$x.foo() + 1'-itest.py
...
$cattest.pya=(b.foo()+1)*cA naive regular expression replacement would have resulted inb.foo() + 1 * c, which is not
equivalent, and is unrelated to the intended replacement.Paired parentheses:Refex is aware of the full syntax tree, and will always match parentheses correctly:$echo"print(foo(bar(b))">test.py
$refex--mode=py.expr'foo($x)'--sub='foo($x + 1)'-itest.py
...
$cattest.pya=print(foo(bar(b)+1))Here, a naive replacement using regular expressions could have resulted in
eitherprint(foo(bar(b)) + 1)orprint(foo(bar(b) + 1)), depending on
whether$xwas matched greedily or non-greedily.Combining replacements:you can pass multiple search/replace pairs to
Refex which combine to do more complex rewrites. For example:# Rewrites "self.assertTrue(x == False)" to "self.assertFalse(x)", even though# that was not explicitly called out.refex--mode=py.expr-i--iterate\--match='self.assertTrue($x == $y)'--sub='self.assertEqual($x, $y)'\--match='self.assertEqual($x, False)'--sub='self.assertFalse($x)'\-Rdir/TODO: also describe--mode=py.Getting startedInstallationRefex can be run viapipxfor one-off use
with control over the Python version:$pipxrunrefex--helpFor longer-term use, or for use of Refexas a library,
it is also pip-installable:$python3-mvenvmy_env
$sourcemy_env/bin/activate
$pipinstallrefex
$refex--helpUseThe template syntax is almost exactly what it looks like, so the examples at the
top of this page, in combination with the--helpoutput, are intended to be
enough to get started.For more details on the template syntax, seePython Patterns and Templates. For details on how to use refex in your own code as a library, seeUsing Refex as a Library.Current statusStable:The APIs documented athttps://refex.readthedocs.io/are expected to remain
mostly the same, except for trivial renames and moves.These command-line interfaces are expected to remain roughly the same, without
backwards-incompatible changes:--mode=py.expr--mode=fix--mode=reUnstableAll undocumented APIs (especiallythe API for creating a new matcher).--mode=py.stmtis missing many safety and convenience features.--mode=py, the matcher interface, will eventually need some fairly large
restructuring to make it O(n), although simple uses should be unaffected.(Also, all the stable parts are unstable too. This isn't a promise, just an
expectation/statement of intent.)ContributingSee thecontribution guideSee Alsoasttokens: the token-preserving
AST library that Refex is built on top of.Pasta: a code rewriting tool using AST
mutation instead of string templates.Semgrep: cross-language AST
search using a similar approach.lib2to3: the
standard library's code rewriting tool based on the concrete syntax tree.DisclaimerYou may have noticed Google copyright notices. This is not an officially
supported Google product.