Skip to main content

Pyink, pronounced pī-ˈiŋk, is a Python formatter, forked from Black with a few different formatting behaviors. We intend to keep rebasing on top of Black's latest changes.

Why Pyink?

We would love to adopt Black, but adopting it overnight is too disruptive to the thousands of developers working in our monorepo. We also have other Python tooling that assumes certain formatting, it would be a too big task to update them all at once. We decided to maintain a few local patches to Black as a medium-term solution, and release them as a separate tool called Pyink.

Pyink is intended to be an adoption helper, and we wish to remove as many patches as possible in the future.

What are the main differences?

  • Support two-space indentation, using the pyink-indentation option.

  • Support inferring preferred quote style by calculating the majority in a file, using the pyink-use-majority-quotes option.

  • Do not wrap trailing pragma comments if the line exceeds the length only because of the pragma (see psf/black#2843). Example

    # Pyink:
    result = some_other_module._private_function(arg="value")  # pylint: disable=protected-access
    
    # Black:
    result = some_other_module._private_function(
        arg="value"
    )  # pylint: disable=protected-access
    
  • Do not wrap imports in parentheses and move them to separate lines (see psf/black#3324). Example:

    # Pyink:
    from very_long_top_level_package_name.sub_package.another_level import a_long_module
    
    # Black:
    from very_long_top_level_package_name.sub_package.another_level import (
        a_long_module,
    )
    
  • Add an empty line between class statements without docstrings, and the first method. We expect we will simply remove this difference from Pyink at some point. Example:

    # Pyink:
    class MyTest(unittest.TestCase):
    
        def test_magic(self):
            ...
    
    # Black:
    class MyTest(unittest.TestCase):
        def test_magic(self):
            ...
    
  • Module docstrings are formatted same as other docstrings (see psf/black#3493).

  • Existing parentheses around strings are kept if the content does not fit on a single line. This is related to https://github.com/psf/black/pull/3640 where we still want to keep the parentheses around the implicitly concatenated strings if the code already uses them, making it more obvious it's a single function argument. Example:

    # Original code:
    func1(
        (
            " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
            " incididunt ut labore et dolore magna aliqua Ut enim ad minim"
        ),
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor",
    )
    
    func2(
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
        " incididunt ut labore et dolore magna aliqua Ut enim ad minim",
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor",
    )
    
    # Pyink:
    func1(
        (
            " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
            " incididunt ut labore et dolore magna aliqua Ut enim ad minim"
        ),
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor",
    )
    
    func2(
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
        " incididunt ut labore et dolore magna aliqua Ut enim ad minim",
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor",
    )
    
    # Black:
    func1(
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
        " incididunt ut labore et dolore magna aliqua Ut enim ad minim",
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor",
    )
    
    func2(
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
        " incididunt ut labore et dolore magna aliqua Ut enim ad minim",
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor",
    )
    
  • Temporarily disabled the following Black future style changes:

Historical differences

These are differences that existed in the past. We have upstreamed them to Black so they are now identical.

  • Wrap concatenated strings in parens for function arguments (see psf/black#3292). Example:

    # New:
    function_call(
        (
            " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
            " incididunt ut labore et dolore magna aliqua Ut enim ad minim"
        ),
        " veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo",
    )
    
    # Old:
    function_call(
        " lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor"
        " incididunt ut labore et dolore magna aliqua Ut enim ad minim",
        " veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo",
    )
    
  • Prefer splitting right hand side of assignment statements (see psf/black#1498). Example:

    # New:
    some_dictionary["some_key"] = (
        some_long_expression_causing_long_line
    )
    
    # Old:
    some_dictionary[
        "some_key"
    ] = some_long_expression_causing_long_line
    
  • Prefer not breaking lines between immediately nested brackets (see psf/black#1811). Example:

    # Pyink:
    secrets = frozenset({
        1001,
        1002,
        1003,
        1004,
        1005,
        1006,
        1007,
        1008,
        1009,
    })
    
    # Black:
    secrets = frozenset(
        {
            1001,
            1002,
            1003,
            1004,
            1005,
            1006,
            1007,
            1008,
            1009,
        }
    )
    
  • Support only formatting selected line ranges, using the --pyink-lines= argument (see psf/black#830).

How do I use Pyink?

Same as black, except you'll use pyink. All black command line options are supported by pyink. To configure the options in the pyproject.toml file, you need to put them in the [tool.pyink] section instead of [tool.black].

There are also a few Pyink only options:

  --pyink / --no-pyink            Enable the Pyink formatting mode. Disabling
                                  it should behave the same as Black.
                                  [default: pyink]
  --pyink-indentation [2|4]       The number of spaces used for indentation.
                                  [default: 4]
  --pyink-use-majority-quotes     When normalizing string quotes, infer
                                  preferred quote style by calculating the
                                  majority in the file. Multi-line strings and
                                  docstrings are excluded from this as they
                                  always use double quotes.

Is there a VS Code extension for Pyink?

No, but with a bit workaround, you can use the Black Formatter extension. After installing Pyink and the extension, you can set these in VS Code's settings.json:

{
    "[python]": {
        "editor.defaultFormatter": "ms-python.black-formatter"
    },
    "black-formatter.path": [
        "path/to/pyink"
    ]
}

Can I use Pyink with the pre-commit framework?

Yes! You can put the following in your .pre-commit-config.yaml file:

repos:
  - repo: https://github.com/google/pyink
    rev: 23.3.0
    hooks:
      - id: pyink
        # It is recommended to specify the latest version of Python
        # supported by your project here, or alternatively use
        # pre-commit's default_language_version, see
        # https://pre-commit.com/#top_level-default_language_version
        language_version: python3.9

Why the name?

We want a name with the same number of characters as Black, to make patching easier. And squid ink is black.

License

MIT

Contributing

See the contribution guide.

Changelog

See CHANGES.md.

Disclaimer

This is not an officially supported Google product.

Release files for pyink 26.5.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 pyink 26.5.1
File Size Uploaded
pyink-26.5.1.tar.gz 290.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pyink 26.5.1
File Interpreter ABI Platform
pyink-26.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 434.8 kB

Release files / pyink-26.5.1.tar.gz

Download URL pyink-26.5.1.tar.gz
Size 290.1 kB
Tags Source
SHA-256 checksum
How to use checksums
d74d3aa19102069a679160be50cc1340e2fa9d04eece25c24c583e0d85404302
BLAKE2b-256 checksum
How to use checksums
410d6cbff4b5f012c682b8b65b44b17bea6bbcd5d38a33e4d6dfe70827c60f7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Release files / pyink-26.5.1-py3-none-any.whl

Download URL pyink-26.5.1-py3-none-any.whl
Size 144.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f9fcf06b0f9392a5c034e750676b59df26779e09500bd03db0af12e4639f471a
BLAKE2b-256 checksum
How to use checksums
11fbdb336d1ca75580e53ae009ce91afd72342fe020893962ac727108e498da0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

26.5.1 This release

2 release files

24.3.0

2 release files

23.9.1

2 release files

23.5.0

2 release files

23.3.0

2 release files

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