Queries
Bowler provides a "fluent" Query
API for building and executing refactoring scripts.
Each method returns the Query
object as the result, allowing you to easily chain
multiple method calls one after the other, without needing to assign the query object
to a variable or reference that variable for every method call.
Example usage of the fluent API:
(
Query()
.select_function("foo")
.rename("bar")
.diff()
)
In the example, the query object was never assigned to a variable, but you could write, build, and execute an equivalent query without the fluent API:
query = Query()
query.select_function("foo")
query.rename("bar")
query.diff()
Both styles are supported by Bowler, but all examples will prefer the fluent style for clarity and brevity.
Query Reference
Query()
.select()
.fixer()
.filter()
.modify()
.process()
.execute()
.diff()
.idiff()
.write()
.dump()
Note: Bowler's API is still in a "provisional" phase. The core concepts will likely stay the same, but individual method signatures may change as the tool matures or gains new functionality.
Query()
Create a new query object to process the given set of files or directories.
Query(
*paths: Union[str, List[str]],
python_version: int,
filename_matcher: FilenameMatcher,
)
*paths
- Accepts either individual file or directory paths (relative to the current working directory), or lists of paths, for any positional argument given. Defaults to the current working directory if no arguments given.*filename_matcher*
- A callback which returns whether a given filename is eligible for refactoring. Defaults to only matching files that end with.py
.python_version
- The 'major' python version of the files to be refactored, i.e.2
or3
. This allows the parser to handleprint
statement vs function correctly. This includes detecting use offrom __future__ import print_function
whenpython_version=2
. Default is3
.
.select()
Start a new transform using a custom selector pattern.
Subsequent calls to .filter()
or .modify()
will be attached to this transform.
For a full list of predefined selectors, as well as details on defining custom
selectors, see the Selectors reference.
query.select(pattern: str, **kwargs)
pattern
- A lib2to3 fixer pattern to select nodes in the syntax tree matching the specified elements, and capture sub-elements using the appropriate pattern syntax. May contain bracketed{keyword}
tokens to be formatted by**kwargs
.**kwargs
- Optional values to format the pattern with. Bowler will perform the equivalent ofpattern.format(**kwargs)
.
.fixer()
Start a new transform using an existing fixer class for lib2to3.
Subsequent calls to .filter()
or .modify()
will be attached to this transform.
Filters will execute before the fixer is executed, while subsequent modifiers will
execute after the fixer.
query.fixer(fx: Type[BaseFix])
fx
- A class implementing theBaseFix
protocol, with aPATTERN
attribute defining the selector and a.transform()
method to modify matched elements.
.filter()
Filter matched elements using a custom function. For a full list of predefined filters, as well as details on defining custom filters, see the Filters reference.
query.filter(callback: Callback)
callback
- The custom function to call for every matched syntax tree element. Filter functions must accept three arguments: the matched element, the dictionary of captured elements, and the filename currently being processed. A truthy return value will pass the matched element to the next filter or modifier function, while a falsey return value will short-circuit remaining filters and prevent the matched element from being modified.
.modify()
Modify matched elements using a custom function. For a full list of predefined modifiers, as well as details on defining custom modifiers, see the Modifiers reference.
query.modify(callback: Callback)
callback
- The custom function to call for every matched syntax tree element that passed all filter functions. Modifier functions must accept three arguments: the matched element, the dictionary of captured elements, and the filename currently being processed. Returned values will automatically replace the matched element in the syntax tree.
.process()
Post-process all modifications with a custom function.
query.process(callback: Processor)
callback
- The custom function to call for every "hunk" of modifications made to files by the query. Processors must accept two arguments: the current filename, and the "hunk" being applied. Each hunk is represented as a list of strings, with each string representing a single line of the unified diff for that modification. Return values ofFalse
will prevent the hunk from being applied, and any other return value will allow the hunk to be applied automatically or interactively by the user.
.execute()
Execute the current query, and generate a diff or write changes to disk.
.execute(
interactive: bool = True,
write: bool = False,
silent: bool = False,
)
interactive
- Whether the generated diff should interactively prompt the user to apply each hunk to each file. WhenTrue
, thewrite
parameter is ignored.write
- Whether diff hunks should be written to disk. WhenFalse
, diff hunks will only be echoed to stdout; whenTrue
, they will be echoed and files will be modified in place.silent
- WhenTrue
, diff hunks will not be echoed to stdout, and theinteractive
parameter is ignored.
.diff()
Alias for .execute(interactive=False, write=False)
.idiff()
Alias for .execute(interactive=True, write=False)
.write()
Alias for .execute(interactive=False, write=True, silent=True)
.dump()
Attaches a debugging function to all transforms to dump a human-readable representation of matched and captured elements to stdout, and then executes the query without writing results to disk.