black Documentation

The uncompromising Python code formatter

RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy black on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name black --restart always psf/black:latest

File: README.md

The Uncompromising Code Formatter

β€œAny color you like.”

Black is the uncompromising Python code formatter. By using it, you agree to cede
control over minutiae of hand-formatting. In return, Black gives you speed,
determinism, and freedom from pycodestyle nagging about formatting. You will save time
and mental energy for more important matters.

Blackened code looks the same regardless of the project you're reading. Formatting
becomes transparent after a while and you can focus on the content instead.

Black makes code review faster by producing the smallest diffs possible.

Watch the PyCon 2019 talk to learn more.


Read the documentation on ReadTheDocs!


Installation and usage

Installation

Black can be installed by running pip install black. It requires Python 3.10+ to
run. If you want to format Jupyter Notebooks, install with
pip install "black[jupyter]".

If you want to run Black without installing Python, download one of the
PyInstaller-built standalone executables from the
latest GitHub release.

Usage

To get started right away with sensible defaults:

sh
black {source_file_or_directory}

You can run Black as a package if running it as a script doesn't work:

sh
python -m black {source_file_or_directory}

Further information can be found in our docs:

Black is already successfully used by many
projects, small and big. Black has a comprehensive test suite, with efficient parallel
tests, and our own auto formatting and parallel Continuous Integration runner. Now that
we have become stable, you should not expect large formatting changes in the future.
Stylistic changes will mostly be responses to bug reports and support for new Python
syntax. For more information please refer to
The Black Code Style.

Also, as a safety measure which slows down processing, Black will check that the
reformatted code still produces a valid AST that is effectively equivalent to the
original (see the
Pragmatism
section for details). If you're feeling confident, use --fast.

The _Black_ code style

Black is a PEP 8 compliant opinionated formatter. Black reformats entire files in
place. Style configuration options are deliberately limited and rarely added. It doesn't
take previous formatting into account (see
Pragmatism
for exceptions).

Our documentation covers the current Black code style, but planned changes to it are
also documented. They're both worth taking a look at:

Changes to the Black code style are bound by the Stability Policy:

Please refer to this document before submitting an issue. What seems like a bug might be
intended behaviour.

Pragmatism

Early versions of Black used to be absolutist in some respects. They took after its
initial author. This was fine at the time as it made the implementation simpler and
there were not many users anyway. Not many edge cases were reported. As a mature tool,
Black does make some exceptions to rules it otherwise holds.

Please refer to this document before submitting an issue just like with the document
above. What seems like a bug might be intended behaviour.

Configuration

Black is able to read project-specific default values for its command line options
from a pyproject.toml file. This is especially useful for specifying custom
--include and --exclude/--force-exclude/--extend-exclude patterns for your
project.

You can find more details in our documentation:

And if you're looking for more general configuration documentation:

Pro-tip: If you're asking yourself "Do I need to configure anything?" the answer is
"No". Black is all about sensible defaults. Applying those defaults will have your
code in compliance with many other Black formatted projects.

Used by

The following notable open-source projects trust Black with enforcing a consistent
code style: pytest, tox, Pyramid, Django, Django Channels, Hypothesis, attrs,
SQLAlchemy, Poetry, PyPA applications (Warehouse, Bandersnatch, Pipenv, virtualenv),
pandas, Pillow, Twisted, LocalStack, every Datadog Agent Integration, Home Assistant,
Zulip, Kedro, OpenOA, FLORIS, ORBIT, WOMBAT, and many more.

The following organizations use Black: Dropbox, KeepTruckin, Lyft, Mozilla, Quora,
Duolingo, QuantumBlack, Tesla, Archer Aviation.

Are we missing anyone? Let us know.

Testimonials

Mike Bayer, creator of SQLAlchemy:

I can't think of any single tool in my entire programming career that has given me a
bigger productivity increase by its introduction. I can now do refactorings in about
1% of the keystrokes that it would have taken me previously when we had no way for
code to format itself.

Dusty Phillips,
writer:

Black is opinionated so you don't have to be.

Hynek Schlawack, creator of attrs, core developer of
Twisted and CPython:

An auto-formatter that doesn't suck is all I want for Xmas!

Carl Meyer, Django core developer:

At least the name is good.

Kenneth Reitz, creator of requests
and pipenv:

This vastly improves the formatting of our code. Thanks a ton!

Show your style

Use the badge in your project's README.md:

md
[](https://github.com/psf/black)

Using the badge in README.rst:

rst
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
    :target: https://github.com/psf/black

Looks like this:

License

MIT

Contributing

Welcome! Happy to see you willing to make the project better. You can get started by
reading this:

You can also take a look at the rest of the contributing docs or talk with the
developers:

Change log

The log has become rather long. It moved to its own file.

See CHANGES.

Authors

The author list is quite long nowadays, so it lives in its own file.

See AUTHORS.md

Code of Conduct

Everyone participating in the Black project, and in particular in the issue tracker,
pull requests, and social media activity, is expected to treat other people with respect
and more generally to follow the guidelines articulated in the
Python Community Code of Conduct.

At the same time, humor is encouraged. In fact, basic familiarity with Monty Python's
Flying Circus is expected. We are not savages.

And if you really need to slap somebody, do it with a fish while dancing.


File: docs/contributing/gauging_changes.md

Gauging changes

A lot of the time, your change will affect formatting and/or performance. Quantifying
these changes is hard, so we have tooling to help make it easier.

It's recommended you evaluate the quantifiable changes your Black formatting
modification causes before submitting a PR. Think about if the change seems disruptive
enough to cause frustration to projects that are already "Black-formatted".

diff-shades

diff-shades is a tool that runs Black across a list of open-source projects recording
the results. The main highlight feature of diff-shades is being able to compare two
revisions of Black. This is incredibly useful as it allows us to see what exact
changes will occur, say merging a certain PR.

For more information, please see the diff-shades documentation.

CI integration

diff-shades is also the tool behind the "diff-shades results comparing ..." comments on
PRs. The project has a GitHub Actions workflow that analyzes and compares two revisions
of Black according to these rules:

Baseline revision Target revision
On PRs latest commit on PR base branch PR commit with main merged
On pushes (main only) latest PyPI version the pushed commit

For pushes to main, there's only one analysis job named preview-new-changes where the
preview style is used for all projects.

For PRs they get one more analysis job: assert-no-changes. It's similar to
preview-new-changes but runs with the stable code style. It will fail if changes were
made. This makes sure code won't be reformatted again and again within the same year in
accordance to Black's stability policy.

Additionally for PRs, a PR comment will be posted embedding a summary previewing any
changes in both styles and links to further information. The next time the workflow is
triggered on the same PR, it'll update the pre-existing diff-shades comment.

{note}
Jobs will only fail intentionally if a file failed to format while analyzing, or if
changes were made to the stable style. Otherwise a failure indicates a bug in the
workflow.

The workflow uploads several artifacts upon completion:

  • HTML diffs (.html)
    • handy for pushes where there's no PR to post a comment
  • The raw analyses (.json)
    • in case you want to do further analysis using the collected data locally
  • .preview.pr-comment.md and .stable.pr-comment.md (if triggered by a PR)
    • used to generate the PR comment and shouldn't be downloaded

File: docs/contributing/index.md

Contributing

{toctree}
---
hidden:
---

the_basics
gauging_changes
issue_triage
release_process

Welcome! Happy to see you willing to make the project better. Have you read the entire
user documentation yet?

{rubric} bird's eye view

In terms of inspiration, Black is about as configurable as gofmt (which is to say,
not very). This is deliberate. Black aims to provide a consistent style and take away
opportunities for arguing about style.

Bug reports and fixes are always welcome! Please follow the
issue templates on GitHub for best
results.

Before you suggest a new feature or configuration knob, ask yourself why you want it. If
it enables better integration with some workflow, fixes an inconsistency, speeds things
up, and so on - go for it! On the other hand, if your answer is "because I don't like a
particular formatting" then you're not ready to embrace Black yet. Such changes are
unlikely to get accepted. You can still try but prepare to be disappointed.

{rubric} contents

This section covers the following topics:

  • {doc}the_basics
  • {doc}gauging_changes
  • {doc}release_process

For an overview on contributing to the Black, please checkout {doc}the_basics.


File: docs/contributing/issue_triage.md

Issue triage

Currently, Black uses the issue tracker for bugs, feature requests, proposed style
modifications, and general user support. Each of these issues have to be triaged so they
can be eventually be resolved somehow. This document outlines the triaging process and
also the current guidelines and recommendations.

{tip}
If you're looking for a way to contribute without submitting patches, this might be the
area for you. Since _Black_ is a popular project, its issue tracker is quite busy and
always needs more attention than is available. While triage isn't the most glamorous or
technically challenging form of contribution, it's still important. For example, we
would love to know whether that old bug report is still reproducible!

You can get easily started by reading over this document and then responding to issues.

If you contribute enough and have stayed for long enough, you may even be given
Triage permissions!

The basics

Black gets a whole bunch of different issues, they range from bug reports to user
support issues. To triage is to identify, organize, and kickstart the issue's journey
through its lifecycle to resolution.

More specifically, to triage an issue means to:

  • identify what type and categories the issue falls under
  • confirm bugs
  • ask questions / for further information if necessary
  • link related issues
  • provide the first initial feedback / support

Note that triage is typically the first response to an issue, so don't fret if the issue
doesn't make much progress after initial triage. The main goal of triaging to prepare
the issue for future more specific development or discussion, so eventually it will be
resolved.

The lifecycle of a bug report or user support issue typically goes something like this:

  1. the issue is waiting for triage
  2. identified - has been marked with a type label and other relevant labels, more
    details or a functional reproduction may be still needed (and therefore should be
    marked with S: needs repro or S: awaiting response)
  3. confirmed - the issue can reproduced and necessary details have been provided
  4. discussion - initial triage has been done and now the general details on how the
    issue should be best resolved are being hashed out
  5. awaiting fix - no further discussion on the issue is necessary and a resolving PR
    is the next step
  6. closed - the issue has been resolved, reasons include:
    • the issue couldn't be reproduced
    • the issue has been fixed
    • duplicate of another pre-existing issue or is invalid

For enhancement, documentation, and style issues, the lifecycle looks very similar but
the details are different:

  1. the issue is waiting for triage
  2. identified - has been marked with a type label and other relevant labels
  3. discussion - the merits of the suggested changes are currently being discussed, a
    PR would be acceptable but would be at significant risk of being rejected
  4. accepted & awaiting PR - it's been determined the suggested changes are OK and a
    PR would be welcomed (S: accepted)
  5. closed: - the issue has been resolved, reasons include:
    • the suggested changes were implemented
    • it was rejected (due to technical concerns, ethos conflicts, etc.)
    • duplicate of a pre-existing issue or is invalid

Note: documentation issues don't use the S: accepted label currently since they're
less likely to be rejected.

Labelling

We use labels to organize, track progress, and help effectively divvy up work.

Our labels are divided up into several groups identified by their prefix:

  • T - Type: the general flavor of issue / PR
  • C - Category: areas of concerns, ranges from bug types to project maintenance
  • F - Formatting Area: like C but for formatting specifically
  • S - Status: what stage of resolution is this issue currently in?
  • R - Resolution: how / why was the issue / PR resolved?

We also have a few standalone labels:

  • good first issue: issues that are beginner-friendly (and will show up in GitHub
    banners for first-time visitors to the repository)
  • help wanted: complex issues that need and are looking for a fair bit of work as
    to progress (will also show up in various GitHub pages)
  • ci: skip news: for PRs that are trivial and don't need a CHANGELOG entry (and
    skips the CHANGELOG entry check)
  • ci: build all wheels: when a full wheel build is needed, such as to debug
    platform-specific issues. Black does not build wheels for every platform on each pull
    request because the full build matrix is expensive. After the label is added, the
    workflow starts only when a new commit is pushed.
{note}
We do use labels for PRs, in particular the `ci: skip news` label, but we aren't that
rigorous about it. Just follow your judgement on what labels make sense for the specific
PR (if any even make sense).

Projects

For more general and broad goals we use projects to track work. Some may be long-term
projects with no true end (e.g. the "Amazing documentation" project) while others may be
more focused and have a definite end (like the "Getting to beta" project).

{note}
To modify GitHub Projects you need the
[Write repository permission level or higher](https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-permission-levels-for-an-organization#repository-access-for-each-permission-level).

Closing issues

Closing an issue signifies the issue has reached the end of its life, so closing issues
should be taken with care. The following is the general recommendation for each type of
issue. Note that these are only guidelines and if your judgement says something else
it's totally cool to go with it instead.

For most issues, closing the issue manually or automatically after a resolving PR is
ideal. For bug reports specifically, if the bug has already been fixed, try to check in
with the issue opener that their specific case has been resolved before closing. Note
that we close issues as soon as they're fixed in the main branch. This doesn't
necessarily mean they've been released yet.

Design and enhancement issues should be also closed when it's clear the proposed change
won't be implemented, whether that has been determined after a lot of discussion or just
simply goes against Black's ethos. If such an issue turns heated, closing and locking
is acceptable if it's severe enough (although checking in with the core team is probably
a good idea).

User support issues are best closed by the author or when it's clear the issue has been
resolved in some sort of manner.

Duplicates and invalid issues should always be closed since they serve no purpose and
add noise to an already busy issue tracker. Although be careful to make sure it's truly
a duplicate and not just very similar before labelling and closing an issue as
duplicate.

Common reports

Some issues are frequently opened, like issues about Black formatted code causing E203
messages. Even though these issues are probably heavily duplicated, they still require
triage sucking up valuable time from other things (although they usually skip most of
their lifecycle since they're closed on triage).

Here's some of the most common issues and also pre-made responses you can use:

"The trailing comma isn't being removed by Black!"

text
Black used to remove the trailing comma if the expression fits in a single line, but this was changed by #826 and #1288. Now a trailing comma tells Black to always explode the expression. This change was made mostly for the cases where you _know_ a collection or whatever will grow in the future. Having it always exploded as one element per line reduces diff noise when adding elements. Before the "magic trailing comma" feature, you couldn't anticipate a collection's growth reliably since collections that fitted in one line were ruthlessly collapsed regardless of your intentions. One of Black's goals is reducing diff noise, so this was a good pragmatic change.

So no, this is not a bug, but an intended feature. Anyway, [here's the documentation](https://github.com/psf/black/blob/main/docs/the_black_code_style/current_style.md#the-magic-trailing-comma) on the "magic trailing comma", including the ability to skip this functionality with the `--skip-magic-trailing-comma` option. Hopefully that helps solve the possible confusion.

"Black formatted code is violating Flake8's E203!"

text
Hi,

This is expected behaviour, please see the documentation regarding this case (emphasis mine):

> PEP 8 recommends to treat : in slices as a binary operator with the lowest priority, and to leave an equal amount of space on either side, **except if a parameter is omitted (e.g. ham[1 + 1 :])**. It recommends no spaces around : operators for β€œsimple expressions” (ham[lower:upper]), and **extra space for β€œcomplex expressions” (ham[lower : upper + offset])**. **Black treats anything more than variable names as β€œcomplex” (ham[lower : upper + 1]).** It also states that for extended slices, both : operators have to have the same amount of spacing, except if a parameter is omitted (ham[1 + 1 ::]). Black enforces these rules consistently.

> This behaviour may raise E203 whitespace before ':' warnings in style guide enforcement tools like Flake8. **Since E203 is not PEP 8 compliant, you should tell Flake8 to ignore these warnings**.

https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices

Have a good day!

File: docs/contributing/release_process.md

Release process

Black has had a lot of work done into standardizing and automating its release
process. This document sets out to explain how everything works and how to release
Black using said automation.

Release cadence

We aim to release whatever is on main every 1-2 months. This ensures merged
improvements and bugfixes are shipped to users reasonably quickly, while not massively
fracturing the user-base with too many versions. This also keeps the workload on
maintainers consistent and predictable.

If there's not much new on main to justify a release, it's acceptable to skip a
month's release. Ideally January releases should not be skipped because as per our
stability policy, the first release in a new calendar year
may make changes to the stable style. While the policy applies to the first release
(instead of only January releases), confining changes to the stable style to January
will keep things predictable (and nicer) for users.

Unless there is a serious regression or bug that requires immediate patching, there
should not be more than one release per month
. While version numbers are cheap,
releases require a maintainer to both commit to do the actual cutting of a release, but
also to be able to deal with the potential fallout post-release. Releasing more
frequently than monthly nets rapidly diminishing returns.

Cutting a release

You must have write permissions for the Black repository to cut a release.

The 10,000 foot view of the release process is that you prepare a release PR and then
publish a GitHub Release. This triggers release automation that
builds all release artifacts and publishes them to the various platforms we publish to.

We now have a scripts/release.py script to help with cutting the release PRs.

  • python3 scripts/release.py --help is your friend.
    • release.py has only been tested in Python 3.12+ (so get with the times :D)

To cut a release:

  1. Determine the release's version number
    • Black follows the CalVer versioning standard using the YY.M.N format
      • So unless there already has been a release during this month, N should be 0
    • Example: the first release in January, 2026 β†’ 26.1.0
    • release.py will calculate this and log it to stdout for your copy-paste pleasure
  2. Double-check that no changelog entries since the last release were put in the wrong
    section (e.g., run git diff origin/stable CHANGES.md)
  3. File a PR editing CHANGES.md and the docs to version the latest changes
    • Run python3 scripts/release.py [--debug] to generate most changes
  4. If release.py fails manually edit; otherwise, yay, skip this step!
    1. Replace the ## Unreleased header with the version number
    2. Remove any empty sections for the current release
    3. (optional) Read through and copy-edit the changelog (eg. by moving entries,
      fixing typos, or rephrasing entries)
  5. Update references to the latest version in
    {doc}/integrations/source_version_control and
    {doc}/usage_and_configuration/the_basics
  6. Once the release PR is merged, wait until all CI passes
    • If CI does not pass, stop and investigate the failure(s) as generally we'd want
      to fix failing CI before cutting a release
  7. Draft a new GitHub Release
    1. Click Choose a tag and type in the version number, then select the
      Create new tag: YY.M.N on publish option that appears
    2. Verify that the new tag targets the main branch
    3. Make sure the release title is set to the version (YY.M.N), as otherwise the
      default title is the last commit's title
    4. Copy and paste the raw changelog Markdown for the current release into the
      description box
  8. Publish the GitHub Release, triggering release automation that
    will handle the rest
  9. Once CI is done add + PR a new empty template for the next release to CHANGES.md
    (Template is able to be copy pasted from release.py should we fail)
    1. python3 scripts/release.py --add-changes-template|-a [--debug]
    2. Should that fail, please return to copy + paste
  10. At this point, you're basically done. It's good practice to go and watch and verify
    that all the release workflows pass
    , although you will receive a
    GitHub notification should something fail.
    • If something fails, don't panic. Please go read the respective workflow's logs and
      configuration file to reverse-engineer your way to a fix/solution.

Congratulations! You've successfully cut a new release of Black. Go and stand up and
take a break, you deserve it.

{important}
Once the release artifacts reach PyPI, you may see new issues being filed indicating
regressions. While regressions are not great, they don't automatically mean a hotfix
release is warranted. Unless the regressions are serious and impact many users, a hotfix
release is probably unnecessary.

In the end, use your best judgement and ask other maintainers for their thoughts.

Release workflows

All of Black's release automation uses GitHub Actions. All workflows are therefore
configured using YAML files in the .github/workflows directory of the Black
repository.

They are triggered by the publication of a GitHub Release.

Below are descriptions of our release workflows.

build and publish

This is our main workflow. It builds an sdist and wheels to upload to PyPI where the
vast majority of users will download Black from. It's divided into three job groups:

sdist + pure wheel

This single job builds the sdist and pure Python wheel (i.e., a wheel that only contains
Python code) using Hatch. These artifacts are general-purpose and can be used on
basically any platform supported by Python.

generate wheels matrix / mypyc wheels (…)

We use mypyc to compile Black into a CPython C extension for significantly improved
performance. Wheels built with mypyc are platform and Python version specific.
Supported platforms are documented in the FAQ.

These matrix jobs use cibuildwheel which handles the complicated task of building C
extensions for many environments for us. Since building these wheels is slow, there are
multiple mypyc wheels jobs (hence the term "matrix") that build for a specific platform
(as noted in the job name in parentheses).

publish-hatch / publish-mypyc

These jobs upload the built sdist and all wheels to PyPI using Trusted
publishing
.

publish binaries

This workflow builds native executables for multiple platforms using PyInstaller. This
allows people to download the executable for their platform and run Black without a
Python runtime installed.

The created binaries are stored on the associated GitHub Release for download over IPv4
only
(GitHub still does not have IPv6 access 😒).

docker

This workflow uses the QEMU powered buildx feature of Docker to upload an arm64 and
amd64/x86_64 build of the official Black Docker imageβ„’.

  • Currently this workflow uses an API Token associated with @cooperlees account
{note}
This also runs on each push to `main`.

post release

This workflow runs a few miscellaneous jobs related to repository maintenance.

update-stable

Updates the stable branch by force pushing it to the most recent tag. This saves us
from remembering to update the branch sometime after cutting the release.

new-changelog

Opens a new PR to add the "Unreleased" section back to the changelog. The PR is
intentionally not auto-merged, in case there's an issue and the release needs to be
re-cut.


File: docs/contributing/the_basics.md

The basics

An overview on contributing to the Black project.

Technicalities

Development on the latest version of Python is preferred. You can use any operating
system.

First clone the Black repository:

console
$ git clone https://github.com/psf/black.git
$ cd black

Then install development dependencies inside a virtual environment of your choice, for
example:

console
$ python3 -m venv .venv
$ source .venv/bin/activate # activation for linux and mac
$ .venv\Scripts\activate # activation for windows

(.venv)$ pip install --group dev
(.venv)$ pip install -e ".[d]"
(.venv)$ pre-commit install

Before submitting pull requests, run lints and tests with the following commands from
the root of the black repo:

console
(.venv)$ pre-commit run -a # Linting
(.venv)$ tox -e py # Unit tests
(.venv)$ tox -e fuzz # Optional Fuzz testing
(.venv)$ tox -e run_self # Format Black itself

Development

Further examples of invoking the tests

console
(.venv)$ tox --parallel=auto # Run all the above in parallel
(.venv)$ tox -e py314 # Run tests on a specific python version
(.venv)$ pytest -k <test name> # Run an individual test
(.venv)$ tox -e py -- --no-cov # Pass arguments to pytest

Testing

All aspects of the Black style should be tested. Normally, tests should be created as
files in the tests/data/cases directory. These files consist of up to three parts:

  • A line that starts with # flags: followed by a set of command-line options. For
    example, if the line is # flags: --preview --skip-magic-trailing-comma, the test
    case will be run with preview mode on and the magic trailing comma off. The options
    accepted are mostly a subset of those of Black itself, except for the
    --minimum-version= flag, which should be used when testing a grammar feature that
    works only in newer versions of Python. This flag ensures that we don't try to
    validate the AST on older versions and tests that we autodetect the Python version
    correctly when the feature is used. For the exact flags accepted, see the function
    get_flags_parser in tests/util.py. If this line is omitted, the default options
    are used.
  • A block of Python code used as input for the formatter.
  • The line # output, followed by the output of Black when run on the previous block.
    If this is omitted, the test asserts that Black will leave the input code unchanged.

Black has two pytest command-line options affecting test files in tests/data/ that
are split into an input part, and an output part, separated by a line with # output.
These can be passed to pytest through tox, or directly into pytest if not using
tox.

Upon a failing test, print the full concrete syntax tree (CST) as it is after processing
the input ("actual"), and the tree that's yielded after parsing the output ("expected").
Note that a test can fail with different output with the same CST. This used to be the
default, but now defaults to False.

console
(.venv)$ tox -e py -- --print-full-tree

Upon a failing test, print the diff of the trees as described above. This is the
default. To turn it off pass --print-tree-diff=False.

console
(.venv)$ tox -e py -- --print-tree-diff=False

News / Changelog Requirement

Black has CI that will check for an entry corresponding to your PR in CHANGES.md. If
you feel this PR does not require a changelog entry please state that in a comment and a
maintainer can add a ci: skip news label to make the CI pass. Otherwise, please ensure
you have a line in the following format added below the appropriate header:

md
- `Black` is now more awesome (#X)

Note that X should be your PR number, not issue number! To workout X, please use
Next PR Number. This
is not perfect but saves a lot of release overhead as now the releaser does not need to
go back and workout what to add to the CHANGES.md for each release.

Style Changes

Please familiarize yourself with our stability policy.
Therefore, most style changes must be added to the --preview style. Exceptions are
fixing crashes or changes that would not affect an already-formatted file.

If a change would affect the advertised code style, please modify the documentation (The
Black code style) to reflect that change. Patches that fix unintended bugs in
formatting don't need to be mentioned separately.

If the change is implemented with the --preview flag, please include the change in the
Future Style document instead and write the changelog entry under the dedicated "Preview
style" heading.

Docs Testing

If you make changes to docs, you can test they still build locally too.

console
(.venv)$ pip install --group docs
(.venv)$ pip install -e ".[d]"
(.venv)$ sphinx-build -a -b html -W docs/ docs/_build/

Hygiene

If you're fixing a bug, add a test. Run it first to confirm it fails, then fix the bug,
and run the test again to confirm it's really fixed.

If adding a new feature, add a test. In fact, always add a test. If adding a large
feature, please first open an issue to discuss it beforehand.

Finally

Thanks again for your interest in improving the project! You're taking action when most
people decide to sit and watch.


File: docs/guides/index.md

Guides

{toctree}
---
hidden:
---

introducing_black_to_your_project
using_black_with_other_tools
using_black_with_jupyter_notebooks

Wondering how to do something specific? You've found the right place! Listed below are
topic specific guides available:

  • {doc}introducing_black_to_your_project
  • {doc}using_black_with_other_tools
  • {doc}using_black_with_jupyter_notebooks

File: docs/guides/introducing_black_to_your_project.md

Introducing _Black_ to your project

{note}
This guide is incomplete. Contributions are welcomed and would be deeply appreciated!

Avoiding ruining git blame

A long-standing argument against moving to automated code formatters like Black is
that the migration will clutter up the output of git blame. This was a valid argument,
but since Git version 2.23, Git natively supports
ignoring revisions in blame
with the --ignore-rev option. You can also pass a file listing the revisions to ignore
using the --ignore-revs-file option. The changes made by the revision will be ignored
when assigning blame. Lines modified by an ignored revision will be blamed on the
previous revision that modified those lines.

So when migrating your project's code style to Black, reformat everything and commit
the changes (preferably in one massive commit). Then put the full 40 characters commit
identifier(s) into a file usually called .git-blame-ignore-revs at the root of your
project directory.

text
# Migrate code style to Black
5b4ab991dede475d393e9d69ec388fd6bd949699

Afterwards, you can pass that file to git blame and see clean and meaningful blame
information.

console
$ git blame important.py --ignore-revs-file .git-blame-ignore-revs
7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 1) def very_important_function(text, file):
abdfd8b0 (Alice Doe  2019-09-23 11:39:32 -0400 2)     text = text.lstrip()
7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 3)     with open(file, "r+") as f:
7a1ae265 (John Smith 2019-04-15 15:55:13 -0400 4)         f.write(formatted)

You can even configure git to automatically ignore revisions listed in a file on every
call to git blame.

console
$ git config blame.ignoreRevsFile .git-blame-ignore-revs

The one caveat is that some online Git-repositories do not yet support ignoring
revisions using their native blame UI.
So blame information will be cluttered with a
reformatting commit on those platforms. However,
GitHub
and
GitLab (since version 17.10)
both support .git-blame-ignore-revs in blame views by default.


File: docs/guides/using_black_with_other_tools.md

Using _Black_ with other tools

Black compatible configurations

All of Black's changes are harmless (or at least, they should be), but a few do conflict
against other tools. It is not uncommon to be using other tools alongside Black like
linters and type checkers. Some of them need a bit of tweaking to resolve the conflicts.
Listed below are Black compatible configurations in various formats for the common
tools out there.

Please note that Black only supports the TOML file format for its configuration
(e.g. pyproject.toml). The provided examples are to only configure their corresponding
tools, using their supported file formats.

Compatible configuration files can be
found here.

isort

isort helps to sort and format imports in your Python
code. Black also formats imports, but in a different way from isort's defaults which
leads to conflicting changes.

Profile

Since version 5.0.0, isort supports
profiles to allow
easy interoperability with common code styles. You can set the black profile in any of
the
config files
supported by isort. Below, an example for pyproject.toml:

toml
[tool.isort]
profile = "black"

Custom Configuration

If you're using an isort version that is older than 5.0.0 or you have some custom
configuration for Black, you can tweak your isort configuration to make it compatible
with Black. Below, an example for .isort.cfg:

ini
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88

Why those options above?

Black wraps imports that surpass line-length by moving identifiers onto separate
lines and by adding a trailing comma after each. A more detailed explanation of this
behaviour can be
found here.

isort's default mode of wrapping imports that extend past the line_length limit is
"Grid".

python
from third_party import (lib1, lib2, lib3,
                         lib4, lib5, ...)

This style is incompatible with Black, but isort can be configured to use a different
wrapping mode called "Vertical Hanging Indent" which looks like this:

python
from third_party import (
    lib1,
    lib2,
    lib3,
    lib4,
)

This style is Black compatible and can be achieved by multi-line-output = 3. Also,
as mentioned above, when wrapping long imports Black puts a trailing comma and uses
parentheses. isort should follow the same behaviour and passing the options
include_trailing_comma = True and use_parentheses = True configures that.

The option force_grid_wrap = 0 is just to tell isort to only wrap imports that surpass
the line_length limit.

Finally, isort should be told to wrap imports when they surpass Black's default limit
of 88 characters via line_length = 88 as well as
ensure_newline_before_comments = True to ensure spacing import sections with comments
works the same as with Black.

Please note ensure_newline_before_comments = True only works since isort >= 5 but
does not break older versions so you can keep it if you are running previous versions.

Formats

.isort.cfg

ini
[settings]
profile = black

setup.cfg

ini
[isort]
profile = black

pyproject.toml

toml
[tool.isort]
profile = 'black'

.editorconfig

ini
[*.py]
profile = black

pycodestyle

pycodestyle is a code linter. It warns you
of syntax errors, possible bugs, stylistic errors, etc. For the most part, pycodestyle
follows PEP 8 when warning about stylistic errors.
There are a few deviations that cause incompatibilities with Black.

Configuration

ini
max-line-length = 88
ignore = E203,E701

(labels/why-pycodestyle-warnings)=

Why those options above?

`max-line-length`

As with isort, pycodestyle should be configured to allow lines up to the length limit of
88, Black's default.

`E203`

In some cases, as determined by PEP 8, Black will enforce an equal amount of
whitespace around slice operators. Due to this, pycodestyle will raise
E203 whitespace before ':' warnings. Since this warning is not PEP 8 compliant, it
should be disabled.

`E701` / `E704`

Black will collapse implementations of classes and functions consisting solely of ..
to a single line. This matches how such examples are formatted in PEP 8. It remains true
that in all other cases Black will prevent multiple statements on the same line, in
accordance with PEP 8 generally discouraging this.

However, pycodestyle does not mirror this logic and may raise
E701 multiple statements on one line (colon) in this situation. Its
disabled-by-default E704 multiple statements on one line (def) rule may also raise
warnings and should not be enabled.

`W503`

When breaking a line, Black will break it before a binary operator. This is compliant
with PEP 8 as of
April 2016.
There's a disabled-by-default warning in Flake8 which goes against this PEP 8
recommendation called W503 line break before binary operator. It should not be enabled
in your configuration. You can use its counterpart
W504 line break after binary operator instead.

Formats

setup.cfg, .pycodestyle, tox.ini

ini
[pycodestyle]
max-line-length = 88
ignore = E203,E701

Flake8

Flake8 is a wrapper around multiple linters,
including pycodestyle. As such, it has many of the same issues.

Bugbear

It's recommended to use the Bugbear plugin
and enable
its B950 check
instead of using Flake8's E501, because it aligns with
Black's 10% rule.

Install Bugbear and use the following config:

ini
[flake8]
max-line-length = 80
extend-select = B950
extend-ignore = E203,E501,E701

Minimal Configuration

In cases where you can't or don't want to install Bugbear, you can use this minimally
compatible config:

ini
[flake8]
max-line-length = 88
extend-ignore = E203,E701

Why those options above?

See the pycodestyle section above.

Formats

.flake8, setup.cfg, tox.ini

ini
[flake8]
max-line-length = 88
extend-ignore = E203,E701

Pylint

Pylint is also a code linter like Flake8. It has many
of the same checks as Flake8 and more. It particularly has more formatting checks
regarding style conventions like variable naming.

Configuration

ini
max-line-length = 88

Why those options above?

Pylint should be configured to only complain about lines that surpass 88 characters
via max-line-length = 88.

If using pylint<2.6.0, also disable C0326 and C0330 as these are incompatible with
Black formatting and have since been removed.

Formats

pylintrc

ini
[format]
max-line-length = 88

setup.cfg

ini
[pylint]
max-line-length = 88

pyproject.toml

toml
[tool.pylint.format]
max-line-length = "88"

File: docs/integrations/editors.md

Editor integration

Emacs

Options include the following:

PyCharm/IntelliJ IDEA

There are several different ways you can use Black from PyCharm:

  1. Using the built-in Black integration (PyCharm 2023.2 and later). This option is the
    simplest to set up.
  2. As local server using the BlackConnect plugin. This option formats the fastest. It
    spins up {doc}Black's HTTP server , to
    avoid the startup cost on subsequent formats.
  3. As external tool.
  4. As file watcher.

Built-in _Black_ integration

  1. Install black.

    console
    $ pip install black
  2. Go to Preferences or Settings -> Tools -> Black and configure Black to your
    liking.

As local server

  1. Install Black with the d extra.

    console
    $ pip install 'black[d]'
  2. Install
    BlackConnect IntelliJ IDEs plugin.

  3. Open plugin configuration in PyCharm/IntelliJ IDEA

    On macOS:

    PyCharm -> Preferences -> Tools -> BlackConnect

    On Windows / Linux / BSD:

    File -> Settings -> Tools -> BlackConnect

  4. In Local Instance (shared between projects) section:

    1. Check Start local blackd instance when plugin loads.
    2. Press the Detect button near Path input. The plugin should detect the blackd
      executable.
  5. In Trigger Settings section check Trigger on code reformat to enable code
    reformatting with Black.

  6. Format the currently opened file by selecting Code -> Reformat Code or using a
    shortcut.

  7. Optionally, to run Black on every file save:

    • In Trigger Settings section of plugin configuration check
      Trigger when saving changed files.

As external tool

  1. Install black.

    console
    $ pip install black
  2. Locate your black installation folder.

    On macOS / Linux / BSD:

    console
    $ which black
    /usr/local/bin/black  # possible location

    On Windows:

    console
    $ where black
    C:\Program Files\Python313\Scripts\black.exe  # possible location

    Note that if you are using a virtual environment detected by PyCharm, this is an
    unneeded step. In this case the path to black is $PyInterpreterDirectory$/black.

  3. Open External tools in PyCharm/IntelliJ IDEA

    On macOS:

    PyCharm -> Preferences -> Tools -> External Tools

    On Windows / Linux / BSD:

    File -> Settings -> Tools -> External Tools

  4. Click the + icon to add a new external tool with the following values:

    • Name: Black
    • Description: Black is the uncompromising Python code formatter.
    • Program: \
    • Arguments: "$FilePath$"
  5. Format the currently opened file by selecting Tools -> External Tools -> black.

    • Alternatively, you can set a keyboard shortcut by navigating to
      Preferences or Settings -> Keymap -> External Tools -> External Tools - Black.

As file watcher

  1. Install black.

    console
    $ pip install black
  2. Locate your black installation folder.

    On macOS / Linux / BSD:

    console
    $ which black
    /usr/local/bin/black  # possible location

    On Windows:

    console
    $ where black
    C:\Program Files\Python313\Scripts\black.exe  # possible location

    Note that if you are using a virtual environment detected by PyCharm, this is an
    unneeded step. In this case the path to black is $PyInterpreterDirectory$/black.

  3. Make sure you have the
    File Watchers plugin
    installed.

  4. Go to Preferences or Settings -> Tools -> File Watchers and click + to add a new
    watcher:

    • Name: Black
    • File type: Python
    • Scope: Project Files
    • Program: \
    • Arguments: $FilePath$
    • Output paths to refresh: $FilePath$
    • Working directory: $ProjectFileDir$
  • In Advanced Options
    • Uncheck "Auto-save edited files to trigger the watcher"
    • Uncheck "Trigger the watcher on external changes"

Wing IDE

Wing IDE supports black via Preference Settings for system wide settings and
Project Properties for per-project or workspace specific settings, as explained in
the Wing documentation on
Auto-Reformatting. The detailed
procedure is:

Prerequisites

  • Wing IDE version 8.0+

  • Install black.

    console
    $ pip install black
  • Make sure it runs from the command line, e.g.

    console
    $ black --help

Preference Settings

If you want Wing IDE to always reformat with black for every project, follow these
steps:

  1. In menubar navigate to Edit -> Preferences -> Editor -> Reformatting.

  2. Set Auto-Reformat from disable (default) to Line after edit or
    Whole files before save.

  3. Set Reformatter from PEP8 (default) to Black.

Project Properties

If you want to just reformat for a specific project and not intervene with Wing IDE
global setting, follow these steps:

  1. In menubar navigate to Project -> Project Properties -> Options.

  2. Set Auto-Reformat from Use Preferences setting (default) to Line after edit
    or Whole files before save.

  3. Set Reformatter from Use Preferences setting (default) to Black.

Vim

Official plugin

Commands and shortcuts:

  • :Black to format the entire file (ranges not supported);
    • you can optionally pass target_version=<version> with the same values as in the
      command line.
  • :BlackUpgrade to upgrade Black inside the virtualenv;
  • :BlackVersion to get the current version of Black in use.

Configuration:

  • g:black_fast (defaults to 0)
  • g:black_linelength (defaults to 88)
  • g:black_skip_string_normalization (defaults to 0)
  • g:black_skip_magic_trailing_comma (defaults to 0)
  • g:black_virtualenv (defaults to ~/.vim/black or ~/.local/share/nvim/black)
  • g:black_use_virtualenv (defaults to 1)
  • g:black_target_version (defaults to "")
  • g:black_quiet (defaults to 0)
  • g:black_preview (defaults to 0)

Installation

This plugin requires Vim 7.0+ built with Python 3.10+ support. It needs Python 3.10
to be able to run Black inside the Vim process which is much faster than calling an
external command.

`vim-plug`

To install with vim-plug:

Black's stable branch tracks official version updates, and can be used to simply
follow the most recent stable version.

vim
Plug 'psf/black', { 'branch': 'stable' }

Another option which is a bit more explicit and offers more control is to use
vim-plug's tag option with a shell wildcard. This will resolve to the latest tag
which matches the given pattern.

The following matches all stable versions (see the
Release Process section for documentation of
version scheme used by Black):

vim
Plug 'psf/black', { 'tag': '*.*.*' }

and the following demonstrates pinning to a specific year's stable style (2026 in this
case):

vim
Plug 'psf/black', { 'tag': '26.*.*' }

Vundle

or with Vundle:

vim
Plugin 'psf/black'

and execute the following in a terminal:

console
$ cd ~/.vim/bundle/black
$ git checkout origin/stable -b stable

Arch Linux

On Arch Linux, the plugin is shipped with the
python-black package, so you
can start using it in Vim after install with no additional setup.

Vim 8 Native Plugin Management

or you can copy the plugin files from
plugin/black.vim and
autoload/black.vim.

sh
mkdir -p ~/.vim/pack/python/start/black/plugin
mkdir -p ~/.vim/pack/python/start/black/autoload
curl https://raw.githubusercontent.com/psf/black/stable/plugin/black.vim -o ~/.vim/pack/python/start/black/plugin/black.vim
curl https://raw.githubusercontent.com/psf/black/stable/autoload/black.vim -o ~/.vim/pack/python/start/black/autoload/black.vim

Let me know if this requires any changes to work with Vim 8's builtin packadd, or
Pathogen, and so on.

Usage

On first run, the plugin creates its own virtualenv using the right Python version and
automatically installs Black. You can upgrade it later by calling :BlackUpgrade and
restarting Vim.

If you need to do anything special to make your virtualenv work and install Black (for
example you want to run a version from main), create a virtualenv manually and point
g:black_virtualenv to it. The plugin will use it.

If you would prefer to use the system installation of Black rather than a virtualenv,
then add this to your vimrc:

vim
let g:black_use_virtualenv = 0

Note that the :BlackUpgrade command is only usable and useful with a virtualenv, so
when the virtualenv is not in use, :BlackUpgrade is disabled. If you need to upgrade
the system installation of Black, then use your system package manager or pip--
whatever tool you used to install Black originally.

To run Black on save, add the following lines to .vimrc or init.vim:

vim
augroup black_on_save
  autocmd!
  autocmd BufWritePre *.py Black
augroup end

To run Black on a key press (e.g. F9 below), add this:

vim
nnoremap <F9> :Black<CR>

With ALE

  1. Install ale

  2. Install black

  3. Add this to your vimrc:

    vim
    let g:ale_fixers = {}
    let g:ale_fixers.python = ['black']

Vim indentation plugin

For insert-mode indentation that follows the same hanging-bracket style as Black, you
can also use the
vim-python-pep8-indent plugin. It
provides Vim's indentexpr; Black remains responsible for formatting the file. For
example, with vim-plug:

vim
Plug 'Vimjas/vim-python-pep8-indent'

With Vundle, use:

vim
Plugin 'Vimjas/vim-python-pep8-indent'

Neovim

Via conform.nvim

conform.nvim is a lightweight formatter
plugin for Neovim. It supports Black out of the box as long as black is available in
your PATH.

  1. Install black (e.g. pip install black or pipx install black)

  2. Install conform.nvim using your plugin manager and add the following to your Neovim
    configuration:

    lua
    require("conform").setup({
      formatters_by_ft = {
        python = { "black" },
      },
    })
  3. To format on save, add:

    lua
    require("conform").setup({
      formatters_by_ft = {
        python = { "black" },
      },
      format_on_save = {
        timeout_ms = 500,
        lsp_format = "fallback",
      },
    })

With ALE

ALE supports both Vim and Neovim. See the
Vim section above for setup instructions β€” the same configuration works for
Neovim.

Simple command

You can invoke Black on the current file directly from Neovim without any plugins:

vim
:!black %

To create a convenient :Black command, add this to your init.lua:

lua
vim.api.nvim_create_user_command(
  "Black",
  function()
    vim.cmd("!black " .. vim.fn.expand("%"))
  end,
  { nargs = 0 }
)

Gedit

gedit is the default text editor of the GNOME, Unix like Operating Systems. Open gedit
as

console
$ gedit <file_name>
  1. Go to edit > preferences > plugins
  2. Search for external tools and activate it.
  3. In Tools menu -> Manage external tools
  4. Add a new tool using + button.
  5. Copy the below content to the code window.
sh
#!/bin/bash
Name=$GEDIT_CURRENT_DOCUMENT_NAME
black $Name
  • Set a keyboard shortcut if you like, Ex. ctrl-B
  • Save: Nothing
  • Input: Nothing
  • Output: Display in bottom pane if you like.
  • Change the name of the tool if you like.

Use your keyboard shortcut or Tools -> External Tools to use your new tool. When you
close and reopen your File, Black will be done with its job.

Visual Studio Code

SublimeText

Use LSP with the
python-lsp-black plugin as documented
below. This is the recommended approach for all versions of Sublime Text.

{note}
The [sublack plugin](https://github.com/jgirardet/sublack) that was previously
recommended here is no longer maintained (the repository has been archived).

Python LSP Server

If your editor supports the Language Server Protocol (Atom,
Sublime Text, Visual Studio Code and many more), you can use the
Python LSP Server with the
python-lsp-black plugin.

Gradle (the build tool)

Use the Spotless plugin.

Kakoune

Add the following hook to your kakrc, then run Black with :format.

text
hook global WinSetOption filetype=python %{
    set-option window formatcmd 'black -q  -'
}

Thonny

Use Thonny-black-formatter.