Skip to main content

spacify

CI PyPI

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. It also checks that spacify leaves the AST of every file unchanged. Checking CPython's Lib, without its tests, 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.

Known limits

spacify parses with tree-sitter-python, which rejects a few valid constructs: type parameter defaults (def f[T = int](), PEP 696), a parenthesised starred subscript (a[*(b)]), and an attribute access broken after its dot onto a line indented less than the statement. A file using one exits 2 and is left untouched. Files must be UTF-8, as for ruff, and line endings that are a bare \r are refused the same way. Python 2 print and exec statements are not rejected, since tree-sitter cannot tell some of them from valid Python 3 such as print >>f, x.

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 def or class, after an import, 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: off and # fmt: on (or # spacify: off and # 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.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spacify 0.2.1
File Size Uploaded Provenance Actions
spacify-0.2.1.tar.gz 28.1 kB Without provenance Details for spacify-0.2.1.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for spacify 0.2.1
File Actions
spacify-0.2.1-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for spacify-0.2.1-py3-none-win_amd64.whl
spacify-0.2.1-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details for spacify-0.2.1-py3-none-musllinux_1_2_x86_64.whl
spacify-0.2.1-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details for spacify-0.2.1-py3-none-musllinux_1_2_aarch64.whl
spacify-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details for spacify-0.2.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
spacify-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details for spacify-0.2.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
spacify-0.2.1-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for spacify-0.2.1-py3-none-macosx_11_0_arm64.whl
spacify-0.2.1-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details for spacify-0.2.1-py3-none-macosx_10_12_x86_64.whl

Total release size: 8.6 MB

Release files / spacify-0.2.1.tar.gz

Download URL spacify-0.2.1.tar.gz
Size 28.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b746f92be51e2416548680543a0182026186c4c0dc843f90d5d01123a60e22d1
BLAKE2b-256 checksum
How to use checksums
edae7982b7127e17c23397b944457eb3d74bb39823c5a45943f327f3e0cea52b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-win_amd64.whl

Download URL spacify-0.2.1-py3-none-win_amd64.whl
Size 1.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
9a9cc037f5e117787cab17efd3aa4ef7cdd2265d2ca76033c139af74f1e48515
BLAKE2b-256 checksum
How to use checksums
cf912eec47da9ea54e478337b74813db5312ffd99ac62a2439d4e16008477485
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-musllinux_1_2_x86_64.whl

Download URL spacify-0.2.1-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
3792d33a375ab475a10211aba6b56944064b98ad8345ad20221931eda5ed0e67
BLAKE2b-256 checksum
How to use checksums
0570409adf0d2436b960af85c19fef28500bfc4890c2264e3d0ebe1dd8aa4a4d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-musllinux_1_2_aarch64.whl

Download URL spacify-0.2.1-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
a701279ad247fd75d61d151aaa046cfcd52bc47e21ff908f98f46969db660d07
BLAKE2b-256 checksum
How to use checksums
5d003ece335ddf405e05e3b058fe20ffdc637f6c7730ad1376747464b999f47c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL spacify-0.2.1-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
281802a6a3777a5484202a8c3dae2b3d16f5203de7ac4a7f14219e5231a1402f
BLAKE2b-256 checksum
How to use checksums
57547971667849a102f6fc5213a1bc6ae6af932f236747c1467554368e3542fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL spacify-0.2.1-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
1c40411851aa02ff53f1c638471c980fedaa178083d5af8fc196ee5aaf28d906
BLAKE2b-256 checksum
How to use checksums
d7aa5761a63cad576f794ce4a656b6438a413c664a76755d6ed9e06b6de33205
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-macosx_11_0_arm64.whl

Download URL spacify-0.2.1-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
83590ce1c5b7eed80d21a447f7f1ce214f93c9a463415fc06673ad3b9af5521b
BLAKE2b-256 checksum
How to use checksums
03d06676a1fdfcca39a287d000516651970e615f85f25d8814c470d5892140f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1-py3-none-macosx_10_12_x86_64.whl

Download URL spacify-0.2.1-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
20f7bdb28ffc450c4508277d4acd013cf5bd0afcb0135537b268dbdc9805028d
BLAKE2b-256 checksum
How to use checksums
e09e0a452dba3fdbb6fd8939eb84a776cad2d6724c8c204b86baaaf57041c339
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.1

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page