ufmt: Safe, Atomic Formatting with Black and µsort
ufmt (pronounced "micro-fmt") is a safe, atomic code formatter for Python, built on top of the popular `black` formatter and `µsort` import sorter. It combines their functionality into a single, atomic step, ensuring consistent code style and import order without intermediate conflicts. Currently at version 2.9.1, it requires Python 3.10 or newer and maintains an active release cadence.
Warnings
- breaking ufmt v2.0.0 dropped support for Python 3.6. v2.2.0 further dropped support for Python 3.7. Users must be on Python 3.10 or newer (as of 2.9.1).
- breaking The `ufmt_file` and `ufmt_paths` API functions now require keyword arguments for all parameters.
- deprecated The `ufmt_string` function was deprecated in v2.0.0 and will be removed in v3.0. Use `ufmt_bytes` instead for formatting raw byte content.
- gotcha For stable and reproducible CI workflows, always pin the versions of `ufmt`, `black`, and `usort` in your `requirements.txt` or `pyproject.toml` to prevent unexpected formatting changes introduced by newer versions of these transitive dependencies.
- gotcha Prior to v2.1.0, `ufmt` could fail to format Python 3.10+ `match case` statements due to `µsort`'s reliance on `LibCST`. This was fixed by enabling `LibCST`'s native parser by default. If using older `ufmt` versions, an `LIBCST_PARSER_TYPE=native` environment variable was required.
Install
-
pip install ufmt
Imports
- ufmt_paths
from ufmt import ufmt_paths
- ufmt_file
from ufmt import ufmt_file
Quickstart
import os
from pathlib import Path
from ufmt import ufmt_file
from black import Mode, TargetVersion
from usort import Config
def main():
# Create a dummy Python file
dummy_content = (
"import os, sys\n\ndef my_func ( param1, param2 ) :\n \"\"\"A docstring.\"\"\"\n return param1 + param2\n"
)
dummy_file = Path("temp_module.py")
dummy_file.write_text(dummy_content)
print(f"Original content of {dummy_file.name}:\n---\n{dummy_content.strip()}\n---")
# Define black and usort configs (optional, ufmt can detect from pyproject.toml)
# For this example, we provide minimal configs
black_config = Mode(target_versions={TargetVersion.PY310})
usort_config = Config()
# Format the file using the ufmt API
result = ufmt_file(
path=dummy_file,
black_config=black_config,
usort_config=usort_config,
return_content=True
)
if result.error:
print(f"Error formatting {dummy_file.name}: {result.error}")
elif result.changed:
print(f"Formatted content of {dummy_file.name}:\n---\n{result.after.decode().strip()}\n---")
else:
print(f"{dummy_file.name} was already formatted correctly.\n---\n{result.after.decode().strip()}\n---")
# Clean up the dummy file
dummy_file.unlink()
if __name__ == "__main__":
main()