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
result = some_other_module._private_function(arg="value")
result = some_other_module._private_function(
arg="value"
)
-
Do not wrap imports in parentheses and move them to separate lines (see
psf/black#3324). Example:
from very_long_top_level_package_name.sub_package.another_level import a_long_module
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:
class MyTest(unittest.TestCase):
def test_magic(self):
...
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:
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",
)
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",
)
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:
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",
)
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:
some_dictionary["some_key"] = (
some_long_expression_causing_long_line
)
some_dictionary[
"some_key"
] = some_long_expression_causing_long_line
-
Prefer not breaking lines between immediately nested brackets (see
psf/black#1811). Example:
secrets = frozenset({
1001,
1002,
1003,
1004,
1005,
1006,
1007,
1008,
1009,
})
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
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.