API Reference

When integrating µfmt into an existing toolchain or workflow, it is highly recommended to use the simple, or high-level, API whenever possible. It is designed to provide easy mechanisms for customizing configuration and post-processing file content, while handling the boring parts of formatting large codebases, like file discovery, reading or writing bytes from disk, or managing workers processes to optimize performance.

When in doubt, ufmt_paths() should be the go-to method of using µfmt within other tools.

Simple API

ufmt.ufmt_paths(paths, *, dry_run=False, diff=False, return_content=False, ufmt_config_factory=None, black_config_factory=None, usort_config_factory=None, pre_processor=None, post_processor=None, concurrency=None, root=None)

Format one or more paths, recursively, ignoring any files excluded by configuration.

Uses trailrunner to first walk all paths, and then to run ufmt_file() on each matching file found. If more than one eligible file is discovered after walking the given paths, all files will be formatted using a process pool for improved performance and CPU utilization.

Returns a generator yielding Result objects for each file formatted. Any errors that occur during formatting will be caught, and those exceptions will be attached to the Result.error property of the result object. It is the responsibility of code calling this function to check for errors in results and handle or surface them appropriately.

If the first given path is STDIN (Path("-")), then content will be formatted from STDIN using ufmt_stdin(). Results will be printed to STDOUT. A second path argument may be given, which represents the original content’s true path name, and will be used when printing status messages, diffs, or errors. Any further path names will result in a runtime error.

See ufmt_file() for details on parameters, config factories, and post processors. All parameters are passed through to ufmt_file().

Note

Factory and post processing functions must be pickleable when using ufmt_paths().

Parameters:
Return type:

Generator[Result, None, None]

ufmt.ufmt_file(path, *, dry_run=False, diff=False, return_content=False, ufmt_config_factory=None, black_config_factory=None, usort_config_factory=None, pre_processor=None, post_processor=None, root=None)

Format a single file on disk, and returns a Result.

Passing dry_run = True will only format the file in memory, without writing changes to disk. Passing diff = True will generate a unified diff of changes on Result.diff. Passing return_content = True will also populate Result.before and Result.after with the bytes content of the file from before and after formatting, respectively.

Any errors that occur during formatting will be caught, and those exceptions will be attached to the Result.error property of the result object. It is the responsibility of code calling this function to check for errors in results and handle or surface them appropriately.

Optionally takes black_config_factory or usort_config_factory to override the default configuration detection for each respective tool. Factory functions must take a pathlib.Path object and return a valid BlackConfig or UsortConfig object respectively.

Optionally takes a pre- or post-processor matching the Processor protocol. If given, the pre-processor will be called with the original byte string content before it has been run through µsort or black. The return value of the pre-processor will be used in place of the original content when formatting. If given, the post processor will be called with the updated byte string content after it has been run through µsort and black. The return value of the post processor will replace the final return value of ufmt_bytes().

Raising ufmt.SkipFormatting from a pre- or post-processor will result in “skipping” the file currently being formatted. The final contents will be unchanged, and the Result.skipped attribute will be set with the string message from the skip exception, or True if no message is given.

Parameters:
Return type:

Result

class ufmt.Result(path, changed=False, written=False, skipped=False, diff=None, error=None, before=b'', after=b'')

Basic metadata results from formatting files.

Parameters:
after: bytes = b''
before: bytes = b''
changed: bool = False
diff: str | None = None
error: Exception | None = None
path: Path
skipped: bool | str = False
written: bool = False
class ufmt.UfmtConfig(project_root: Optional[pathlib.Path] = None, pyproject_path: Optional[pathlib.Path] = None, excludes: List[str] = <factory>, formatter: ufmt.types.Formatter = <Formatter.black: 'black'>, sorter: ufmt.types.Sorter = <Sorter.usort: 'usort'>)
Parameters:
excludes: List[str]
formatter: Formatter = 'black'
project_root: Path | None = None
pyproject_path: Path | None = None
sorter: Sorter = 'usort'
ufmt.UfmtConfigFactory

alias of Callable[[Optional[Path], Optional[Path]], UfmtConfig]

ufmt.BlackConfig

alias of Mode

ufmt.BlackConfigFactory

alias of Callable[[Path], Mode]

ufmt.UsortConfig

alias of Config

ufmt.UsortConfigFactory

alias of Callable[[Path], Config]

class ufmt.Processor(*args, **kwargs)
__call__(path, content, *, encoding='utf-8')

Process bytes before or after formatting and return the updated file content.

Parameters:
Return type:

bytes

class ufmt.SkipFormatting

Raise this exception in a pre/post processor to skip formatting a file.

Low-level API

ufmt.Encoding

alias of str

ufmt.FileContent

alias of bytes

ufmt.Newline

alias of bytes

class ufmt.types.Formatter(value)

Select preferred formatter implementation.

black = 'black'

Use black (default).

ruff_api = 'ruff-api'

Experimental: Use Ruff via unofficial ruff-api extension.

Note

This implementation still depends on and uses the [tool.black] configuration table from pyproject.toml rather than Ruff’s own configuration options. This may change in future updates.

class ufmt.types.Sorter(value)

Preferred import sorter implementation.

skip = 'skip'

Skip sorting imports

usort = 'usort'

Use µsort (default).

ufmt.ufmt_bytes(path, content, *, encoding='utf-8', black_config, usort_config, ufmt_config=UfmtConfig(project_root=None, pyproject_path=None, excludes=[], formatter=<Formatter.black: 'black'>, sorter=<Sorter.usort: 'usort'>), pre_processor=None, post_processor=None)

Format arbitrary bytes for the given path.

Requires passing valid config objects for both black and µsort. If the given path represents a type stub (has a .pyi suffix), the black config object will be updated to set is_pyi = True.

This function will not catch any errors during formatting, except for “everything is fine” messages, like black.NothingChanged. All other errors must be handled by the code calling this function; see ufmt_file() for example error handling.

Optionally takes a pre- or post-processor matching the Processor protocol. If given, the pre-processor will be called with the original byte string content before it has been run through µsort or black. The return value of the pre-processor will be used in place of the original content when formatting. If given, the post processor will be called with the updated byte string content after it has been run through µsort and black. The return value of the post processor will replace the final return value of ufmt_bytes().

Experimental: The optional ufmt_config parameter allows passing alternative Formatter and Sorter values, to choose formatting and sorting implementations instead of black and µsort. This should be passed by alternate frontends, and be based on the project’s configuration in pyproject.toml. Optionally can be passed through from ufmt_file() or ufmt_paths() as ufmt_config_factory.

Note

Content will be decoded before passing to black, and re-encoded to bytes again. Be sure to pass a known-valid unicode encoding for the content.

Specifying the correct encoding is important! µfmt cannot do the right thing without the correct encoding if files contain PEP 263 coding lines, or byte values unrepresentable in UTF-8 (like \ud800).

When in doubt, use :func:`ufmt_file` or :func:`ufmt_paths`.

ufmt.util.read_file() can be used to both read bytes from disk, and make a best guess at file encodings. Otherwise, use tokenize.detect_encodings().

Parameters:
Return type:

bytes

ufmt.ufmt_stdin(path, *, dry_run=False, diff=False, return_content=False, ufmt_config_factory=None, black_config_factory=None, usort_config_factory=None, pre_processor=None, post_processor=None)

Wrapper around ufmt_file() for formatting content from STDIN.

If given dry_run = False, the resulting formatted content will be printed to STDOUT. Diff content and changed status will be returned as part of the Result object as normal.

Requires passing a path that represents the filesystem location matching the contents to be formatted. Reads bytes from STDIN until EOF, writes the content to a temporary location on disk, and formats that file on disk using ufmt_file(). The Result object will be updated to match the location given by path.

See ufmt_file() for details on parameters, config factories, and post processors. All parameters are passed through to ufmt_file().

Parameters:
Return type:

Result

ufmt.util.normalize_result(content, newline)

Convert bytes content with UNIX style line endings to the given style.

No-op if newline is given as b"\n".

Parameters:
Return type:

bytes

ufmt.util.read_file(path)

Read a file from disk, detect encoding, and normalize newlines.

Returns a tuple of file contents, file encoding, and original newline style. File contents are in bytes, with newlines normalized to UNIX style “n”. File encoding is detected either by PEP 263 coding line or encoding cookie. Newline is detected from the first line ending, and assumes that all lines in the file will have (or should have) consistent line endings.

Intended for use with write_file(), where newlines get converted back to the original newline style before being written to disk.

Parameters:

path (Path) –

Return type:

Tuple[bytes, str, bytes]

ufmt.util.write_file(path, content, newline)

Write to a file on disk, normalizing to the given newline style.

Expects given content in bytes, with UNIX style line endings. UNIX style newlines will be converted to the given newline style before writing bytes to disk.

Intended for use with content and newline style from read_file(), so that newlines are correctly normalized back to their original style when writing to disk.

Parameters:
Return type:

None