Package: pyrefact
pyrefactPyrefact does advanced python refactoring, with the goal of simplifying complicated code, deleting dead code, and improving performance.Unlike emerging AI tools, pyrefact is entirely rule based and does not share your code with any third parties. Pyrefact can however break your code in some cases, and is not suitable for CI or other automated workflows.FeaturesReadabilityMove common code inif/elseblocks before or after theif/else.De-indent code with earlycontinueandreturnstatements.Simplify boolean expressions.Replace for loops with immediateifconditions withfilter.Remove commented code.Move code into primitive functions.Replace loops that only fill up lists, dicts or sets with comprehensions.Invertif/elseto put the smaller block first.Rename variables, functions and classes with conventions.Rewrite defaultdict-like use of dictionaries withcollections.defaultdict().Formats lines that are longer than 100 characters withblack.Put overused constant expressions in variables.Remove redundancies and improve definitions of lists, sets, dicts.Useisinstead of==for comparisons toNone,TrueandFalse.PerformanceReplacesumcomprehensions and for loops with constant expressions. The symbolic algebra toolSympyis used under the hood.Replace hardcoded inlined collections and comprehensions with set or generator equivalents in places where that would improve performance.Replacesorted()[:n]withheapq.nsmallest, replacesorted()[0]withmin.Replace matrix operation comprehensions with equivalentnp.matmul()andnp.dot()calls, for code that already depends on numpy.Replace pandas .loc[], .iloc[] and .iterrows() with .at[], .iat[] and .itertuples()/.index where appropriate.Move constant code in loops before the loops.De-interpolate interpolated logging calls.Removing dead and useless codeDelete unused functions, classes and variables.Remove most pointless simple statements.Remove branches of code that obviously do nothing useful.Remove unreachable code.Rename unused variables to_.Delete variables named_, unless where that would cause a syntax error.Remove redundant chained calls involvingsorted(),set(),tuple(),reversed(),iter()andlist().Remove duplicate function definitions.Remove redundant elif and else.Remove unusedselfandclsfunction arguments, and add@staticmethodor@classmethod.Move functions decorated with@staticmethodoutside of their class namespaces.Simplify deterministicif,elifandelsestatements.ImportsDelete unused imports.Refactor star imports (e.g.from pathlib import *) to normal imports (e.g.from pathlib import Path)Move builtin and otherwise safe imports to toplevel.Replace indirect imports with direct imports, in cases where a name is imported from a file that also imports that name. Exceptions exists for__init__.pyfiles, and files that define__all__.Merge or remove duplicate or partially duplicate importsBreak out stacked plain imports to individual linesAdd missing imports by guessing what you probably wanted.For example, ifSequenceis used but never defined, it will insertfrom typing import Sequenceat the top of the file.Pattern-matchingPyrefact supports pattern-matching analogous to Python's builtinrelibrary:>>>frompyrefactimportpattern_matching>>>source="""... x = 1... y = "asdf"... """>>>pattern="x = 1">>>list(pattern_matching.finditer(pattern,source))[Match(span=Range(start=1,end=6),source='\nx = 1\ny = "asdf"\n',groups=(<ast.Assignobjectat0x1015f38e0>,))]>>>pattern_matching.findall(pattern,source)['x = 1']>>>pattern_matching.sub(pattern,"x = 33 - x",source)'\nx = 33 - x\ny = "asdf"\n'>>>pattern_matching.search(pattern,source)Match(span=Range(start=1,end=6),source='\nx = 1\ny = "asdf"\n',groups=(<ast.Assignobjectat0x103acaf20>,))Pattern-matching can also be used from the command-line:python-mpyrefact.pattern_matchingfind"x = {{value}}"/path/to/filename.py
python-mpyrefact.pattern_matchingreplace"x = {{value}}""x = 1 - {{value}} ** 3"/path/to/filename.pyInstallationPyrefact can be installed with pip, and works on Python 3.8 or newer:pipinstallpyrefactUsageThe--preserveflag lets you define places where code is used. When this is set, pyrefact will try to keep these usages intact.
The--safeflag will entirely prevent pyrefact from renaming or removing code.
The--from-stdinflag will format code recieved from stdin, and output the result to stdout.pipinstallpyrefact
pyrefact/path/to/filename.py--preserve/path/to/module/where/filename/is/used
pyrefact/path/to/filename.py--safe
cat/path/to/filename.py|pyrefact--from-stdinIt is possible to disable pyrefact for a given file by adding a comment withpyrefact: skip_fileanywhere in the file, as donehere.ContributingTo contribute to Pyrefact, please viewCONTRIBUTING.mdVS Code ExtensionPyrefact is also available as a VS Code extension, simply namedPyrefact. The extension allows you to use pyrefact as your formatter, similar to how other formatting extensions work.Pyrefact always runs with the--safeflag when used through the VS Code extension.The extension is published through theVS Code Marketplace, and the source code is available atpyrefact-vscode-extension.PrerequisitesPyrefact is tested on CPython 3.8, 3.9, 3.10, 3.11 and 3.12, and on Windows, MacOS and Linux. Pyrefact is also tested on PyPy3.10.PyPy tests may be removed in the future, seehttps://github.com/OlleLindgren/pyrefact/issues/25. I will add tests for new CPython versions when they enter alpha, and remove tests when they become EOL, along with any special logic in place to support those versions.