A minimalist Python formatting tool
Project description
Parsimony
A minimalist line-breaker that adds the fewest breaks to fit the line.
Unlike black/blue/ruff, which explode the outermost bracket first and stack every closing bracket on its own line, Parsimony makes the smallest change that fits an over-long line, using two complementary strategies.
Explode a bracket — open the minimum number of brackets and coalesce adjacent ones:
response = authed_client().get(reverse('forwarding:detail', args=[c.id]))
becomes
response = authed_client().get(reverse(
'forwarding:detail',
args=[c.id],
))
Break a method chain — split a long .-chain one segment per line.
This is done for lines that can't be shortened by exploding a bracket:
queryset = SomeModel.objects.filter(active=True).order_by('-last_modified_at')
becomes
queryset = (
SomeModel
.objects
.filter(active=True)
.order_by('-last_modified_at')
)
Both keep related calls grouped and give long pipelines a clean one-operation-per-line shape.
Usage
Format files or directories (recurses for *.py):
parsimony -i src/ # rewrite in place
parsimony --check src/ # print a diff, exit 1 if anything would change
parsimony src/file.py # print formatted output to stdout
Read from stdin and write to stdout:
parsimony < src/file.py
cat src/file.py | parsimony
Installation
pip install kaapstorm-parsimony
Algorithm
While a physical line exceeds LINE_LENGTH, explode one container that
intersects an over-long line, chosen by:
- multi-item containers only (>= 2 args/elements); single-item containers are never opened — see "Contract" below.
- outermost (shallowest) of those.
Then re-measure and repeat. "Explode" = each element on its own line at
a +4 hanging indent, with a trailing comma, and the closing bracket
dedented to the opening line's indent. Because we only open the chosen
container and never its single-item parents, adjacent openers like
get(reverse( remain coalesced. Coalescing is not about depth, only
about not opening single-item wrappers.
When no multi-item container intersects a remaining over-long line, fall
back to breaking the outermost method chain on it (>= 2 call segments,
as shown above): wrap it in parentheses and put the head plus each
.attr on its own +4 line. Bracket explosion is preferred — a chain is
only broken when opening a bracket cannot fix the line — which keeps
breaks minimal. Any brackets already opened inside a segment are
re-indented to stay aligned under their now-deeper segment.
Contract
The tool only ever adds breaks to over-long lines; it never removes or
rewrites existing breaks. This makes it idempotent, safe to re-run, and
safe to combine with hand-formatting. Preserving existing line breaks
is intentional, so it cannot be combined with ruff format, which would
re-flow its output back into the staircase. Pair it with ruff-as-linter
(E501 off) instead.
Multi-item-only is also a correctness guardrail: opening a single-item
subscript would turn x[0] into x[0,] (== x[(0,)]), which changes
meaning. Restricting to multi-item containers avoids that. It also
avoids ugly single-element splits.
Limitations
- Lines long for non-bracket, non-method-chain reasons — ternaries, boolean/arithmetic chains, pure attribute chains (no calls), long string literals — are left untouched and reported, not fixed.
- No "join" pass: it will not re-flow code that another tool has already split. It only acts on lines that are physically too long.
- Comments inside brackets and pre-existing trailing commas are not specially handled.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kaapstorm_parsimony-0.1.2.tar.gz.
File metadata
- Download URL: kaapstorm_parsimony-0.1.2.tar.gz
- Upload date:
- Size: 30.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e61b1b535f7797602e2f9a89d11a3594a10bd38df559fc92f43b835b406755e5
|
|
| MD5 |
1b3b905aed562c93ac1883bff5ebe171
|
|
| BLAKE2b-256 |
6f191f170df9bf3b47134d9a1e8b9ecf0dd750588e64124bf09fd4ca2a571413
|
Provenance
The following attestation bundles were made for kaapstorm_parsimony-0.1.2.tar.gz:
Publisher:
publish.yml on kaapstorm/parsimony
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kaapstorm_parsimony-0.1.2.tar.gz -
Subject digest:
e61b1b535f7797602e2f9a89d11a3594a10bd38df559fc92f43b835b406755e5 - Sigstore transparency entry: 1994210127
- Sigstore integration time:
-
Permalink:
kaapstorm/parsimony@9f5fc6d6a20e46747a5c4943c08dd27931df2ab4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/kaapstorm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9f5fc6d6a20e46747a5c4943c08dd27931df2ab4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file kaapstorm_parsimony-0.1.2-py3-none-any.whl.
File metadata
- Download URL: kaapstorm_parsimony-0.1.2-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0cc9364280425ac577702601bd709c25b31125331f01d541aca17a399b9e821b
|
|
| MD5 |
625f5a877b996ebe4c122b7c1f5ed184
|
|
| BLAKE2b-256 |
637c05375cc9ab2fe8eb173934d7b6de4b3cd6d6937c4325c6075781f00763ef
|
Provenance
The following attestation bundles were made for kaapstorm_parsimony-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on kaapstorm/parsimony
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
kaapstorm_parsimony-0.1.2-py3-none-any.whl -
Subject digest:
0cc9364280425ac577702601bd709c25b31125331f01d541aca17a399b9e821b - Sigstore transparency entry: 1994210163
- Sigstore integration time:
-
Permalink:
kaapstorm/parsimony@9f5fc6d6a20e46747a5c4943c08dd27931df2ab4 -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/kaapstorm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@9f5fc6d6a20e46747a5c4943c08dd27931df2ab4 -
Trigger Event:
push
-
Statement type: