Code formatting#
pw_presubmit: Python tools for running presubmit checks and linters
The pw format command provides a unified experience for checking and fixing
code formatting for a variety of languages used in Pigweed. It automatically
detects which formatters to apply based on file extensions and names.
Features#
Check vs. fix: Run in check-only mode with
--checkto find errors without modifying files.Targeted formatting: Format specific files or directories by passing them as arguments.
Only format modified files: By default, only formats the files that have been modified in the last change (or since the upstream tracking branch, if set). Use
--fullto format all files in a repo.Automatic configuration: Discovers and uses project-specific formatter configurations like
.clang-format,.black.toml, andrustfmt.toml.Parallel execution: Speed up formatting with the
-jor--jobsflag to run on multiple files in parallel.Unified experience: Regardless of what files you format, you’ll always have a consistent CLI experience.
Language support:
File type |
Flag |
Enabled by default |
Bazel build files |
|
✅ |
C/C++ |
|
✅ |
CMake |
|
✅ |
CSS |
|
✅ |
GN build files |
|
❌ |
Go |
|
❌ |
Java |
|
✅ |
JavaScript |
|
❌ |
JSON |
|
✅ |
Markdown |
|
✅ |
OWNERS files |
|
✅ |
Protobuf |
|
✅ |
Python (using |
|
✅ |
reStructuredText |
|
✅ |
Rust |
|
❌ |
Starlark |
|
✅ |
TypeScript |
|
❌ |
Get started#
The formatter is usually invoked via the pw entry point at the root of your
project.
Usage examples#
# Fix formatting for all files.
$ ./pw format
# Check formatting for all files in the repository without making
# modifications.
$ ./pw format --check
# Format all files tracked by Git.
$ ./pw format --all
# Format specific files or directories.
$ ./pw format pw_foo/ public/pw_foo/foo.h
Project setup#
Pigweed’s default formatter is designed to work out-of-the-box for most Bazel projects. You can try it with no additional setup setups with the following command:
$ bazel run @pigweed//pw_presubmit/py:format
Add a shortcut#
To make running the formatter easier, add the format to a Workflow
shortcut. See the Workflows
Get Started guide for more
info.
Enable additional formatters#
Some formatters that may not be interesting to most projects are disabled by
default, and may be enabled by adding flags to your project’s .bazelrc
file:
# Enable GN build file formatting.
common --@pigweed//pw_presubmit/py:enable_gn_formatter=True
Note
Enabling additional formatters will cause more tooling to be downloaded.
API reference#
Note
b/326309165: While the pw format command interface is very stable,
the pw_presubmit.format library is a work-in-progress effort to detach
the implementation of pw format from the pw_presubmit
module. Not all formatters are migrated, and the library API is unstable.
After some of the core pieces land, this library will be moved to
pw_code_format.
Core#
Formatting library core.
- pw_presubmit.format.core.DiffCallback
The callback type for producing diffs.
- Arugments:
path: File path of the file being diffed. original: The contents of the original file, as a string. formatted: The contents of the formatted file, as a string.
- Returns:
A human readable diff as a string.
alias of
Callable[[Path,str,str],str]
- class pw_presubmit.format.core.FileChecker(*, file_patterns: ~pw_cli.file_filter.FileFilter, mnemonic: str, tool_runner: ~pw_cli.tool_runner.ToolRunner = <pw_cli.tool_runner.BasicSubprocessRunner object>, diff_tool: ~typing.Callable[[~pathlib.Path, str, str], str] = <function simple_diff>)
Abstract class for a code format check tool.
This class does not have the ability to apply formatting to files, and instead only allows in-memory checks to produce expected resulting diffs.
- file_patterns
A
pw_cli.file_filter.FileFilterthat describes what kind of files this check applies to.
- mnemonic
A human-readable description of the kind of checker this is (e.g. “C and C++”, “Bazel”, “Python (black)”).
- tool_runner
The
pw_presubmit.format.core.ToolRunnerto use when calling out to subprocesses.
- diff_tool
The
pw_presubmit.format.core.DiffCallbackto use when producing formatting diffs.
- __init__(*, file_patterns: ~pw_cli.file_filter.FileFilter, mnemonic: str, tool_runner: ~pw_cli.tool_runner.ToolRunner = <pw_cli.tool_runner.BasicSubprocessRunner object>, diff_tool: ~typing.Callable[[~pathlib.Path, str, str], str] = <function simple_diff>)
- abstract format_file_in_memory(
- file_path: Path,
- file_contents: bytes,
Returns the formatted version of a file as in-memory bytes.
file_pathandfile_contentrepresent the same file. Both are provided for convenience. Usefile_pathif you can do so without modifying the file, or usefile_contentsif the formatting tool provides a mechanism for formatting the file by piping it to stdin.Any subprocess calls should be initiated with
self.run_tool()to enable testing and injection of tools and tool wrappers.WARNING: A
pw_presubmit.format.core.FileCheckermust never modify the file at``file_path``.- Returns:
A populated
pw_presubmit.format.core.FormattedFileContentsthat contains either the result of formatting the file, or an error message.
- get_formatting_diff(file_path: Path, dry_run: bool = False) FormattedDiff | None
Returns a diff comparing a file to its formatted version.
If
dry_runisTrue, the diff will always beNone.- Returns:
Noneif there is no difference after formatting OR ifdry_runis enabled. Otherwise, apw_presubmit.format.core.FormattedDiffis returned containing either a diff or an error.
- get_formatting_diffs(
- paths: Iterable[Path],
- dry_run: bool = False,
Checks the formatting of many files without modifying them.
This method may be overridden to optimize for formatters that allow checking multiple files in a single invocation, though you may need to do additional parsing to produce diffs or error messages associated with each file path.
- Returns:
An iterator of
pw_presubmit.format.core.FormattingDiffobjects for each file with identified formatting issues.
- class pw_presubmit.format.core.FileFormatter(**kwargs)
Abstract class for a code format fix tool.
- __init__(**kwargs)
- abstract format_file(file_path: Path) FormatFixStatus
Formats the provided file in-place.
Any subprocess calls should be initiated with
self.run_tool()to enable testing and injection of tools and tool wrappers.- Returns:
A FormatFixStatus that contains relevant errors/warnings.
- format_files(
- paths: Iterable[Path],
- keep_warnings: bool = True,
Formats the provided files and fixes them in-place.
All files must be updated to contain the formatted version. If errors are encountered along the way, they should be collected and returned as a dictionary that maps the path of the file to a string that describes the errors encountered while processing that file.
Any subprocess calls should be initiated with
self.run_tool()to enable testing and injection of tools and tool wrappers.This method may be overridden to optimize for formatters that allow formatting multiple files in a single invocation, though you may need to do additional parsing to associate error messages with the paths of the files that produced them.
- Returns:
An iterator of
Pathandpw_presubmit.format.core.FormatFixStatuspairs for each file that was not successfully formatted. Ifkeep_warningsisTrue, any successful format operations with warnings will also be returned.
- class pw_presubmit.format.core.FormatFixStatus(ok: bool, error_message: str | None)
The status of running a code formatter in-place on a file.
This type is returned by in-place formatting fix operations.
- ok
A boolean indicating whether or not formatting was successful.
- Type:
bool
- error_message
A string containing any errors or warnings produced by the formatting process.
- Type:
str | None
- __init__(ok: bool, error_message: str | None) None
- class pw_presubmit.format.core.FormattedDiff(ok: bool, diff: str, error_message: str | None, file_path: Path)
The resulting diff of applying a code formatter to a file.
- ok
A boolean indicating whether or not formatting was successful.
- Type:
bool
- diff
The resulting diff of applying code formatting, as a human-readable string.
- Type:
str
- error_message
A string containing any errors or warnings produced by the formatting process.
- Type:
str | None
- file_path
The path of the corresponding file that produced this diff.
- Type:
pathlib.Path
- __init__(ok: bool, diff: str, error_message: str | None, file_path: Path) None
- class pw_presubmit.format.core.FormattedFileContents(ok: bool, formatted_file_contents: bytes, error_message: str | None)
The result of running a code formatter on the contents of a file.
This type is returned by in-memory formatting check operations.
- ok
A boolean indicating whether or not formatting was successful.
- Type:
bool
- formatted_file_contents
The contents of the resulting formatted file as bytes.
- Type:
bytes
- error_message
A string containing any errors or warnings produced by the formatting process.
- Type:
str | None
- __init__(ok: bool, formatted_file_contents: bytes, error_message: str | None) None
- pw_presubmit.format.core.simple_diff(path: Path, original: str, formatted: str) str
Produces a diff of the contents of two files.
Formatters#
- class pw_presubmit.format.bazel.BuildifierFormatter(warnings_to_fix: Sequence[str] = ('load', 'native-build', 'unsorted-dict-items'), **kwargs)
A formatter that runs
buildifieron files.- __init__(warnings_to_fix: Sequence[str] = ('load', 'native-build', 'unsorted-dict-items'), **kwargs)
- format_file(file_path: Path) FormatFixStatus
Formats the provided file in-place using
buildifier.- Returns:
A FormatFixStatus that contains relevant errors/warnings.
- format_file_in_memory(
- file_path: Path,
- file_contents: bytes,
Uses
buildifierto check the formatting of the requested file.The file at
file_pathis NOT modified by this check.- Returns:
A populated
pw_presubmit.format.core.FormattedFileContentsthat contains either the result of formatting the file, or an error message.
- format_files(
- paths: Iterable[Path],
- keep_warnings: bool = True,
Uses
buildifierto format the specified files in-place.- Returns:
An iterator of
Pathandpw_presubmit.format.core.FormatFixStatuspairs for each file that was not successfully formatted. Ifkeep_warningsisTrue, any successful format operations with warnings will also be returned.
- class pw_presubmit.format.cpp.ClangFormatFormatter(tool_flags: Sequence[str] = ('--style=file',), **kwargs)
A formatter that runs clang-format on files.
- __init__(tool_flags: Sequence[str] = ('--style=file',), **kwargs)
- format_file(file_path: Path) FormatFixStatus
Formats the provided file in-place using
clang-format.- Returns:
A FormatFixStatus that contains relevant errors/warnings.
- format_file_in_memory(
- file_path: Path,
- file_contents: bytes,
Uses
clang-formatto check the formatting of the requested file.The file at
file_pathis NOT modified by this check.- Returns:
A populated
pw_presubmit.format.core.FormattedFileContentsthat contains either the result of formatting the file, or an error message.
- format_files(
- paths: Iterable[Path],
- keep_warnings: bool = True,
Uses
clang-formatto format the specified files in-place.- Returns:
An iterator of
Pathandpw_presubmit.format.core.FormatFixStatuspairs for each file that was not successfully formatted. Ifkeep_warningsisTrue, any successful format operations with warnings will also be returned.
- class pw_presubmit.format.gn.GnFormatter(tool_flags: Sequence[str] = (), **kwargs)
A formatter that runs gn format on files.
- __init__(tool_flags: Sequence[str] = (), **kwargs)
- format_file(file_path: Path) FormatFixStatus
Formats the provided file in-place using
gn format.- Returns:
A FormatFixStatus that contains relevant errors/warnings.
- format_file_in_memory(
- file_path: Path,
- file_contents: bytes,
Uses
gn formatto check the formatting of the requested file.The file at
file_pathis NOT modified by this check.- Returns:
A populated
pw_presubmit.format.core.FormattedFileContentsthat contains either the result of formatting the file, or an error message.
- format_files(
- paths: Iterable[Path],
- keep_warnings: bool = True,
Uses
gn formatto fix formatting of the specified files in-place.- Returns:
An iterator of
Pathandpw_presubmit.format.core.FormatFixStatuspairs for each file that was not successfully formatted. Ifkeep_warningsisTrue, any successful format operations with warnings will also be returned.
- class pw_presubmit.format.python.BlackFormatter(config_file: Path | bool = True, **kwargs)
A formatter that runs
blackon files.- __init__(config_file: Path | bool = True, **kwargs)
Creates a formatter for Python that uses black.
- Parameters:
config_file – The black config file to use to configure black. This defaults to
True, which formats files using the nearest.black.tomlfile in the parent directory of the file being formatted.Falsedisables this behavior entirely.
- format_file(file_path: Path) FormatFixStatus
Formats the provided file in-place using
black.- Returns:
A FormatFixStatus that contains relevant errors/warnings.
- format_file_in_memory(
- file_path: Path,
- file_contents: bytes,
Uses
blackto check the formatting of the requested file.The file at
file_pathis NOT modified by this check.- Returns:
A populated
pw_presubmit.format.core.FormattedFileContentsthat contains either the result of formatting the file, or an error message.
- format_files(
- paths: Iterable[Path],
- keep_warnings: bool = True,
Uses
blackto format the specified files in-place.- Returns:
An iterator of
Pathandpw_presubmit.format.core.FormatFixStatuspairs for each file that was not successfully formatted. Ifkeep_warningsisTrue, any successful format operations with warnings will also be returned.
- class pw_presubmit.format.rust.RustfmtFormatter(tool_flags: Sequence[str] = (), **kwargs)
A formatter that runs rustfmt on files.
- __init__(tool_flags: Sequence[str] = (), **kwargs)
- format_file(file_path: Path) FormatFixStatus
Formats the provided file in-place using
rustfmt.- Returns:
A FormatFixStatus that contains relevant errors/warnings.
- format_file_in_memory(
- file_path: Path,
- file_contents: bytes,
Uses
rustfmtto check the formatting of the requested file.The file at
file_pathis NOT modified by this check.- Returns:
A populated
pw_presubmit.format.core.FormattedFileContentsthat contains either the result of formatting the file, or an error message.
- format_files(
- paths: Iterable[Path],
- keep_warnings: bool = True,
Uses
rustfmtto format the specified files in-place.- Returns:
An iterator of
Pathandpw_presubmit.format.core.FormatFixStatuspairs for each file that was not successfully formatted. Ifkeep_warningsisTrue, any successful format operations with warnings will also be returned.