Skip to main content

A Python typesetter for the reader.

Project description

Prose

A Python typesetter for the reader

Rust1.82+ Python3.10+ Coveragepercent


🪻 About

Prose formats Python source to be legible at a glance. It aligns equals signs and colons vertically across consecutive lines, places one entry per line in dictionaries and lists, alphabetizes methods and fields within their groups, applies a singleton rule for colon padding, and treats code like prose rather than minified text.

[!NOTE] Prose is still pre-1.0. 0.2.0 lifts the catalog to eighteen rules (fourteen auto-fix, four lint-only) and lands the surrounding surface (structured output formats, suppression directives, rule subsetting, an exit-code matrix), with additional rules and configuration knobs planned for later releases.


🗞️ Philosophy

Code is read far more often than it is written. A reader's eye moves down a page and across adjacent lines looking for parallels, patterns, and shape. When every = sits at a different column and every collection is compressed onto one line, that shape disappears, forcing the eye to slow down. Prose restores it, with aligned columns letting the eye skim, one-per-line collections making each entry a unit, and alphabetized groupings giving every reader the same landmarks.

The trade-offs minimalist formatters were built to avoid (wider diffs, more vertical scrolling, occasional re-alignment churn) no longer dominate the equation. Agentic assistants do much of the typing, and every modern code host offers whitespace-ignoring diffs. What remains is the daily experience of reading code.


🪄 Install & Usage

uv tool install prose-formatter

The binary exposes format, check, and completions:

prose format path/                          # rewrite files in place
prose check path/                           # exit non-zero on violations
prose format --diff path/                   # show the diff without writing
prose check --stdin < file.py               # read from stdin

Subset the active rules with --select and --ignore:

prose check --select align-equals path/         # run a single rule
prose check --ignore strip-trailing-commas path/  # subtract one
prose check --select align-equals,align-colons path/  # comma list

Pick a structured output format for editors, pre-commit, and CI:

prose check --output-format json path/      # newline-delimited JSON
prose check --output-format github path/    # GitHub Actions annotations
prose check --output-format sarif path/     # SARIF for Code Scanning
prose check --color always path/            # force color, NO_COLOR honored
prose completions zsh                       # shell completion script

Source ranges may opt out of formatting via block markers:

# fmt: off
keep_this_block_exactly_as_written = (1,2,3)
# fmt: on

# fmt: skip on the same line opts out a single statement, and # yapf: disable / # yapf: enable are honored as block-level aliases. Lint diagnostics opt out per line through # prose: ignore[<rule>]. A bare # prose: ignore suppresses every lint rule on the line, and # prose: ignore[a, b] lists several.


🦉 Exit Codes

The binary resolves every run into one of five exit codes, which CI gates and pre-commit hooks compile against:

Code Meaning
0 Clean: no diagnostics, no rewrites pending
1 Format would change: at least one auto-fix diagnostic
2 Lint violation: at least one lint-only diagnostic
3 Parse error: input could not be parsed as Python
4 Config error: pyproject.toml, --select / --ignore, or argument validation

When two outcomes apply to the same run, the higher number wins. prose --help prints the same table beneath the option list. In format mode, code 1 is suppressed when the rewrite succeeds because the changes were applied rather than left pending. Codes 2, 3, and 4 apply identically across both subcommands.


🪶 Rules

Auto-fix rules:

Rule Coverage
align-colons Collection literals, Pydantic / dataclass fields, function signatures, and docstring Args: sections
align-equals Consecutive assignments at the same indentation
align-imports The import keyword in from ... import ... groups and as in import ... as ... groups
alphabetize Classes, methods (grouped dunders → properties → privates → publics), enum members, Pydantic fields (required then optional), function parameters, keyword arguments, and from imports
bare-import-allowlist Bare import X outside a configurable allowlist (default numpy, pandas)
blank-lines Module-level def and class carry 2 blank lines before them, methods inside a class body carry 1, a module-level statement after if __name__ == "__main__": carries 1, and adjacent module-level bare import and from imports carry 1 between them
collection-layout Expands dict, list, and set literals to one entry per line, even when they fit inline
docstring-wrap Wraps docstring description prose to docstring-line-length and structured Args: / Returns: / Raises: sections to the budget chosen by docstring-structured-policy
match-case-align Single-expression case bodies
multi-line-docstrings Multi-line docstring placement, with opener and closer each on their own line
no-single-line-docstrings Single-line triple-quoted docstrings, expanded into the canonical multi-line shape
singleton-rule Skips colon padding when only one item exists in the aligned group
strip-trailing-commas Multi-line collections and signatures
unused-future-annotations Removes from __future__ import annotations when removal is provably safe for the file

Lint-only rules:

Rule Coverage
legacy-union-syntax Union[X, Y] and Optional[X] when target-version is 3.10 or higher, with the PEP 604 X | Y / X | None shapes as the recommendation
loose-constants Module-level SCREAMING_CASE assignments that would read better as an Enum, a model field, or a function-local
no-step-narration Own-line numbered-step comments (# 1. ..., # Step 2: ...) that signal extractable functions
single-use-variables Bindings assigned and read exactly once, where inlining the right-hand side carries the same meaning

Example

Before:

from pydantic import BaseModel
from datetime import date
from collections.abc import Iterable
from decimal import Decimal

DEFAULT_LIMIT = 50
RETRY_INTERVAL = 30
PAGE_SIZE = 25

class Posting(BaseModel, extra="forbid"):
    title: str
    company: str
    skills: Iterable[str] | None = None
    location: str | None = None
    date_posted: date
    salary_max: Decimal | None = None

    def render(self, separator: str, include_location: bool, include_date: bool, max_width: int = 80) -> str: ...

config = {"threshold": 0.7, "metric": "euclidean", "linkage": "ward", "n_clusters": None, "random_state": 42,}

After:

from collections.abc import Iterable
from datetime        import date
from decimal         import Decimal
from pydantic        import BaseModel

DEFAULT_LIMIT  = 50
RETRY_INTERVAL = 30
PAGE_SIZE      = 25

class Posting(BaseModel, extra="forbid"):
    company     : str
    date_posted : date
    title       : str
    location    : str | None           = None
    salary_max  : Decimal | None       = None
    skills      : Iterable[str] | None = None

    def render(
        self,
        include_date     : bool,
        include_location : bool,
        separator        : str,
        max_width        : int = 80
    ) -> str: ...

config = {
    "linkage"      : "ward",
    "metric"       : "euclidean",
    "n_clusters"   : None,
    "random_state" : 42,
    "threshold"    : 0.7
}

⚖️ Configuration

Prose loads the nearest [tool.prose] section found by walking upward from the working directory. With no configuration, every rule runs at its default. To tune a rule, write its sub-table:

[tool.prose]
code-line-length = 88

[tool.prose.rules.align-equals]
enabled = false                # disable a rule outright

[tool.prose.rules.align-colons]
max-shift        = 12          # cap padding width
max-shift-policy = "drop"      # how to handle overrun groups

[tool.prose.rules.collection-layout]
max-atomics-per-line = 3       # keep short tuples on one line

Per-rule knobs:

Key Type Where Meaning
enabled bool every rule sub-table Toggle the rule on or off, defaulting to true
max-shift positive int alignment rules Ceiling on per-line padding, defaulting to 8
max-shift-policy "split" | "drop" | "skip" alignment rules How to handle a group whose widest member exceeds max-shift. split partitions the group, drop excludes the widest members from the padding calculation, skip leaves the whole group unaligned, defaulting to "split"
max-atomics-per-line positive int collection-layout Keep short collections on one line when each entry is an atomic literal and the run fits the cap, defaulting to 8
allow list of module names bare-import-allowlist Modules whose bare-import form is preserved, defaulting to ["numpy", "pandas"]
allow list of names loose-constants Module-level names exempted from the lint, defaulting to []
allow-pattern regex single-use-variables Binding names exempted from the lint, defaulting to "^_"
code-line-length positive int top-level [tool.prose] Honored by line-length-aware rules, defaulting to 88
docstring-line-length positive int top-level [tool.prose] Description-prose budget for docstring-wrap, defaulting to 76
docstring-structured-policy "code-line-length" | "docstring-line-length" top-level [tool.prose] Source budget for structured docstring sections, defaulting to "code-line-length"
target-version "3.X" version string top-level [tool.prose] Python runtime the project ships to. Consumed by version-gated rules, defaulting to unset

Docstrings carry two readings inside one triple-quoted region. Description prose between the opening """ and the first section heading reads as paragraphs, where 76 characters is the comfortable line for sustained reading. Structured sections (Args:, Returns:, Raises:) read as code-shaped tables and reuse code-line-length (88 by default) to match surrounding indentation, though docstring-structured-policy switches them to docstring-line-length if a project prefers a single narrower budget across the whole docstring. The docstring-wrap rule consumes both budgets.

target-version names the Python runtime a project ships to, taking the bare major.minor form ("3.13", "3.14") used by mypy's python_version setting. Rules whose safety depends on the runtime read this field directly, treating an unset value as the cue to skip every version-dependent arm rather than assume a default. legacy-union-syntax is the first such consumer, staying quiet on every project that has not opted into a target.

Alignment rules are align-colons, align-equals, align-imports, and match-case-align. Toggle-only rules carry only the enabled knob. They are alphabetize, blank-lines, docstring-wrap, legacy-union-syntax, multi-line-docstrings, no-single-line-docstrings, no-step-narration, singleton-rule, strip-trailing-commas, and unused-future-annotations. The remaining rules (bare-import-allowlist, collection-layout, loose-constants, single-use-variables) carry rule-specific knobs documented in the table above.

Per-invocation overrides via --select and --ignore (see Install & Usage above) take precedence over the configured-enabled set.


🗺️ Composition

Prose runs as the second pass in a two-stage pipeline. The first pass owns tokens (line wrapping, quote normalization, indentation, blank-line discipline) and the second pass owns layout (alignment, alphabetization, the singleton rule, one-entry-per-line collections, trailing-comma stripping). Ruff is the canonical first pass, in that ruff format matches the token-level scope and its lint config shares the pyproject.toml root with [tool.prose].

ruff format && prose format

[!IMPORTANT] Running Prose first is incorrect, because Prose's alignment math depends on already-settled line breaks and an upstream re-wrap will undo per-line layout decisions, forcing a third pass.

Ruff Configuration

Code Conflict Reason
COM812 Lint re-adds trailing commas strip-trailing-commas removes them in multi-line collections and signatures
E203 Lint flags whitespace before : align-colons produces it in dict literals, dataclass fields, function signatures, and docstring Args: blocks
E221 Lint flags multiple spaces before = align-equals produces it across consecutive assignments at the same indentation
E272 Lint flags multiple spaces before import / as align-imports produces it across from ... import ... and import ... as ... groups
E501 Lint flags lines past line-length A long member in an alignment group pads shorter lines rightward, occasionally past the configured limit
skip-magic-trailing-comma Formatter re-expands collections by trailing-comma presence prose format controls collection layout independently of comma signaling

Other Tools

Black formats, Flake8 lints, and isort sorts, so each pairs with Prose at a different layer:

Tool Pairing
Black Run Black with --skip-magic-trailing-comma, then Prose second. Black collapses collections that collection-layout re-expands and preserves trailing commas that strip-trailing-commas removes
Flake8 Add extend-ignore = E203, E221, E272 to .flake8 or setup.cfg (and C812 if flake8-commas is installed). Flake8 inherits the same pycodestyle codes Ruff inherits
isort Run isort first, Prose second, with no configuration adjustment. Prose alphabetizes within isort's groups and aligns the import keyword that isort leaves un-aligned

🪡 Integrations

Wire Prose into anything that runs on save, on commit, or in CI.

GitHub Actions

The minimal check-on-CI shape:

- run: uv tool install prose-formatter
- run: prose check .

For inline annotations on the PR diff, use the github output format. Prose emits workflow commands that GitHub renders as native check-run annotations:

- run: uv tool install prose-formatter
- run: prose check --output-format github .

For findings that persist across runs and surface in Code Scanning, emit SARIF and upload it:

- run: uv tool install prose-formatter
- run: prose check --output-format sarif . > prose.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: prose.sarif

CI gates compile against the exit-code matrix above. A non-zero status without continue-on-error fails the step.

Editor

Any editor that supports run-on-save (VSCode's runOnSave, Vim's autocmd BufWritePost, JetBrains File Watchers) can shell out to prose format <file>. For editors that consume structured diagnostics, prose check --output-format json --stdin emits one Ruff-shaped record per line.

Pre-Commit

Add a local hook to your .pre-commit-config.yaml:

- repo: local
  hooks:
    - id: prose
      name: prose
      entry: prose format
      language: system
      types: [python]

Swap entry: prose format for entry: prose check for the check-only variant. The hook surfaces the same exit codes the CLI uses, so a format hook never fails on rewrites it applies and a check hook fails the commit when changes are pending.

Shell Completions

prose completions zsh > "${fpath[1]}/_prose"
prose completions bash > /etc/bash_completion.d/prose
prose completions fish > ~/.config/fish/completions/prose.fish

Both elvish and powershell are supported targets for the completions subcommand.


🗜️ Development

One-Time Setup

Prose uses mise to manage every toolchain and CLI through a single mise.toml. Install mise, wire it into your shell, then mise install provisions the rest.

Install Mise

curl https://mise.run | sh

The installer drops the binary into ~/.local/bin/mise.

Wire Mise into Zsh

Three init files cover the three load contexts (every shell, login shells, interactive shells) so mise-managed tools resolve correctly whether you are inside an interactive terminal, a login shell, or a non-interactive subprocess:

# ~/.zshenv  (sourced for every shell, including non-interactive)
export PATH="$HOME/.local/bin:$PATH"

# ~/.zprofile  (sourced for login shells, before .zshrc)
eval "$(mise activate zsh --shims)"

# ~/.zshrc  (sourced for interactive shells)
eval "$(mise activate zsh)"

.zshenv puts mise itself on PATH so the later eval lines can find it. .zprofile's --shims activation makes mise-managed binaries resolvable in non-interactive contexts (scripts, editors, GUI launches). .zshrc's full activation gives interactive shells the per-directory tool resolution and task discovery.

Clone and Provision

git clone https://github.com/Jybbs/prose.git
cd prose
mise install

mise install provisions:

Tool Purpose
cargo-insta Snapshot test review
maturin Rust → Python wheel builder
python (3.14) Python interpreter for wheel builds
rust (stable) Rust toolchain via rustup
uv Python package and venv manager

Daily Workflow

Tasks are defined in mise.toml and discoverable via mise tasks:

Command What it does
mise build Compile in debug mode
mise check Verify Rust source matches rustfmt without rewriting
mise ci Lint + test + wheel (full local sweep)
mise format Format Rust source with rustfmt
mise lint Run clippy with all warnings as errors
mise review Interactively accept pending snapshot diffs
mise test Run all tests including insta snapshots
mise wheel Build the wheel and install into .venv

Editor

VSCode

Install rust-analyzer and Even Better TOML. The rust-analyzer extension bundles its own language server, so it works without additional global Rust installs.

Suggested user settings (apply to any Rust project):

"rust-analyzer.check.command": "clippy",
"rust-analyzer.imports.granularity.group": "module"

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

prose_formatter-0.2.2.tar.gz (365.6 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

prose_formatter-0.2.2-py3-none-win_amd64.whl (2.2 MB view details)

Uploaded Python 3Windows x86-64

prose_formatter-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

prose_formatter-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.3 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

prose_formatter-0.2.2-py3-none-macosx_11_0_arm64.whl (2.2 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

prose_formatter-0.2.2-py3-none-macosx_10_12_x86_64.whl (2.3 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file prose_formatter-0.2.2.tar.gz.

File metadata

  • Download URL: prose_formatter-0.2.2.tar.gz
  • Upload date:
  • Size: 365.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}

File hashes

Hashes for prose_formatter-0.2.2.tar.gz
Algorithm Hash digest
SHA256 de00af96f7909ccab2fc1a1430f5b80e67cefae334cd54ae3af43df34cc4839a
MD5 4f754fbacd68cb43d5a59b9569735ad4
BLAKE2b-256 85b4d2fe896c32966619b25b91b014669cbeedf8cc5609b3de59cb4c22f02593

See more details on using hashes here.

Provenance

The following attestation bundles were made for prose_formatter-0.2.2.tar.gz:

Publisher: release.yml on Jybbs/prose

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prose_formatter-0.2.2-py3-none-win_amd64.whl.

File metadata

  • Download URL: prose_formatter-0.2.2-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.2 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}

File hashes

Hashes for prose_formatter-0.2.2-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 b9ba833e053cef7ca6f0bf3d5aacffd9d8b0dfdaf8e8d3f0d6852e0633d9e6ff
MD5 bd219980e3af9aac9370a69fc3f59467
BLAKE2b-256 c0e040684ba03c7d3e9e3bf372af076d73d78b5110df3233ac876bcfff573db7

See more details on using hashes here.

Provenance

The following attestation bundles were made for prose_formatter-0.2.2-py3-none-win_amd64.whl:

Publisher: release.yml on Jybbs/prose

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prose_formatter-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

  • Download URL: prose_formatter-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  • Upload date:
  • Size: 2.4 MB
  • Tags: Python 3, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}

File hashes

Hashes for prose_formatter-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 b2a8161407a63abba4592c5cd8a6bc2702dfe928355e311130bac5ca0b92b069
MD5 10308a7ed49c16a83428faf7521c3a8a
BLAKE2b-256 3d17e48ba5b0dbf8dbb6ba557f3881c04e8b34156c3aac91138cd42548568f1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for prose_formatter-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on Jybbs/prose

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prose_formatter-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

  • Download URL: prose_formatter-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
  • Upload date:
  • Size: 2.3 MB
  • Tags: Python 3, manylinux: glibc 2.17+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}

File hashes

Hashes for prose_formatter-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 01ee22c6163b2874719285ae0adb890ee70589d21eafe8d4c371613e725fc7c9
MD5 5e7ca71c2588a2bc306c2684f45fddf9
BLAKE2b-256 0b02cad93de378738afa7905eeaedad945c06c6e95c9b0983e7d92a0fb3842ba

See more details on using hashes here.

Provenance

The following attestation bundles were made for prose_formatter-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on Jybbs/prose

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prose_formatter-0.2.2-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: prose_formatter-0.2.2-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 2.2 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}

File hashes

Hashes for prose_formatter-0.2.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 be74aa673ea885142902ee2262926af943b298a4eca30634941abed8b18e1a41
MD5 136b4885f42a736fd890bbd92f43adb7
BLAKE2b-256 157ab8858e567102c081e1eec57c200dfe297e9d547fb013234ec73df4d60913

See more details on using hashes here.

Provenance

The following attestation bundles were made for prose_formatter-0.2.2-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on Jybbs/prose

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file prose_formatter-0.2.2-py3-none-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: prose_formatter-0.2.2-py3-none-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 2.3 MB
  • Tags: Python 3, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","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}

File hashes

Hashes for prose_formatter-0.2.2-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 254661191ff7c7a0f03a62e19bb26c48fc6941d334a90006997e022429ab8146
MD5 5adc4372d69d60264973d3e725ae30ac
BLAKE2b-256 33de56be2d788ec9d7898738e0193b970208213e3aca86fcba90d6dc279f72f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for prose_formatter-0.2.2-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on Jybbs/prose

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page