spacify
A fast formatter for the vertical rhythm of Python code. ruff format decides how a statement is
laid out, but leaves most of the blank lines between statements up to you. spacify fills that gap:
it puts air around logical blocks and tightens runs of related statements, and it only touches the
blank lines between statements.
Before:
def load(paths):
seen = set()
for path in paths:
if path in seen:
continue
seen.add(path)
total = len(seen)
count = 0
log(total)
return total
After spacify:
def load(paths):
seen = set()
for path in paths:
if path in seen:
continue
seen.add(path)
total = len(seen)
count = 0
log(total)
return total
spacify never fights ruff. Every rule stays inside the blank-line bounds ruff format keeps, and
CI runs both tools over CPython's standard library in both orders to check they reach a fixed point.
Checking all of CPython's Lib takes under half a second on 8 cores.
Install
uv tool install spacify # or: pipx install spacify, pip install spacify
Use with prek or pre-commit
Put the hook after ruff-format, so spacify sees ruff's line wrapping:
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.9
hooks:
- id: ruff-format
- repo: https://github.com/avanserv/spacify-pre-commit
rev: v0.1.0
hooks:
- id: spacify
The hook installs the prebuilt wheel from PyPI, so you don't need a Rust toolchain.
Command line
spacify # format every Python file under the current directory
spacify src/ tests/a.py # format these paths
spacify --check # write nothing; exit 1 if any file would change
spacify --diff # write nothing; print a unified diff
spacify - < a.py # read stdin, write stdout (--stdin-filename names it)
The exit code is 0 on success, 1 when --check or --diff found changes, and 2 on an error such as
a syntax error, in which case the file is left untouched. Directory walks respect .gitignore and
skip the directories ruff skips by default. A file you name explicitly is always formatted, unless
you also pass --force-exclude, which is what the hook does.
Rules
Each rule can be turned on or off. They all apply to sibling statements in the same block.
| Rule | Effect |
|---|---|
blank-before-block |
At least one blank line before if, for, while, try, with and match (including the async forms) when another statement comes before them. |
blank-after-block |
At least one blank line after one of those blocks, before the next statement. |
blank-before-exit |
At least one blank line before return, raise, break, continue and a bare yield, in blocks of exit-min-block-statements (default 3) or more statements. |
collapse-groups |
No blank line between two single-line statements of the same kind: assignments, augmented assignments, calls, del, assert, global/nonlocal. Outside every function and class, an assignment whose target names all have an uppercase letter and no lowercase one (MAX = 3, T = TypeVar("T"), A, *REST = items) is a constant, a kind apart from other assignments. |
The added blank lines take priority over collapse-groups. A few places are never touched:
- Gaps next to a
deforclass, after animport, or after a docstring. Ruff decides these. - Blank lines that have a comment in the gap, because a comment marks a paragraph you meant. When a rule does add a blank line, it goes above the comments that belong to the next statement.
- Regions between
# fmt: offand# fmt: on(or# spacify: offand# spacify: on), and any line marked# fmt: skip.
Imports are never collapsed, because ruff's isort rules separate import sections with blank lines.
A nested block never gets more than one blank line in a row. At module level the limit is two, or one
in a .pyi stub.
Configuration
spacify reads [tool.spacify] from pyproject.toml, or the top level of a spacify.toml or
.spacify.toml. It uses the first one it finds walking up from the current directory, or the file
you pass with --config.
[tool.spacify]
extend-exclude = ["generated", "migrations/*.py"] # `exclude = [...]` replaces the defaults
[tool.spacify.rules]
blank-before-block = true
blank-after-block = true
blank-before-exit = true
exit-min-block-statements = 3
collapse-groups = true
An exclude pattern containing a / matches the path relative to the config file. Any other pattern
matches a single file or directory name.
Contributing
See CONTRIBUTING.md.
Metadata
Release files for spacify 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| spacify-0.2.0.tar.gz | 25.1 kB | Without provenance | Details for spacify-0.2.0.tar.gz |
Built distributions (wheels)
Total release size: 8.6 MB
Release files / spacify-0.2.0.tar.gz
| Download URL | spacify-0.2.0.tar.gz |
|---|---|
| Size | 25.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5b89f2e73ff9f1de3529f84f60b26400be06eaf07a3fc6a3ad443aa7fab9b67c
|
|
BLAKE2b-256 checksum How to use checksums |
92e0a210f6a16aa902eade24fbc6ce9221042a923db9e1565647b56a2172207a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-win_amd64.whl
| Download URL | spacify-0.2.0-py3-none-win_amd64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
a8878890d86c382c384bc99b4f5feddefa0cc551e67394c58854d257e95e24ea
|
|
BLAKE2b-256 checksum How to use checksums |
d5c62eb39ca095025f76cb5a5c68963a054426ca1d50dbe58dbf8a69f059b858
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-musllinux_1_2_x86_64.whl
| Download URL | spacify-0.2.0-py3-none-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.4 MB |
| Tags | Linux musl 1.2+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
62c5d62d856be5719cca7922ce3a336a2b7c87d31499d6e692b8fbfba584abf9
|
|
BLAKE2b-256 checksum How to use checksums |
d54465145047dbc4bfe0abb19ebb9e4bc4cfd61f2e6c05e6a7a6bb3edf8eae00
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-musllinux_1_2_aarch64.whl
| Download URL | spacify-0.2.0-py3-none-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Linux musl 1.2+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
b3415c0aae405268a510a748527a64bd4e79b87e4b6897d28eb08899812fe16e
|
|
BLAKE2b-256 checksum How to use checksums |
df91b48ffd6e3a83d0dfac21af4b586828871c4ab3a3e9f88c334d9bbaa7c624
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | spacify-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.3 MB |
| Tags | Linux glibc 2.17+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
343646acf8fbb2dccba41d33d575262df456cbcb8a57e2d034f4bebe4220bd02
|
|
BLAKE2b-256 checksum How to use checksums |
ede4615eb25a43eedfe48df8aaefc46ef6e80cce4edc49ed9f5abf9416460ccc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | spacify-0.2.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Linux glibc 2.17+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
c0aebdfe5a7d3887d7d89ef8310dd49bd865343bd816dbb8c475f4eb9ecc98af
|
|
BLAKE2b-256 checksum How to use checksums |
ba42ffb19c222a8d933d719022b87f9dbd196436c4f958e4a48006f08fafaa5c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-macosx_11_0_arm64.whl
| Download URL | spacify-0.2.0-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.1 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
9a47ea5539053cb1589f264252bf6e843898ccc5f97d8a00b0a47f047a507cc9
|
|
BLAKE2b-256 checksum How to use checksums |
c3b9a9a8d6ff4cce6218666d179f3ea490366c1b189406828299d93d19a0e8c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / spacify-0.2.0-py3-none-macosx_10_12_x86_64.whl
| Download URL | spacify-0.2.0-py3-none-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | Python 3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
99910246fdf5c5991bbf3ee2ff56ffff996f578bc41458626ca4598668212a97
|
|
BLAKE2b-256 checksum How to use checksums |
6cd32c7fa78f9582925bc28aac04aefff2dfc2b8b577e1378e81367a51939258
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.2 {"installer":{"name":"uv","version":"0.13.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for spacify 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.