chore: import upstream snapshot with attribution
test release tool / test-release-tool (macOS-latest, 3.12) (push) Waiting to run
test release tool / test-release-tool (macOS-latest, 3.13) (push) Waiting to run
test release tool / test-release-tool (macOS-latest, 3.14) (push) Waiting to run
test release tool / test-release-tool (macOS-latest, 3.15) (push) Waiting to run
docker / build (linux/arm64) (push) Waiting to run
docker / push (push) Blocked by required conditions
docs / docs (windows-latest) (push) Waiting to run
test release tool / test-release-tool (windows-latest, 3.12) (push) Waiting to run
test release tool / test-release-tool (windows-latest, 3.13) (push) Waiting to run
test release tool / test-release-tool (windows-latest, 3.14) (push) Waiting to run
test release tool / test-release-tool (windows-latest, 3.15) (push) Waiting to run
test / test (macOS-latest, 3.10) (push) Waiting to run
test / test (macOS-latest, 3.11) (push) Waiting to run
test / test (macOS-latest, 3.12.10) (push) Waiting to run
test / test (macOS-latest, 3.13) (push) Waiting to run
test / test (macOS-latest, 3.14) (push) Waiting to run
test / test (macOS-latest, 3.15) (push) Waiting to run
test / test (macOS-latest, pypy3.11-v7.3.22) (push) Waiting to run
test / test (windows-11-arm, 3.11) (push) Waiting to run
test / test (windows-11-arm, 3.12.10) (push) Waiting to run
test / test (windows-11-arm, 3.13) (push) Waiting to run
test / test (windows-11-arm, 3.14) (push) Waiting to run
test / test (windows-11-arm, 3.15) (push) Waiting to run
test / test (windows-latest, 3.10) (push) Waiting to run
test / test (windows-latest, 3.11) (push) Waiting to run
test / test (windows-latest, 3.12.10) (push) Waiting to run
test / test (windows-latest, 3.13) (push) Waiting to run
test / test (windows-latest, 3.14) (push) Waiting to run
test / test (windows-latest, 3.15) (push) Waiting to run
test / test (windows-latest, pypy3.11-v7.3.22) (push) Waiting to run
test / coveralls-finish (push) Blocked by required conditions
test / uvloop (macOS-latest) (push) Waiting to run
test / uvloop (windows-11-arm) (push) Waiting to run
test / uvloop (windows-latest) (push) Waiting to run
fuzz / fuzz (3.11) (push) Failing after 1s
fuzz / fuzz (3.12) (push) Failing after 1s
build and publish / sdist + pure wheel (push) Failing after 0s
diff-shades / analysis / base / ${{ matrix.mode }} (push) Has been skipped
diff-shades / compare / ${{ matrix.mode }} (push) Waiting to run
docs / docs (ubuntu-latest) (push) Failing after 2s
fuzz / fuzz (3.10) (push) Failing after 1s
fuzz / fuzz (3.14) (push) Failing after 0s
lint and format / lint (push) Failing after 1s
build and publish / publish-mypyc (push) Waiting to run
diff-shades / configure (push) Failing after 1s
docker / build (linux/amd64) (push) Has been skipped
diff-shades / analysis / target / ${{ matrix.mode }} (push) Has been skipped
fuzz / fuzz (3.13) (push) Failing after 0s
fuzz / create-issue (push) Waiting to run
build and publish / generate wheels matrix (push) Failing after 0s
test release tool / test-release-tool (ubuntu-latest, 3.13) (push) Failing after 1s
build and publish / mypyc wheels ${{ matrix.only }} (push) Has been skipped
build and publish / publish-hatch (push) Waiting to run
test / test (ubuntu-latest, 3.10) (push) Failing after 0s
test / test (ubuntu-latest, 3.11) (push) Failing after 1s
test / test (ubuntu-latest, 3.13) (push) Failing after 0s
test / test (ubuntu-latest, pypy3.11-v7.3.22) (push) Failing after 1s
test / test (ubuntu-latest, 3.15) (push) Failing after 1s
test release tool / test-release-tool (ubuntu-latest, 3.15) (push) Failing after 0s
zizmor / zizmor (push) Failing after 0s
test release tool / test-release-tool (ubuntu-latest, 3.12) (push) Failing after 4s
test release tool / test-release-tool (ubuntu-latest, 3.14) (push) Failing after 3s
test / uvloop (ubuntu-latest) (push) Failing after 1s
test / test (ubuntu-latest, 3.14) (push) Failing after 1s
test / test (ubuntu-latest, 3.12.10) (push) Failing after 5s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:07:39 +08:00
commit d0aab9212a
460 changed files with 145411 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
[flake8]
ignore = E203, E266, E501, E701, E704, W503, B907
# line length is intentionally set to 80 here because black uses Bugbear
# See https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html#bugbear for more details
max-line-length = 80
max-complexity = 18
select = B,E,F,W,T4,B9
+3
View File
@@ -0,0 +1,3 @@
node: $Format:%H$
node-date: $Format:%cI$
describe-name: $Format:%(describe:tags=true,match=[0-9]*)$
+2
View File
@@ -0,0 +1,2 @@
.git_archival.txt export-subst
*.py diff=python
+11
View File
@@ -0,0 +1,11 @@
# Treat each other well
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](https://www.python.org/psf/codeofconduct/).
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.
+64
View File
@@ -0,0 +1,64 @@
---
name: Bug report
about: Create a report to help us improve Black's quality
title: ""
labels: "T: bug"
assignees: ""
---
<!--
Please make sure that the bug is not already fixed either in newer versions or the
current development version. To confirm this, you have three options:
1. Update Black's version if a newer release exists: `pip install -U black`
2. Install the latest `main` branch directly:
`pip install "black @ git+https://github.com/psf/black.git"`
3. Or run _Black_ from source on your machine:
- create a new virtualenv (make sure it's the same Python version);
- clone this repository;
- run `pip install -e .[d]`;
- run `pip install --group tests`
- make sure it's sane by running `python -m pytest -n auto`; and
- run `black` like you did last time.
-->
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
<!--
Minimal steps to reproduce the behavior with source code and Black's configuration.
-->
For example, take this code:
```python
this = "code"
```
And run it with these arguments:
```sh
$ black file.py --target-version py310
```
The resulting error is:
> cannot format file.py: INTERNAL ERROR: ...
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Environment**
<!-- Please complete the following information: -->
- Black's version: <!-- e.g. [main] -->
- OS and Python version: <!-- e.g. [Linux/Python 3.7.4rc1] -->
**Additional context**
<!-- Add any other context about the problem here. -->
+11
View File
@@ -0,0 +1,11 @@
# See also: https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
# This is the default and blank issues are useful so let's keep 'em.
blank_issues_enabled: true
contact_links:
- name: Chat on Python Discord
url: https://discord.gg/RtVdv86PrH
about: >-
User support, questions, and other lightweight requests can be handled via the
#black-formatter text channel we have on Python Discord.
+27
View File
@@ -0,0 +1,27 @@
---
name: Documentation
about: Report a problem with or suggest something for the documentation
title: ""
labels: "T: documentation"
assignees: ""
---
**Is this related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is.
e.g. I'm always frustrated when [...] / I wished that [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to
happen or see changed. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any
alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the issue
here. -->
+27
View File
@@ -0,0 +1,27 @@
---
name: Feature request
about: Suggest an idea for this project
title: ""
labels: "T: enhancement"
assignees: ""
---
**Is your feature request related to a problem? Please describe.**
<!-- A clear and concise description of what the problem is.
e.g. I'm always frustrated when [...] -->
**Describe the solution you'd like**
<!-- A clear and concise description of what you want to
happen. -->
**Describe alternatives you've considered**
<!-- A clear and concise description of any
alternative solutions or features you've considered. -->
**Additional context**
<!-- Add any other context or screenshots about the feature request
here. -->
+38
View File
@@ -0,0 +1,38 @@
---
name: Code style issue
about: Help us improve the Black code style
title: ""
labels: "T: style"
assignees: ""
---
**Describe the style change**
<!-- A clear and concise description of how the style can be
improved. -->
**Examples in the current _Black_ style**
<!-- Think of some short code snippets that show
how the current _Black_ style is not great: -->
```python
def f():
"""This code should be formatted as per the current Black style"""
pass
```
**Desired style**
<!-- How do you think _Black_ should format the above snippets: -->
```python
def f(
):
"""This code can be formatted however you suggest!"""
pass
```
**Additional context**
<!-- Add any other context about the problem here. -->
+42
View File
@@ -0,0 +1,42 @@
<!-- Hello! Thanks for submitting a PR. To help make things go a bit smoother
we would appreciate that you go through this template. -->
### Description
<!-- Good things to put here include: reasoning for the change (please link
any relevant issues!), any noteworthy (or hacky) choices to be aware of,
or what the problem resolved here looked like ... we won't mind a ranty
story :) -->
### Checklist - did you ...
<!-- If any of the following items aren't relevant for your contribution,
please still tick them so we know you've gone through the checklist.
- Please familiarize yourself with Black's stability policy, linked
below. Code style changes are only allowed under the `--preview` flag
until maintainers move them to stable in the next calendar year.
- All user-facing changes should get a changelog entry. If this isn't
user-facing, signal to us that this should get the magical label to
silence the check.
- Tests are required for all bugfixes and new features.
- Documentation changes are necessary for most formatting changes and
other enhancements. -->
- [ ] Implement any code style changes under the `--preview` style, following the stability policy?
- [ ] Add an entry in `CHANGES.md` if necessary?
- [ ] Add / update tests if necessary?
- [ ] Add new / update outdated documentation?
<!-- Just as a reminder, everyone in all psf/black spaces, including PRs, must
follow the PSF Code of Conduct (link below).
Finally, thanks once again for your time and effort. If you have any
feedback regarding your experience contributing here, please let us know!
Helpful links:
- PSF COC: https://www.python.org/psf/conduct/
- Contributing docs: https://black.readthedocs.io/en/latest/contributing/index.html
- Chat on Python Discord: https://discord.gg/RtVdv86PrH
- Stability policy: https://black.readthedocs.io/en/stable/the_black_code_style/index.html -->
+21
View File
@@ -0,0 +1,21 @@
# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
# Workflow files in .github/workflows will be checked
directory: "/"
labels: ["ci: skip news", "C: dependencies", "C: maintenance"]
schedule:
interval: daily
cooldown:
default-days: 7
- package-ecosystem: "pip"
directory: "/"
labels: ["ci: skip news", "C: dependencies"]
schedule:
interval: daily
cooldown:
default-days: 7
+25
View File
@@ -0,0 +1,25 @@
name: changelog
on:
pull_request:
types: [opened, synchronize, labeled, unlabeled, reopened]
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Grep CHANGES.md for PR number
if: >
contains(github.event.pull_request.labels.*.name, 'ci: skip news') != true
run: |
grep -Pz "\((\n\s*)?#${{ github.event.pull_request.number }}(\n\s*)?\)" CHANGES.md || \
(echo "Please add '(#${{ github.event.pull_request.number }})' change line to CHANGES.md (or if appropriate, ask a maintainer to add the 'ci: skip news' label)" && \
exit 1)
+240
View File
@@ -0,0 +1,240 @@
name: diff-shades
on:
push:
branches: [main]
paths:
- src/**
- pyproject.toml
- scripts/diff_shades_gha_helper.py
- .github/workflows/diff_shades.yml
- .github/workflows/diff_shades_comment.yml
pull_request:
paths:
- src/**
- pyproject.toml
- scripts/diff_shades_gha_helper.py
- .github/workflows/diff_shades.yml
- .github/workflows/diff_shades_comment.yml
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
env:
HATCH_BUILD_HOOKS_ENABLE: "1"
# Clang is less picky with the C code it's given than gcc (and may generate faster
# binaries too).
CC: clang-18
permissions: {}
jobs:
configure:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-config.outputs.matrix }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades --group diff-shades-comment
- name: Calculate run configuration & metadata
id: set-config
env:
GITHUB_TOKEN: ${{ github.token }}
run: python scripts/diff_shades_gha_helper.py config
analysis-base:
name: analysis / base / ${{ matrix.mode }}
needs: configure
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.configure.outputs.matrix) }}
steps:
- name: Checkout this repository (full clone)
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# The baseline revision could be rather old so a full clone is ideal.
fetch-depth: 0
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades
- name: Configure git
run: |
git config user.name "diff-shades-gha"
git config user.email "diff-shades-gha@example.com"
- name: Attempt to use cached baseline analysis
id: baseline-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ matrix.baseline-analysis }}
key: ${{ matrix.baseline-cache-key }}
- name: Build and install baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
${{ matrix.baseline-setup-cmd }}
python -m pip install .
- name: Analyze baseline revision
if: steps.baseline-cache.outputs.cache-hit != 'true'
run:
diff-shades analyze ${{ matrix.baseline-analysis }} --work-dir projects-cache/
--force-${{ matrix.style }}-style -v
- name: Upload baseline analysis
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.baseline-analysis }}
path: ${{ matrix.baseline-analysis }}
analysis-target:
name: analysis / target / ${{ matrix.mode }}
needs: configure
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.configure.outputs.matrix) }}
steps:
- name: Checkout this repository (full clone)
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# The baseline revision could be rather old so a full clone is ideal.
fetch-depth: 0
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades
- name: Configure git
run: |
git config user.name "diff-shades-gha"
git config user.email "diff-shades-gha@example.com"
- name: Build and install target revision
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
${{ matrix.target-setup-cmd }}
python -m pip install .
# Pull it from previous runs - we're NOT trying to get it from this run
# (but it wouldn't cause problems if we theoretically did)
- name: Attempt to find baseline analysis
id: baseline-cache
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ matrix.baseline-analysis }}
key: ${{ matrix.baseline-cache-key }}
- name: Analyze target revision (with repeated projects)
if: steps.baseline-cache.outputs.cache-hit == 'true'
run: |
diff-shades analyze ${{ matrix.target-analysis }} --work-dir projects-cache/ \
--force-${{ matrix.style }}-style -v \
--repeat-projects-from ${{ matrix.baseline-analysis }}
- name: Analyze target revision (without repeated projects)
if: steps.baseline-cache.outputs.cache-hit != 'true'
run:
diff-shades analyze ${{ matrix.target-analysis }} --work-dir projects-cache/
--force-${{ matrix.style }}-style -v
- name: Upload target analysis
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.target-analysis }}
path: ${{ matrix.target-analysis }}
- name: Check for failed files for target revision
run: diff-shades show-failed --check --show-log ${{ matrix.target-analysis }}
compare:
name: compare / ${{ matrix.mode }}
needs: ["configure", "analysis-base", "analysis-target"]
if: ${{ !cancelled() }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.configure.outputs.matrix) }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
merge-multiple: true
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades --group diff-shades-comment
- name: Generate HTML diff report
run: |
diff-shades --dump-html diff.html \
compare --diff ${{ matrix.baseline-analysis }} ${{ matrix.target-analysis }}
- name: Upload diff report
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.style }}-diff.html
path: diff.html
- name: Generate summary file (PR only)
if: github.event_name == 'pull_request'
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
python scripts/diff_shades_gha_helper.py comment-body \
${{ matrix.baseline-analysis }} ${{ matrix.target-analysis }} \
${{ matrix.style }} ${{ matrix.mode }}
- name: Upload summary file (PR only)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: .${{ matrix.style }}.pr-comment.md
path: .${{ matrix.style }}.pr-comment.md
include-hidden-files: true
- name: Verify zero changes (PR only)
if: matrix.mode == 'assert-no-changes'
run: |
diff-shades compare --check \
${{ matrix.baseline-analysis }} ${{ matrix.target-analysis }} || \
(echo "Please verify you didn't change the stable code style unintentionally!" \
&& exit 1)
+123
View File
@@ -0,0 +1,123 @@
name: diff-shades comment
on:
workflow_run:
workflows: [diff-shades]
types: [completed]
permissions: {}
jobs:
comment:
runs-on: ubuntu-latest
# We want to comment even if there were failed files or the stable style changed
# That would cause the main workflow to "fail"
if:
github.event.workflow_run.event == 'pull_request' &&
contains(fromJSON('["success", "failure"]'), github.event.workflow_run.conclusion)
permissions:
pull-requests: write # Needed to comment on PR
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
id: artifacts
with:
merge-multiple: true
pattern: ".*.pr-comment.md"
path: ${{ runner.temp }}/diff-shades-artifacts
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
- name: Validate downloaded comment artifacts
id: comment-artifacts
shell: bash
run: |
set -euo pipefail
artifact_dir="${RUNNER_TEMP}/diff-shades-artifacts"
preview_artifact="${artifact_dir}/.preview.pr-comment.md"
stable_artifact="${artifact_dir}/.stable.pr-comment.md"
if [ ! -d "$artifact_dir" ]; then
echo "::error::Artifact directory does not exist: ${artifact_dir}"
exit 1
fi
while IFS= read -r -d '' entry; do
if [ "$(dirname "$entry")" != "$artifact_dir" ]; then
echo "::error::Unexpected nested artifact path: ${entry}"
exit 1
fi
case "$(basename "$entry")" in
.preview.pr-comment.md|.stable.pr-comment.md) ;;
*)
echo "::error::Unexpected artifact path: ${entry}"
exit 1
;;
esac
if [ ! -f "$entry" ] || [ -L "$entry" ]; then
echo "::error::Artifact must be a regular file: ${entry}"
exit 1
fi
done < <(find "$artifact_dir" -mindepth 1 -print0)
for artifact in "$preview_artifact" "$stable_artifact"; do
if [ ! -f "$artifact" ] || [ -L "$artifact" ]; then
echo "::error::Missing expected artifact file: ${artifact}"
exit 1
fi
done
{
echo "preview=${preview_artifact}"
echo "stable=${stable_artifact}"
} >> "$GITHUB_OUTPUT"
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group diff-shades-comment
- name: Get PR number
id: pr
run:
echo pr=$(gh pr list --search $sha --json number --jq ".[0].number") >>
"$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ github.token }}
sha: ${{ github.event.workflow_run.head_sha }}
- name: Get details from initial workflow run
id: metadata
run: |
python scripts/diff_shades_gha_helper.py comment-details \
"$pr" "$run_id" "$preview_artifact" "$stable_artifact"
env:
GITHUB_TOKEN: ${{ github.token }}
pr: ${{ steps.pr.outputs.pr }}
run_id: ${{ github.event.workflow_run.id }}
preview_artifact: ${{ steps.comment-artifacts.outputs.preview }}
stable_artifact: ${{ steps.comment-artifacts.outputs.stable }}
- name: Try to find pre-existing PR comment
id: find-comment
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
with:
issue-number: ${{ steps.pr.outputs.pr }}
comment-author: "github-actions[bot]"
body-includes: "diff-shades"
- name: Create or update PR comment
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ steps.pr.outputs.pr }}
body: ${{ steps.metadata.outputs.comment-body }}
edit-mode: replace
+123
View File
@@ -0,0 +1,123 @@
name: docker
on:
push:
branches:
- "main"
release:
types: [published]
permissions:
contents: read
env:
REGISTRY: pyfound/black
jobs:
build:
if: github.repository == 'psf/black'
runs-on: ${{ matrix.runner }}
name: build (${{ matrix.platform }})
strategy:
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Login to DockerHub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Prepare
id: prepare
run: echo "platform=${platform//\//-}" >> $GITHUB_OUTPUT
env:
platform: ${{ matrix.platform }}
- name: Build and push
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
platforms: ${{ matrix.platform }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
tags: ${{ env.REGISTRY }}
cache-from: type=gha,scope=${{ steps.prepare.outputs.platform }}
cache-to: type=gha,scope=${{ steps.prepare.outputs.platform }},mode=max
- name: Export digest
run: |
mkdir -p digests
touch "digests/${digest#sha256:}"
env:
digest: ${{ steps.build.outputs.digest }}
- name: Upload digest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-${{ steps.prepare.outputs.platform }}
path: digests/*
if-no-files-found: error
push:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: digests
pattern: digests-*
merge-multiple: true
- name: Login to DockerHub
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Create manifest list and push
run: |
TAGS="-t $REGISTRY:latest"
if [[ "$EVENT_NAME" == "release" ]]; then
TAGS="$TAGS -t $REGISTRY:$(git describe --candidates=0 --tags)"
if [[ "$PRERELEASE" == "true" ]]; then
TAGS="$TAGS -t $REGISTRY:latest_prerelease"
else
TAGS="$TAGS -t $REGISTRY:latest_release"
fi
else
TAGS="$TAGS -t $REGISTRY:latest_non_release"
fi
cd digests
docker buildx imagetools create $TAGS $(printf "$REGISTRY@sha256:%s " *)
env:
EVENT_NAME: ${{ github.event_name }}
PRERELEASE: ${{ github.event.release.prerelease }}
- name: Inspect image
run: docker buildx imagetools inspect $REGISTRY:latest
+41
View File
@@ -0,0 +1,41 @@
name: docs
on:
push:
paths: ["docs/**", "src/**", "pyproject.toml", ".github/workflows/docs.yml"]
pull_request:
paths: ["docs/**", "src/**", "pyproject.toml", ".github/workflows/docs.yml"]
permissions:
contents: read
jobs:
docs:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: -e .[d] --group docs
- name: Build documentation
run: sphinx-build -a -b html -W --keep-going docs/ docs/_build
+109
View File
@@ -0,0 +1,109 @@
name: fuzz
on:
push:
branches: main
pull_request:
paths:
- .github/workflows/fuzz.yml
- scripts/fuzz.py
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
jobs:
fuzz:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# TODO: add 3.15; relies on libcst which doesn't support 3.15 yet
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
pip-version: "25.3"
pip-install: --group tox
- name: Run fuzz tests
id: fuzz
run: tox -e fuzz --result-json $python_ver
env:
python_ver: ${{ matrix.python-version }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && steps.fuzz.outcome == 'failure'
with:
name: ${{ matrix.python-version }}
path: ${{ matrix.python-version }}
create-issue:
runs-on: ubuntu-latest
needs: fuzz
if:
github.repository == 'psf/black' && github.event_name != 'pull_request' &&
failure()
permissions:
issues: write # Needed to create issue
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
merge-multiple: true
path: ./output
- name: Generate issue data
run: |
output=issue-body.html
touch $output
for FILE in ./output/*; do
echo "**Python $(basename $FILE)**" >> $output
echo -e "\`\`\`py" >> $output
echo -e "# stdout:" >> $output
echo -e "$(jq .testenvs.fuzz.test[-1].output $FILE -r)\n" >> $output
echo -e "# stderr:" >> $output
echo -e "$(jq .testenvs.fuzz.test[-1].err $FILE -r)" >> $output
echo -e "\`\`\`\n" >> $output
done
- name: Get existing issue
id: issue
run: |
echo "ISSUE=$( gh issue list \
-A github-actions[bot] -l 'ci: fuzz error' \
--json number -q .[0].number \
-R $REPO )" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
- name: Create new issue
if: steps.issue.outputs.ISSUE == ''
run: >
gh issue create -t "Fuzz test failure" -F issue-body.html -l "ci: fuzz error"
-R $REPO
env:
GITHUB_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
- name: Edit existing issue
if: steps.issue.outputs.ISSUE != ''
run: gh issue edit $ISSUE -F issue-body.html -R $REPO
env:
GITHUB_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
ISSUE: ${{ steps.issue.outputs.ISSUE }}
+46
View File
@@ -0,0 +1,46 @@
name: lint and format
on: [push, pull_request]
permissions: {}
jobs:
lint:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Assert PR target is main
if: github.event_name == 'pull_request' && github.repository == 'psf/black'
run: |
if [ "$GITHUB_BASE_REF" != "main" ]; then
echo "::error::PR targeting '$GITHUB_BASE_REF', please refile targeting 'main'." && exit 1
fi
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: -e . --group tox
- name: Run pre-commit hooks
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
- name: Format ourselves
run: tox -e run_self
- name: Regenerate schema
run: |
tox -e generate_schema
git diff --exit-code
+66
View File
@@ -0,0 +1,66 @@
name: post release
on:
release:
types: published
permissions: {}
jobs:
update-stable:
runs-on: ubuntu-latest
if: github.event.release.prerelease != 'true'
permissions:
contents: write # Needed to push to stable
steps:
- name: Checkout stable branch
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: stable
fetch-depth: 0
persist-credentials: true # needed for `git push` below
- name: Update stable branch to release tag & push
run: |
git reset --hard "${TAG_NAME}"
git push
env:
TAG_NAME: ${{ github.event.release.tag_name }}
new-changelog:
runs-on: ubuntu-latest
if: github.event.release.prerelease != 'true'
permissions:
contents: write # Needed to push to new branch
pull-requests: write # Needed to create PR
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: main
fetch-tags: true
persist-credentials: true # Needed for git-auto-commit-action
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
- run: python scripts/release.py -a
- uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0
with:
commit_message: Add new changelog
branch: ci/new-changelog
create_branch: true
- name: Create PR
run: |
gh pr create \
-t "Add new changelog" -b "" \
-l "ci: skip news" -l "C: maintenance" \
-a $USER
env:
GITHUB_TOKEN: ${{ github.token }}
USER: ${{ github.event.release.author.login }}
+77
View File
@@ -0,0 +1,77 @@
name: publish binaries
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
required: true
type: string
permissions: {}
jobs:
publish:
name: publish (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
pathsep: ";"
asset_name: black_windows.exe
executable_mime: "application/vnd.microsoft.portable-executable"
strip: false
- os: windows-11-arm
pathsep: ";"
asset_name: black_windows-arm.exe
executable_mime: "application/vnd.microsoft.portable-executable"
strip: false
- os: ubuntu-latest
pathsep: ":"
asset_name: black_linux
executable_mime: "application/x-executable"
strip: true
- os: ubuntu-24.04-arm
pathsep: ":"
asset_name: black_linux-arm
executable_mime: "application/x-executable"
strip: true
- os: macos-latest
pathsep: ":"
asset_name: black_macos
executable_mime: "application/x-mach-binary"
strip: false
permissions:
contents: write # Needed to upload to release
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: .[colorama] --group pyinstaller
- name: Build executable with PyInstaller
run:
python -m PyInstaller -F ${{ matrix.strip && '--strip' || '' }} --name ${{
matrix.asset_name }} --add-data 'src/blib2to3${{ matrix.pathsep }}blib2to3'
src/black/__main__.py
- name: Quickly test executable
run: |
./dist/${{ matrix.asset_name }} --version
./dist/${{ matrix.asset_name }} src --verbose
- run: gh release upload "$tag" dist/${{ matrix.asset_name }}
shell: bash
env:
GH_TOKEN: ${{ github.token }}
tag: ${{ inputs.tag || github.event.release.tag_name }}
+160
View File
@@ -0,0 +1,160 @@
name: build and publish
on:
release:
types: published
pull_request:
push:
branches: main
permissions: {}
env:
PROJECT: https://pypi.org/p/black
jobs:
configure:
name: generate wheels matrix
runs-on: ubuntu-latest
outputs:
include: ${{ steps.set-matrix.outputs.include }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group cibw
- name: generate matrix
if: |
github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'ci: build all wheels')
run: |
{
cibuildwheel --print-build-identifiers --platform linux \
| pyp 'json.dumps({"only": x, "os": "ubuntu-latest"})' \
&& cibuildwheel --print-build-identifiers --platform macos \
| pyp 'json.dumps({"only": x, "os": "macos-latest"})' \
&& cibuildwheel --print-build-identifiers --platform windows \
| pyp 'json.dumps({"only": x, "os": "windows-latest"})' \
&& cibuildwheel --print-build-identifiers --platform windows --archs ARM64 \
| pyp 'json.dumps({"only": x, "os": "windows-11-arm"})'
} | pyp 'json.dumps(list(map(json.loads, lines)))' > /tmp/matrix
env:
CIBW_ARCHS_LINUX: x86_64
CIBW_ARCHS_MACOS: x86_64 arm64
CIBW_ARCHS_WINDOWS: AMD64
- name: generate matrix (PR)
if: |
github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'ci: build all wheels')
run: |
{
CIBW_BUILD="cp310-*" cibuildwheel --print-build-identifiers --platform linux | pyp 'json.dumps({"only": x, "os": "ubuntu-latest"})'
CIBW_BUILD="cp314-*" cibuildwheel --print-build-identifiers --platform windows | pyp 'json.dumps({"only": x, "os": "windows-latest"})'
} | pyp 'json.dumps(list(map(json.loads, lines)))' > /tmp/matrix
env:
CIBW_ARCHS_LINUX: x86_64
- id: set-matrix
run: echo "include=$(cat /tmp/matrix)" | tee -a $GITHUB_OUTPUT
mypyc:
name: mypyc wheels ${{ matrix.only }}
needs: configure
runs-on: ${{ matrix.os }}
strategy:
matrix:
include: ${{ fromJson(needs.configure.outputs.include) }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group cibw
- name: Run cibuildwheel
run: cibuildwheel . --only ${{ matrix.only }}
- name: Upload wheels as workflow artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.only }}-mypyc-wheels
path: wheelhouse/
hatch:
name: sdist + pure wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: --group hatch
- name: Build wheel and source distributions
run: python -m hatch build
- name: Store the distribution packages
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sdist-and-pure-wheel
path: dist/
publish-mypyc:
if: github.event_name == 'release'
needs: mypyc
runs-on: ubuntu-latest
environment:
name: release
url: ${{ env.PROJECT }}
permissions:
id-token: write # Required for PyPI trusted publishing
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-mypyc-wheels"
path: wheelhouse/
merge-multiple: true
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
packages-dir: wheelhouse/
verbose: true
publish-hatch:
if: github.event_name == 'release'
needs: hatch
runs-on: ubuntu-latest
environment:
name: release
url: ${{ env.PROJECT }}
permissions:
id-token: write # Required for PyPI trusted publishing
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: sdist-and-pure-wheel
path: dist/
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
with:
verbose: true
+59
View File
@@ -0,0 +1,59 @@
name: test release tool
on:
push:
paths:
- .github/workflows/release_tests.yml
- scripts/release.py
- scripts/release_tests.py
pull_request:
paths:
- .github/workflows/release_tests.yml
- scripts/release.py
- scripts/release_tests.py
permissions: {}
jobs:
test-release-tool:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.12", "3.13", "3.14", "3.15"]
os: [macOS-latest, ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# Give us all history, branches and tags
fetch-depth: 0
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
pip-version: "25.3"
pip-install: --group coverage
- name: Print Python Version
run: python --version --version && which python
- name: Print Pip Version
run: pip --version && which pip
- name: Print Git Version
run: git --version && which git
- name: Run unit tests via coverage + print report
run: |
coverage run scripts/release_tests.py
coverage report --show-missing
+124
View File
@@ -0,0 +1,124 @@
name: test
on:
push:
paths:
- .github/workflows/test.yml
- src/**
- tests/**
- tox.ini
- pyproject.toml
pull_request:
paths:
- .github/workflows/test.yml
- src/**
- tests/**
- tox.ini
- pyproject.toml
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
test:
# We want to run on external PRs, but not on our own internal PRs as they'll be run
# by the push to the branch. Without this if check, checks are duplicated since
# internal PRs match both the push and pull_request events.
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version:
["3.10", "3.11", "3.12.10", "3.13", "3.14", "3.15", "pypy3.11-v7.3.22"]
os: [ubuntu-latest, macOS-latest, windows-latest, windows-11-arm]
exclude:
# setup-python only supports CPython 3.11+ on arm64 windows
- os: windows-11-arm
python-version: "3.10"
- os: windows-11-arm
python-version: "pypy3.11-v7.3.22"
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
pip-version: "25.3"
pip-install: --group tox
- name: Unit tests
if: "!startsWith(matrix.python-version, 'pypy')"
run:
tox -e ci-py$(echo ${{ matrix.python-version }} | tr -d '.') -- -v --color=yes
- name: Unit tests (pypy)
if: "startsWith(matrix.python-version, 'pypy')"
run: tox -e ci-pypy3 -- -v --color=yes
- name: Upload coverage to Coveralls
# Upload coverage if we are on the main repository and
# we're running on Linux (this action only supports Linux)
if:
github.repository == 'psf/black' && matrix.os == 'ubuntu-latest' &&
!startsWith(matrix.python-version, 'pypy')
uses: AndreMiras/coveralls-python-action@ac868b9540fad490f7ca82b8ca00480fd751ed19
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel: true
flag-name: py${{ matrix.python-version }}-${{ matrix.os }}
debug: true
coveralls-finish:
needs: test
if: github.repository == 'psf/black'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Send finished signal to Coveralls
uses: AndreMiras/coveralls-python-action@ac868b9540fad490f7ca82b8ca00480fd751ed19
with:
parallel-finished: true
debug: true
uvloop:
if:
github.event_name == 'push' || github.event.pull_request.head.repo.full_name !=
github.repository
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest, windows-11-arm]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
with:
python-version: "3.14"
pip-version: "25.3"
pip-install: -e .[uvloop]
- name: Format ourselves
run: python -m black --check .
+25
View File
@@ -0,0 +1,25 @@
name: zizmor
on:
push:
branches: ["main"]
paths: ["**.yml"]
pull_request:
paths: ["**.yml"]
permissions: {}
jobs:
zizmor:
name: zizmor
runs-on: ubuntu-latest
permissions:
security-events: write # Required for upload-sarif (used by zizmor-action) to upload SARIF files.
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Run zizmor
uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7
+8
View File
@@ -0,0 +1,8 @@
rules:
dangerous-triggers:
ignore:
# The diff-shades comment workflow intentionally runs after the unprivileged
# diff-shades workflow so it can publish the generated PR comment. It must
# treat artifacts as untrusted and only read validated files from an isolated
# artifact directory.
- diff_shades_comment.yml
+29
View File
@@ -0,0 +1,29 @@
.venv
.coverage
.coverage.*
_build
.DS_Store
.vscode
.python-version
docs/_static/pypi.svg
.tox
__pycache__
# Packaging artifacts
black.egg-info
black.dist-info
build/
dist/
pip-wheel-metadata/
.eggs
src/_black_version.py
.idea
.dmypy.json
*.swp
.hypothesis/
venv/
.ipynb_checkpoints/
node_modules/
*.pyd
+85
View File
@@ -0,0 +1,85 @@
# Note: don't use this config for your own repositories. Instead, see
# "Version control integration" in docs/integrations/source_version_control.md
exclude: ^(profiling/|tests/data/)
repos:
- repo: local
hooks:
- id: check-pre-commit-rev-in-example
name: Check pre-commit rev in example
language: python
entry: python -m scripts.check_pre_commit_rev_in_example
files: '(CHANGES|source_version_control|using_black_with_jupyter_notebooks)\.md$'
additional_dependencies:
- beautifulsoup4>=4.14.2
- commonmark>=0.9.1
- pyyaml>=6.0.1
- id: check-version-in-the-basics-example
name: Check black version in the basics example
language: python
entry: python -m scripts.check_version_in_basics_example
files: '(CHANGES|the_basics)\.md$'
additional_dependencies:
- beautifulsoup4>=4.14.2
- commonmark>=0.9.1
- repo: https://github.com/pycqa/isort
rev: 8.0.1
hooks:
- id: isort
- repo: https://github.com/pycqa/flake8
rev: 7.3.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-comprehensions
- flake8-simplify
exclude: ^src/blib2to3/
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.20.2
hooks:
- id: mypy
exclude: ^docs/conf.py$
args: []
additional_dependencies:
- click>=8.0.0
- packaging>=22.0
- platformdirs>=2
- pytokens~=0.4.0
- tomli>=1.1.0
- uvloop>=0.15.2; sys_platform != 'win32'
- winloop>=0.5.0; sys_platform == 'win32'
# blackd
- aiohttp>=3.10
# tests
- pytest>=7
# fuzz
- hypothesis
- hypothesmith
- types-atheris
# diff-shades
- urllib3
# version check
- beautifulsoup4>=4.14.2
- types-commonmark>=0.9.0
- types-pyyaml>=6.0.0
- repo: https://github.com/rbubley/mirrors-prettier
rev: v3.8.3
hooks:
- id: prettier
types_or: [markdown, yaml, json]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
+20
View File
@@ -0,0 +1,20 @@
# Note that we recommend using https://github.com/psf/black-pre-commit-mirror instead
# This will work about 2x as fast as using the hooks in this repository
- id: black
name: black
description: "Black: The uncompromising Python code formatter"
entry: black
language: python
minimum_pre_commit_version: 2.9.2
require_serial: true
types_or: [python, pyi]
- id: black-jupyter
name: black-jupyter
description:
"Black: The uncompromising Python code formatter (with Jupyter Notebook support)"
entry: black
language: python
minimum_pre_commit_version: 2.9.2
require_serial: true
types_or: [python, pyi, jupyter]
additional_dependencies: [".[jupyter]"]
+9
View File
@@ -0,0 +1,9 @@
proseWrap: always
printWidth: 88
endOfLine: auto
overrides:
- files:
- ".github/ISSUE_TEMPLATE/*.md"
- ".github/PULL_REQUEST_TEMPLATE.md"
options:
proseWrap: never
+17
View File
@@ -0,0 +1,17 @@
version: 2
formats:
- htmlzip
build:
os: ubuntu-lts-latest
tools:
python: "3.13"
jobs:
install:
- pip install --upgrade pip
- pip install .[d]
- pip install --group docs
sphinx:
configuration: docs/conf.py
+198
View File
@@ -0,0 +1,198 @@
# Authors
Glued together by [Łukasz Langa](mailto:lukasz@langa.pl).
Maintained with:
- [Carol Willing](mailto:carolcode@willingconsulting.com)
- [Carl Meyer](mailto:carl@oddbird.net)
- [Jelle Zijlstra](mailto:jelle.zijlstra@gmail.com)
- [Mika Naylor](mailto:mail@autophagy.io)
- [Zsolt Dollenstein](mailto:zsol.zsol@gmail.com)
- [Cooper Lees](mailto:me@cooperlees.com)
- [Richard Si](mailto:sichard26@gmail.com)
- [Felix Hildén](mailto:felix.hilden@gmail.com)
- [Batuhan Taskaya](mailto:batuhan@python.org)
- [Shantanu Jain](mailto:hauntsaninja@gmail.com)
Multiple contributions by:
- [Abdur-Rahmaan Janhangeer](mailto:arj.python@gmail.com)
- [Adam Johnson](mailto:me@adamj.eu)
- [Adam Williamson](mailto:adamw@happyassassin.net)
- [Alexander Huynh](mailto:ahrex-gh-psf-black@e.sc)
- [Alexandr Artemyev](mailto:mogost@gmail.com)
- [Alex Vandiver](mailto:github@chmrr.net)
- [Allan Simon](mailto:allan.simon@supinfo.com)
- Anders-Petter Ljungquist
- [Amethyst Reese](mailto:amy@n7.gg)
- [Andrew Thorp](mailto:andrew.thorp.dev@gmail.com)
- [Andrew Zhou](mailto:andrewfzhou@gmail.com)
- [Andrey](mailto:dyuuus@yandex.ru)
- [Andy Freeland](mailto:andy@andyfreeland.net)
- [Anthony Sottile](mailto:asottile@umich.edu)
- [Antonio Ossa Guerra](mailto:aaossa+black@uc.cl)
- [Arjaan Buijk](mailto:arjaan.buijk@gmail.com)
- [Arnav Borbornah](mailto:arnavborborah11@gmail.com)
- [Artem Malyshev](mailto:proofit404@gmail.com)
- [Asger Hautop Drewsen](mailto:asgerdrewsen@gmail.com)
- [Augie Fackler](mailto:raf@durin42.com)
- [Aviskar KC](mailto:aviskarkc10@gmail.com)
- Batuhan Taşkaya
- [Benjamin Wohlwend](mailto:bw@piquadrat.ch)
- [Benjamin Woodruff](mailto:github@benjam.info)
- [Bharat Raghunathan](mailto:bharatraghunthan9767@gmail.com)
- [Brandt Bucher](mailto:brandtbucher@gmail.com)
- [Brett Cannon](mailto:brett@python.org)
- [Bryan Bugyi](mailto:bryan.bugyi@rutgers.edu)
- [Bryan Forbes](mailto:bryan@reigndropsfall.net)
- [Calum Lind](mailto:calumlind@gmail.com)
- [Charles](mailto:peacech@gmail.com)
- Charles Reid
- [Christian Clauss](mailto:cclauss@bluewin.ch)
- [Christian Heimes](mailto:christian@python.org)
- [Chuck Wooters](mailto:chuck.wooters@microsoft.com)
- [Chris Rose](mailto:offline@offby1.net)
- Codey Oxley
- [Cong](mailto:congusbongus@gmail.com)
- [Cooper Ry Lees](mailto:me@cooperlees.com)
- [Dan Davison](mailto:dandavison7@gmail.com)
- [Daniel Hahler](mailto:github@thequod.de)
- [Daniel M. Capella](mailto:polycitizen@gmail.com)
- Daniele Esposti
- [David Hotham](mailto:david.hotham@metaswitch.com)
- [David Lukes](mailto:dafydd.lukes@gmail.com)
- [David Szotten](mailto:davidszotten@gmail.com)
- [Denis Laxalde](mailto:denis@laxalde.org)
- [Douglas Thor](mailto:dthor@transphormusa.com)
- dylanjblack
- [Eli Treuherz](mailto:eli@treuherz.com)
- [Emil Hessman](mailto:emil@hessman.se)
- [Felix Kohlgrüber](mailto:felix.kohlgrueber@gmail.com)
- [Florent Thiery](mailto:fthiery@gmail.com)
- Francisco
- [Giacomo Tagliabue](mailto:giacomo.tag@gmail.com)
- [Greg Gandenberger](mailto:ggandenberger@shoprunner.com)
- [Gregory P. Smith](mailto:greg@krypto.org)
- Gustavo Camargo
- hauntsaninja
- [Hadi Alqattan](mailto:alqattanhadizaki@gmail.com)
- [Hassan Abouelela](mailto:hassan@hassanamr.com)
- [Heaford](mailto:dan@heaford.com)
- [Hugo Barrera](mailto:hugo@barrera.io)
- Hugo van Kemenade
- [Hynek Schlawack](mailto:hs@ox.cx)
- [Ionite](mailto:dev@ionite.io)
- [Ivan Katanić](mailto:ivan.katanic@gmail.com)
- [Jakub Kadlubiec](mailto:jakub.kadlubiec@skyscanner.net)
- [Jakub Warczarek](mailto:jakub.warczarek@gmail.com)
- [Jan Hnátek](mailto:jan.hnatek@gmail.com)
- [Jason Fried](mailto:me@jasonfried.info)
- [Jason Friedland](mailto:jason@friedland.id.au)
- [jgirardet](mailto:ijkl@netc.fr)
- Jim Brännlund
- [Jimmy Jia](mailto:tesrin@gmail.com)
- [Joe Antonakakis](mailto:jma353@cornell.edu)
- [Jon Dufresne](mailto:jon.dufresne@gmail.com)
- [Jonas Obrist](mailto:ojiidotch@gmail.com)
- [Jonty Wareing](mailto:jonty@jonty.co.uk)
- [Jose Nazario](mailto:jose.monkey.org@gmail.com)
- [Joseph Larson](mailto:larson.joseph@gmail.com)
- [Josh Bode](mailto:joshbode@fastmail.com)
- [Josh Holland](mailto:anowlcalledjosh@gmail.com)
- [Joshua Cannon](mailto:joshdcannon@gmail.com)
- [José Padilla](mailto:jpadilla@webapplicate.com)
- [Juan Luis Cano Rodríguez](mailto:hello@juanlu.space)
- [kaiix](mailto:kvn.hou@gmail.com)
- [Katie McLaughlin](mailto:katie@glasnt.com)
- Katrin Leinweber
- [Keith Smiley](mailto:keithbsmiley@gmail.com)
- [Kenyon Ralph](mailto:kenyon@kenyonralph.com)
- [Kevin Kirsche](mailto:Kev.Kirsche+GitHub@gmail.com)
- [Kyle Hausmann](mailto:kyle.hausmann@gmail.com)
- [Kyle Sunden](mailto:sunden@wisc.edu)
- Lawrence Chan
- [Linus Groh](mailto:mail@linusgroh.de)
- [Loren Carvalho](mailto:comradeloren@gmail.com)
- [Luka Sterbic](mailto:luka.sterbic@gmail.com)
- [LukasDrude](mailto:mail@lukas-drude.de)
- Mahmoud Hossam
- Mariatta
- [Matt VanEseltine](mailto:vaneseltine@gmail.com)
- [Matthew Clapp](mailto:itsayellow+dev@gmail.com)
- [Matthew Walster](mailto:matthew@walster.org)
- Max Smolens
- [Michael Aquilina](mailto:michaelaquilina@gmail.com)
- [Michael Flaxman](mailto:michael.flaxman@gmail.com)
- [Michael J. Sullivan](mailto:sully@msully.net)
- [Michael McClimon](mailto:michael@mcclimon.org)
- [Miguel Gaiowski](mailto:miggaiowski@gmail.com)
- [Mike](mailto:roshi@fedoraproject.org)
- [mikehoyio](mailto:mikehoy@gmail.com)
- [Min ho Kim](mailto:minho42@gmail.com)
- [Miroslav Shubernetskiy](mailto:miroslav@miki725.com)
- MomIsBestFriend
- [Nathan Goldbaum](mailto:ngoldbau@illinois.edu)
- [Nathan Hunt](mailto:neighthan.hunt@gmail.com)
- [Neraste](mailto:neraste.herr10@gmail.com)
- [Nikolaus Waxweiler](mailto:madigens@gmail.com)
- [Ofek Lev](mailto:ofekmeister@gmail.com)
- [Osaetin Daniel](mailto:osaetindaniel@gmail.com)
- [otstrel](mailto:otstrel@gmail.com)
- [Pablo Galindo](mailto:Pablogsal@gmail.com)
- [Paul Ganssle](mailto:p.ganssle@gmail.com)
- [Paul Meinhardt](mailto:mnhrdt@gmail.com)
- [Paul S. Reid](mailto:paul@reid-family.org)
- [Peter Bengtsson](mailto:mail@peterbe.com)
- [Peter Grayson](mailto:pete@jpgrayson.net)
- [Peter Stensmyr](mailto:peter.stensmyr@gmail.com)
- pmacosta
- [Quentin Pradet](mailto:quentin@pradet.me)
- [Ralf Schmitt](mailto:ralf@systemexit.de)
- [Ramón Valles](mailto:mroutis@protonmail.com)
- [Richard Fearn](mailto:richardfearn@gmail.com)
- [Rishikesh Jha](mailto:rishijha424@gmail.com)
- [Rupert Bedford](mailto:rupert@rupertb.com)
- Russell Davis
- [Sagi Shadur](mailto:saroad2@gmail.com)
- [Rémi Verschelde](mailto:rverschelde@gmail.com)
- [Sami Salonen](mailto:sakki@iki.fi)
- [Samuel Cormier-Iijima](mailto:samuel@cormier-iijima.com)
- [Sanket Dasgupta](mailto:sanketdasgupta@gmail.com)
- Sergi
- [Scott Stevenson](mailto:scott@stevenson.io)
- Shantanu
- [shaoran](mailto:shaoran@sakuranohana.org)
- [Shinya Fujino](mailto:shf0811@gmail.com)
- springstan
- [Stavros Korokithakis](mailto:hi@stavros.io)
- [Stephen Rosen](mailto:sirosen@globus.org)
- [Steven M. Vascellaro](mailto:S.Vascellaro@gmail.com)
- [Sunil Kapil](mailto:snlkapil@gmail.com)
- [Sébastien Eustace](mailto:sebastien.eustace@gmail.com)
- [Tal Amuyal](mailto:TalAmuyal@gmail.com)
- [Terrance](mailto:git@terrance.allofti.me)
- [Thom Lu](mailto:thomas.c.lu@gmail.com)
- [Thomas Grainger](mailto:tagrain@gmail.com)
- [Tim Gates](mailto:tim.gates@iress.com)
- [Tim Swast](mailto:swast@google.com)
- [Timo](mailto:timo_tk@hotmail.com)
- Toby Fleming
- [Tom Christie](mailto:tom@tomchristie.com)
- [Tony Narlock](mailto:tony@git-pull.com)
- [Tsuyoshi Hombashi](mailto:tsuyoshi.hombashi@gmail.com)
- [Tushar Chandra](mailto:tusharchandra2018@u.northwestern.edu)
- [Tushar Sadhwani](mailto:tushar.sadhwani000@gmail.com)
- [Tzu-ping Chung](mailto:uranusjr@gmail.com)
- [Utsav Shah](mailto:ukshah2@illinois.edu)
- utsav-dbx
- vezeli
- [Ville Skyttä](mailto:ville.skytta@iki.fi)
- [Vishwas B Sharma](mailto:sharma.vishwas88@gmail.com)
- [Vlad Emelianov](mailto:volshebnyi@gmail.com)
- [williamfzc](mailto:178894043@qq.com)
- [wouter bolsterlee](mailto:wouter@bolsterl.ee)
- Yazdan
- [Yngve Høiseth](mailto:yngve@hoiseth.net)
- [Yurii Karabas](mailto:1998uriyyo@gmail.com)
- [Zac Hatfield-Dodds](mailto:zac@zhd.dev)
+2426
View File
File diff suppressed because it is too large Load Diff
+22
View File
@@ -0,0 +1,22 @@
cff-version: 1.2.0
title: "Black: The uncompromising Python code formatter"
message: >-
If you use this software, please cite it using the metadata from this file.
type: software
authors:
- family-names: Langa
given-names: Łukasz
- name: "contributors to Black"
repository-code: "https://github.com/psf/black"
url: "https://black.readthedocs.io/en/stable/"
abstract: >-
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.
license: MIT
+13
View File
@@ -0,0 +1,13 @@
# Contributing to _Black_
Welcome future contributor! We're happy to see you willing to make the project better.
If you aren't familiar with _Black_, or are looking for documentation on something
specific, the [user documentation](https://black.readthedocs.io/en/stable/) is the best
place to look.
For getting started on contributing, please read the
[contributing documentation](https://black.readthedocs.io/en/latest/contributing/) for
all you need to know.
Thank you, and we look forward to your contributions!
+25
View File
@@ -0,0 +1,25 @@
FROM python:3.13-slim AS builder
RUN mkdir /src
COPY . /src/
ENV VIRTUAL_ENV=/opt/venv
ENV HATCH_BUILD_HOOKS_ENABLE=1
# Install build tools to compile black + dependencies
RUN apt update && apt install -y build-essential git python3-dev
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
RUN python -m venv $VIRTUAL_ENV
RUN cd /src \
&& pip install --no-cache-dir --upgrade pip \
&& pip install --no-cache-dir --group hatch \
&& hatch build -t wheel \
&& pip install --no-cache-dir dist/*-cp* \
&& pip install black[colorama,d,uvloop]
FROM python:3.13-slim
# copy only Python packages to limit the image size
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
CMD ["/opt/venv/bin/black"]
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2018 Łukasz Langa
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+231
View File
@@ -0,0 +1,231 @@
[![Black Logo](https://raw.githubusercontent.com/psf/black/main/docs/_static/logo2-readme.png)](https://black.readthedocs.io/en/stable/)
<h2 align="center">The Uncompromising Code Formatter</h2>
<p align="center">
<a href="https://github.com/psf/black/actions"><img alt="Actions Status" src="https://github.com/psf/black/workflows/Test/badge.svg"></a>
<a href="https://black.readthedocs.io/en/stable/?badge=stable"><img alt="Documentation Status" src="https://readthedocs.org/projects/black/badge/?version=stable"></a>
<a href="https://coveralls.io/github/psf/black?branch=main"><img alt="Coverage Status" src="https://coveralls.io/repos/github/psf/black/badge.svg?branch=main"></a>
<a href="https://github.com/psf/black/blob/main/LICENSE"><img alt="License: MIT" src="https://black.readthedocs.io/en/latest/_static/license.svg"></a>
<a href="https://pypi.org/project/black/"><img alt="PyPI" src="https://img.shields.io/pypi/v/black"></a>
<a href="https://pypi.org/project/black"><img alt="Supported Python Versions" src="https://img.shields.io/pypi/pyversions/black?color=brightgreen"></a>
<a href="https://pepy.tech/project/black"><img alt="Downloads" src="https://static.pepy.tech/badge/black"></a>
<a href="https://anaconda.org/conda-forge/black/"><img alt="conda-forge" src="https://img.shields.io/conda/dn/conda-forge/black.svg?label=conda-forge"></a>
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>
> “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](https://youtu.be/esZLCuWs_2Y) to learn more.
---
**[Read the documentation on ReadTheDocs!](https://black.readthedocs.io/en/stable)**
---
## 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](https://github.com/psf/black/releases/latest).
### 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:
- [Usage and Configuration](https://black.readthedocs.io/en/stable/usage_and_configuration/index.html)
_Black_ is already [successfully used](https://github.com/psf/black#used-by) 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](https://black.readthedocs.io/en/stable/the_black_code_style/index.html).
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](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#ast-before-and-after-formatting)
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](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#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:
- [The _Black_ Code Style: Current style](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html)
- [The _Black_ Code Style: Future style](https://black.readthedocs.io/en/stable/the_black_code_style/future_style.html)
Changes to the _Black_ code style are bound by the Stability Policy:
- [The _Black_ Code Style: Stability Policy](https://black.readthedocs.io/en/stable/the_black_code_style/index.html#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.
- [The _Black_ code style: Pragmatism](https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#pragmatism)
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:
- [The basics: Configuration via a file](https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file)
And if you're looking for more general configuration documentation:
- [Usage and Configuration](https://black.readthedocs.io/en/stable/usage_and_configuration/index.html)
**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`](https://www.sqlalchemy.org/):
> 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](https://www.amazon.com/stores/Dusty-Phillips/author/B00HSYG5BO):
> _Black_ is opinionated so you don't have to be.
**Hynek Schlawack**, creator of [`attrs`](https://www.attrs.org/), core developer of
Twisted and CPython:
> An auto-formatter that doesn't suck is all I want for Xmas!
**Carl Meyer**, [Django](https://www.djangoproject.com/) core developer:
> At least the name is good.
**Kenneth Reitz**, creator of [`requests`](https://requests.readthedocs.io/en/stable/)
and [pipenv](https://pipenv.pypa.io/en/stable/):
> This vastly improves the formatting of our code. Thanks a ton!
## Show your style
Use the badge in your project's README.md:
```md
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](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:
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
## License
MIT
## Contributing
Welcome! Happy to see you willing to make the project better. You can get started by
reading this:
- [Contributing: The basics](https://black.readthedocs.io/en/latest/contributing/the_basics.html)
You can also take a look at the rest of the contributing docs or talk with the
developers:
- [Contributing documentation](https://black.readthedocs.io/en/latest/contributing/index.html)
- [Chat on Discord](https://discord.gg/RtVdv86PrH)
## Change log
The log has become rather long. It moved to its own file.
See [CHANGES](https://black.readthedocs.io/en/latest/change_log.html).
## Authors
The author list is quite long nowadays, so it lives in its own file.
See [AUTHORS.md](./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](https://www.python.org/psf/codeofconduct/).
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.
+7
View File
@@ -0,0 +1,7 @@
# WeHub 来源说明
- 原始项目:`psf/black`
- 原始仓库:https://github.com/psf/black
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+11
View File
@@ -0,0 +1,11 @@
# Security Policy
## Supported Versions
Only the latest non-prerelease version is supported.
## Security contact information
To report a security vulnerability, please use the
[Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the
fix and disclosure.
+87
View File
@@ -0,0 +1,87 @@
name: "Black"
description: "The uncompromising Python code formatter."
author: "Łukasz Langa and contributors to Black"
inputs:
options:
description:
"Options passed to Black. Use `black --help` to see available options. Default:
'--check --diff'"
required: false
default: "--check --diff"
src:
description: "Source to run Black. Default: '.'"
required: false
default: "."
jupyter:
description:
"Set this option to true to include Jupyter Notebook files. Default: false"
required: false
default: false
black_args:
description: "[DEPRECATED] Black input arguments."
required: false
default: ""
deprecationMessage:
"Input `with.black_args` is deprecated. Use `with.options` and `with.src` instead."
version:
description: 'Python Version specifier (PEP440) - e.g. "21.5b1"'
required: false
default: ""
use_pyproject:
description: Read Black version specifier from pyproject.toml if `true`.
required: false
default: "false"
summary:
description: "Whether to add the output to the workflow summary"
required: false
default: true
output-file:
description: >
Optional path to write Black output to a file in addition to stdout. Useful for
keeping GitHub Actions logs clean when using --diff or --check.
required: false
default: ""
branding:
color: "black"
icon: "check-circle"
runs:
using: composite
steps:
- name: black
run: |
# Even when black fails, do not close the shell
set +e
if [ "$RUNNER_OS" == "Windows" ]; then
runner="python"
else
runner="python3"
fi
out=$(${runner} $GITHUB_ACTION_PATH/action/main.py)
exit_code=$?
# Display the raw output in the step
echo "${out}"
if [ "${INPUT_SUMMARY}" == "true" ]; then
# Display the Markdown output in the job summary
echo "\`\`\`python" >> $GITHUB_STEP_SUMMARY
echo "${out}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi
# Exit with the exit-code returned by Black
exit ${exit_code}
env:
# TODO: Remove once https://github.com/actions/runner/issues/665 is fixed.
INPUT_OPTIONS: ${{ inputs.options }}
INPUT_SRC: ${{ inputs.src }}
INPUT_JUPYTER: ${{ inputs.jupyter }}
INPUT_BLACK_ARGS: ${{ inputs.black_args }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_USE_PYPROJECT: ${{ inputs.use_pyproject }}
INPUT_SUMMARY: ${{ inputs.summary }}
OUTPUT_FILE: ${{ inputs.output-file }}
pythonioencoding: utf-8
shell: bash
+201
View File
@@ -0,0 +1,201 @@
import os
import re
import shlex
import shutil
import sys
from pathlib import Path
from subprocess import PIPE, STDOUT, run
ACTION_PATH = Path(os.environ["GITHUB_ACTION_PATH"])
ENV_PATH = ACTION_PATH / ".black-env"
ENV_BIN = ENV_PATH / ("Scripts" if sys.platform == "win32" else "bin")
OPTIONS = os.getenv("INPUT_OPTIONS", default="")
SRC = os.getenv("INPUT_SRC", default="")
JUPYTER = os.getenv("INPUT_JUPYTER") == "true"
BLACK_ARGS = os.getenv("INPUT_BLACK_ARGS", default="")
VERSION = os.getenv("INPUT_VERSION", default="")
USE_PYPROJECT = os.getenv("INPUT_USE_PYPROJECT") == "true"
OUTPUT_FILE = os.getenv("OUTPUT_FILE", default="")
BLACK_VERSION_RE = re.compile(
r"^black((?:\s*(?:~=|==|!=|<=|>=|<|>|===)\s*[A-Za-z0-9*+._-]+)"
r"(?:\s*,\s*(?:~=|==|!=|<=|>=|<|>|===)\s*[A-Za-z0-9*+._-]+)*)\s*$",
re.IGNORECASE,
)
EXTRAS_RE = re.compile(r"\[.*\]")
EXPORT_SUBST_FAIL_RE = re.compile(r"\$Format:.*\$")
def determine_version_specifier() -> str:
"""Determine the version of Black to install.
The version can be specified either via the `with.version` input or via the
pyproject.toml file if `with.use_pyproject` is set to `true`.
"""
if USE_PYPROJECT and VERSION:
print(
"::error::'with.version' and 'with.use_pyproject' inputs are "
"mutually exclusive.",
file=sys.stderr,
flush=True,
)
sys.exit(1)
if USE_PYPROJECT:
return read_version_specifier_from_pyproject()
elif VERSION and VERSION[0] in "0123456789":
return f"=={VERSION}"
else:
return VERSION
def read_version_specifier_from_pyproject() -> str:
if sys.version_info < (3, 11):
print(
"::error::'with.use_pyproject' input requires Python 3.11 or later.",
file=sys.stderr,
flush=True,
)
sys.exit(1)
import tomllib # type: ignore[import-not-found,unreachable]
try:
with Path("pyproject.toml").open("rb") as fp:
pyproject = tomllib.load(fp)
except FileNotFoundError:
print(
"::error::'with.use_pyproject' input requires a pyproject.toml file.",
file=sys.stderr,
flush=True,
)
sys.exit(1)
version = pyproject.get("tool", {}).get("black", {}).get("required-version")
if version is not None:
# Match the two supported usages of `required-version`:
if "." in version:
return f"=={version}"
else:
return f"~={version}.0"
arrays = [
*pyproject.get("dependency-groups", {}).values(),
pyproject.get("project", {}).get("dependencies"),
*pyproject.get("project", {}).get("optional-dependencies", {}).values(),
]
for array in arrays:
version = find_black_version_in_array(array)
if version is not None:
break
if version is None:
print(
"::error::'black' dependency missing from pyproject.toml.",
file=sys.stderr,
flush=True,
)
sys.exit(1)
return version
def find_black_version_in_array(array: object) -> str | None:
if not isinstance(array, list):
return None
try:
for item in array:
# Rudimentary PEP 508 parsing.
item = item.split(";")[0]
item = EXTRAS_RE.sub("", item).strip()
if item == "black":
print(
"::error::Version specifier missing for 'black' dependency in "
"pyproject.toml.",
file=sys.stderr,
flush=True,
)
sys.exit(1)
elif m := BLACK_VERSION_RE.match(item):
return m.group(1).strip()
except TypeError:
pass
return None
run([sys.executable, "-m", "venv", str(ENV_PATH)], check=True)
version_specifier = determine_version_specifier()
if JUPYTER:
extra_deps = "[colorama,jupyter]"
else:
extra_deps = "[colorama]"
if version_specifier:
req = f"black{extra_deps}{version_specifier}"
else:
describe_name = ""
with open(ACTION_PATH / ".git_archival.txt", encoding="utf-8") as fp:
for line in fp:
if line.startswith("describe-name: "):
describe_name = line[len("describe-name: ") :].rstrip()
break
if not describe_name:
print("::error::Failed to detect action version.", file=sys.stderr, flush=True)
sys.exit(1)
# expected format is one of:
# - 23.1.0
# - 23.1.0-51-g448bba7
# - $Format:%(describe:tags=true,match=*[0-9]*)$ (if export-subst fails)
if (
describe_name.count("-") < 2
and EXPORT_SUBST_FAIL_RE.match(describe_name) is None
):
# the action's commit matches a tag exactly, install exact version from PyPI
req = f"black{extra_deps}=={describe_name}"
else:
# the action's commit does not match any tag, install from the local git repo
req = f".{extra_deps}"
print(f"Installing {req}...", flush=True)
pip_proc = run(
[str(ENV_BIN / "python"), "-m", "pip", "install", req],
stdout=PIPE,
stderr=STDOUT,
encoding="utf-8",
cwd=ACTION_PATH,
)
if pip_proc.returncode:
print(pip_proc.stdout)
print("::error::Failed to install Black.", file=sys.stderr, flush=True)
sys.exit(pip_proc.returncode)
base_cmd = [str(ENV_BIN / "black")]
if BLACK_ARGS:
# TODO: remove after a while since this is deprecated in favour of SRC + OPTIONS.
proc = run(
[*base_cmd, *shlex.split(BLACK_ARGS)],
stdout=PIPE,
stderr=STDOUT,
encoding="utf-8",
)
else:
proc = run(
[*base_cmd, *shlex.split(OPTIONS), *shlex.split(SRC)],
stdout=PIPE,
stderr=STDOUT,
encoding="utf-8",
)
shutil.rmtree(ENV_PATH, ignore_errors=True)
# Write output to file if specified
if OUTPUT_FILE:
try:
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
f.write(proc.stdout)
print(f"Black output written to {OUTPUT_FILE}")
except Exception as e:
print(f"::error::Failed to write output to {OUTPUT_FILE}: {e}", file=sys.stderr)
sys.exit(1)
print(proc.stdout)
sys.exit(proc.returncode)
+303
View File
@@ -0,0 +1,303 @@
python3 << EndPython3
import collections
import os
import sys
import vim
def strtobool(text):
if text.lower() in ["y", "yes", "t", "true", "on", "1"]:
return True
if text.lower() in ["n", "no", "f", "false", "off", "0"]:
return False
raise ValueError(f"{text} is not convertible to boolean")
class Flag(collections.namedtuple("FlagBase", "name, cast")):
@property
def var_name(self):
return self.name.replace("-", "_")
@property
def vim_rc_name(self):
name = self.var_name
if name == "line_length":
name = name.replace("_", "")
return "g:black_" + name
FLAGS = [
Flag(name="line_length", cast=int),
Flag(name="fast", cast=strtobool),
Flag(name="skip_string_normalization", cast=strtobool),
Flag(name="quiet", cast=strtobool),
Flag(name="skip_magic_trailing_comma", cast=strtobool),
Flag(name="preview", cast=strtobool),
]
def _get_python_binary(exec_prefix, pyver):
try:
default = vim.eval("g:pymode_python").strip()
except vim.error:
default = ""
if default and os.path.exists(default):
return default
if sys.platform[:3] == "win":
return exec_prefix / "python.exe"
bin_path = exec_prefix / "bin"
exec_path = (bin_path / f"python{pyver[0]}.{pyver[1]}").resolve()
if exec_path.exists():
return exec_path
# It is possible that some environments may only have python3
exec_path = (bin_path / "python3").resolve()
if exec_path.exists():
return exec_path
raise ValueError("python executable not found")
def _get_pip(venv_path):
if sys.platform[:3] == "win":
return venv_path / "Scripts" / "pip.exe"
return venv_path / "bin" / "pip"
def _get_virtualenv_site_packages(venv_path, pyver):
if sys.platform[:3] == "win":
return venv_path / "Lib" / "site-packages"
if (
venv_path.exists()
and not (venv_path / "lib" / f"python{pyver[0]}.{pyver[1]}").exists()
):
# The virtualenv already exists but it doesn't seem to have the expected
# Python version, so we disregard the requested `pyver` and
# discover the real Python interpreter from this virtualenv
import subprocess
result = subprocess.run(
[_get_python_binary(venv_path, pyver), "--version"],
stdout=subprocess.PIPE,
text=True,
)
venv_version = result.stdout.split(" ")[1].strip().split(".")
return (
venv_path
/ "lib"
/ f"python{venv_version[0]}.{venv_version[1]}"
/ "site-packages"
)
else:
return venv_path / "lib" / f"python{pyver[0]}.{pyver[1]}" / "site-packages"
def _initialize_black_env(upgrade=False):
if vim.eval("g:black_use_virtualenv ? 'true' : 'false'") == "false":
if upgrade:
print("Upgrade disabled due to g:black_use_virtualenv being disabled.")
print(
"Either use your system package manager (or pip) to upgrade black"
" separately,"
)
print("or modify your vimrc to have 'let g:black_use_virtualenv = 1'.")
return False
else:
# Nothing needed to be done.
return True
pyver = sys.version_info[:3]
if pyver < (3, 10):
print("Sorry, Black requires Python 3.10+ to run.")
return False
from pathlib import Path
import subprocess
import venv
virtualenv_path = Path(vim.eval("g:black_virtualenv")).expanduser()
virtualenv_site_packages = str(
_get_virtualenv_site_packages(virtualenv_path, pyver)
)
first_install = False
if not virtualenv_path.is_dir():
print("Please wait, one time setup for Black.")
_executable = sys.executable
_base_executable = getattr(sys, "_base_executable", _executable)
try:
executable = str(_get_python_binary(Path(sys.exec_prefix), pyver))
sys.executable = executable
sys._base_executable = executable
print(f"Creating a virtualenv in {virtualenv_path}...")
print(
"(this path can be customized in .vimrc by setting g:black_virtualenv)"
)
venv.create(virtualenv_path, with_pip=True)
except Exception:
print(
"Encountered exception while creating virtualenv (see traceback below)."
)
print(f"Removing {virtualenv_path}...")
import shutil
shutil.rmtree(virtualenv_path)
raise
finally:
sys.executable = _executable
sys._base_executable = _base_executable
first_install = True
if first_install:
print("Installing Black with pip...")
if upgrade:
print("Upgrading Black with pip...")
if first_install or upgrade:
subprocess.run(
[str(_get_pip(virtualenv_path)), "install", "-U", "black"],
stdout=subprocess.PIPE,
)
print("DONE! You are all set, thanks for waiting ✨ 🍰 ✨")
if first_install:
print(
"Pro-tip: to upgrade Black in the future, use the :BlackUpgrade command and"
" restart Vim.\n"
)
if virtualenv_site_packages not in sys.path:
sys.path.insert(0, virtualenv_site_packages)
return True
if _initialize_black_env():
try:
import black
except ImportError:
print(f"Could not import black from any of: {', '.join(sys.path)}.")
import time
def get_target_version(tv):
if isinstance(tv, black.TargetVersion):
return tv
ret = None
try:
ret = black.TargetVersion[tv.upper()]
except KeyError:
print(
f"WARNING: Target version {tv!r} not recognized by Black, using default"
" target"
)
return ret
def Black(**kwargs):
"""
kwargs allows you to override ``target_versions`` argument of
``black.FileMode``.
``target_version`` needs to be cleaned because ``black.FileMode``
expects the ``target_versions`` argument to be a set of TargetVersion enums.
Allow kwargs["target_version"] to be a string to allow
to type it more quickly.
Using also target_version instead of target_versions to remain
consistent to Black's documentation of the structure of pyproject.toml.
"""
start = time.time()
configs = get_configs()
black_kwargs = {}
if "target_version" in kwargs:
target_version = kwargs["target_version"]
if not isinstance(target_version, (list, set)):
target_version = [target_version]
target_version = set(
filter(lambda x: x, map(lambda tv: get_target_version(tv), target_version))
)
black_kwargs["target_versions"] = target_version
mode = black.FileMode(
line_length=configs["line_length"],
string_normalization=not configs["skip_string_normalization"],
is_pyi=vim.current.buffer.name.endswith(".pyi"),
magic_trailing_comma=not configs["skip_magic_trailing_comma"],
preview=configs["preview"],
**black_kwargs,
)
quiet = configs["quiet"]
buffer_str = "\n".join(vim.current.buffer) + "\n"
try:
new_buffer_str = black.format_file_contents(
buffer_str,
fast=configs["fast"],
mode=mode,
)
except black.NothingChanged:
if not quiet:
print(
"Black: already well formatted, good job. (took"
f" {time.time() - start:.4f}s)"
)
except Exception as exc:
print(f"Black: {exc}")
else:
current_buffer = vim.current.window.buffer
cursors = []
for i, tabpage in enumerate(vim.tabpages):
if tabpage.valid:
for j, window in enumerate(tabpage.windows):
if window.valid and window.buffer == current_buffer:
cursors.append((i, j, window.cursor))
vim.current.buffer[:] = new_buffer_str.split("\n")[:-1]
for i, j, cursor in cursors:
window = vim.tabpages[i].windows[j]
try:
window.cursor = cursor
except vim.error:
window.cursor = (len(window.buffer), 0)
if not quiet:
print(f"Black: reformatted in {time.time() - start:.4f}s.")
def get_configs():
filename = vim.eval("@%")
path_pyproject_toml = black.find_pyproject_toml((filename,))
if path_pyproject_toml:
toml_config = black.parse_pyproject_toml(path_pyproject_toml)
else:
toml_config = {}
return {
flag.var_name: toml_config.get(flag.name, flag.cast(vim.eval(flag.vim_rc_name)))
for flag in FLAGS
}
def BlackUpgrade():
_initialize_black_env(upgrade=True)
def BlackVersion():
print(f"Black, version {black.__version__} on Python {sys.version}.")
EndPython3
function black#Black(...)
let kwargs = {}
for arg in a:000
let arg_list = split(arg, '=')
let kwargs[arg_list[0]] = arg_list[1]
endfor
python3 << EOF
import vim
kwargs = vim.eval("kwargs")
EOF
:py3 Black(**kwargs)
endfunction
function black#BlackUpgrade()
:py3 BlackUpgrade()
endfunction
function black#BlackVersion()
:py3 BlackVersion()
endfunction
+20
View File
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = black
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="78" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="78" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h47v20H0z"/><path fill="#7900CA" d="M47 0h31v20H47z"/><path fill="url(#b)" d="M0 0h78v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="245" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">license</text><text x="245" y="140" transform="scale(.1)" textLength="370">license</text><text x="615" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="210">MIT</text><text x="615" y="140" transform="scale(.1)" textLength="210">MIT</text></g> </svg>

After

Width:  |  Height:  |  Size: 950 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="88" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="88" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h33v20H0z"/><path fill="#007ec6" d="M33 0h55v20H33z"/><path fill="url(#b)" d="M0 0h88v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"><text x="175" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="230">pypi</text><text x="175" y="140" transform="scale(.1)" textLength="230">pypi</text><text x="595" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="450">$version</text><text x="595" y="140" transform="scale(.1)" textLength="450">$version</text></g> </svg>

After

Width:  |  Height:  |  Size: 954 B

+3
View File
@@ -0,0 +1,3 @@
```{include} ../AUTHORS.md
```
+3
View File
@@ -0,0 +1,3 @@
```{include} ../CHANGES.md
```
+3
View File
@@ -0,0 +1,3 @@
[flake8]
max-line-length = 88
extend-ignore = E203,E701
+3
View File
@@ -0,0 +1,3 @@
[flake8]
max-line-length = 88
extend-ignore = E203,E701
+3
View File
@@ -0,0 +1,3 @@
[flake8]
max-line-length = 88
extend-ignore = E203,E701
@@ -0,0 +1,2 @@
[*.py]
profile = black
+2
View File
@@ -0,0 +1,2 @@
[settings]
profile = black
@@ -0,0 +1,2 @@
[tool.isort]
profile = 'black'
+2
View File
@@ -0,0 +1,2 @@
[isort]
profile = black
@@ -0,0 +1,3 @@
[pycodestyle]
max-line-length = 88
ignore = E203,E701
@@ -0,0 +1,3 @@
[pycodestyle]
max-line-length = 88
ignore = E203,E701
@@ -0,0 +1,3 @@
[pycodestyle]
max-line-length = 88
ignore = E203,E701
+2
View File
@@ -0,0 +1,2 @@
[format]
max-line-length = 88
@@ -0,0 +1,2 @@
[tool.pylint.format]
max-line-length = "88"
+2
View File
@@ -0,0 +1,2 @@
[pylint]
max-line-length = 88
+235
View File
@@ -0,0 +1,235 @@
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import re
import string
from importlib.metadata import version
from pathlib import Path
from sphinx.application import Sphinx
CURRENT_DIR = Path(__file__).parent
def make_pypi_svg(version: str) -> None:
template: Path = CURRENT_DIR / "_static" / "pypi_template.svg"
target: Path = CURRENT_DIR / "_static" / "pypi.svg"
with open(str(template), encoding="utf8") as f:
svg: str = string.Template(f.read()).substitute(version=version)
with open(str(target), "w", encoding="utf8") as f:
f.write(svg)
def replace_pr_numbers_with_links(content: str) -> str:
"""Replaces all PR numbers with the corresponding GitHub link."""
return re.sub(r"#(\d+)", r"[#\1](https://github.com/psf/black/pull/\1)", content)
def handle_include_read(
app: Sphinx,
relative_path: Path,
parent_docname: str,
content: list[str],
) -> None:
"""Handler for the include-read sphinx event."""
if parent_docname == "change_log":
content[0] = replace_pr_numbers_with_links(content[0])
def setup(app: Sphinx) -> None:
"""Sets up a minimal sphinx extension."""
app.connect("include-read", handle_include_read)
# Necessary so Click doesn't hit an encode error when called by
# sphinxcontrib-programoutput on Windows.
os.putenv("pythonioencoding", "utf-8")
# -- Project information -----------------------------------------------------
project = "Black"
copyright = "2018-Present, Łukasz Langa and contributors to Black"
author = "Łukasz Langa and contributors to Black"
# Autopopulate version
# The version, including alpha/beta/rc tags, but not commit hash and datestamps
release = version("black").split("+")[0]
# The short X.Y version.
version = release
for sp in "abcfr":
version = version.split(sp)[0]
make_pypi_svg(release)
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx.ext.napoleon",
"myst_parser",
"sphinxcontrib.programoutput",
"sphinx_copybutton",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
source_suffix = [".rst", ".md"]
# The master toctree document.
master_doc = "index"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path .
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
# We need headers to be linkable to so ask MyST-Parser to autogenerate anchor IDs for
# headers up to and including level 3.
myst_heading_anchors = 3
# Prettier support formatting some MyST syntax but not all, so let's disable the
# unsupported yet still enabled by default ones.
myst_disable_syntax = [
"colon_fence",
"myst_block_break",
"myst_line_comment",
"math_block",
]
# Optional MyST Syntaxes
myst_enable_extensions = []
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = "furo"
html_logo = "_static/logo2-readme.png"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = "blackdoc"
# -- Options for LaTeX output ------------------------------------------------
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [(
master_doc,
"black.tex",
"Documentation for Black",
"Łukasz Langa and contributors to Black",
"manual",
)]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "black", "Documentation for Black", [author], 1)]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [(
master_doc,
"Black",
"Documentation for Black",
author,
"Black",
"The uncompromising Python code formatter",
"Miscellaneous",
)]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ["search.html"]
# -- Extension configuration -------------------------------------------------
autodoc_member_order = "bysource"
# -- sphinx-copybutton configuration ----------------------------------------
copybutton_prompt_text = (
r">>> |\.\.\. |> |\$ |\# | In \[\d*\]: | {2,5}\.\.\.: | {5,8}: "
)
copybutton_prompt_is_regexp = True
copybutton_remove_prompts = True
# -- Options for intersphinx extension ---------------------------------------
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
+57
View File
@@ -0,0 +1,57 @@
# 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][diff-shades].
### 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
[diff-shades]: https://github.com/ichard26/diff-shades#readme
+45
View File
@@ -0,0 +1,45 @@
# 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](https://black.readthedocs.io/en/latest/) 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](https://github.com/psf/black/issues/new/choose) 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`.
+173
View File
@@ -0,0 +1,173 @@
# 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/master/docs/the_black_code_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!
```
+180
View File
@@ -0,0 +1,180 @@
# 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](labels/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](#release-workflows) 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
1. 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`)
1. File a PR editing `CHANGES.md` and the docs to version the latest changes
- Run `python3 scripts/release.py [--debug]` to generate most changes
1. If `release.py` fails manually edit; otherwise, yay, skip this step!
1. Replace the `## Unreleased` header with the version number
1. Remove any empty sections for the current release
1. (_optional_) Read through and copy-edit the changelog (eg. by moving entries,
fixing typos, or rephrasing entries)
1. Update references to the latest version in
{doc}`/integrations/source_version_control` and
{doc}`/usage_and_configuration/the_basics`
- Example PR: [GH-4563]
1. 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
1. [Draft a new GitHub Release][new-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
1. Verify that the new tag targets the `main` branch
1. Make sure the release title is set to the version (`YY.M.N`), as otherwise the
default title is the last commit's title
1. Copy and paste the _raw changelog Markdown_ for the current release into the
description box
1. Publish the GitHub Release, triggering [release automation](#release-workflows) that
will handle the rest
1. 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]`
1. Should that fail, please return to copy + paste
1. At this point, you're basically done. It's good practice to go and [watch and verify
that all the release workflows pass][black-actions], 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](labels/mypyc-support).
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][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](https://wiki.python.org/moin/PythonImplementations) 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.
[black-actions]: https://github.com/psf/black/actions
[calver]: https://calver.org
[cibuildwheel]: https://cibuildwheel.readthedocs.io/
[gh-4563]: https://github.com/psf/black/pull/4563
[github actions]: https://github.com/features/actions
[github release]: https://github.com/psf/black/releases
[hatch]: https://hatch.pypa.io/latest/
[mypyc]: https://mypyc.readthedocs.io/
[new-release]: https://github.com/psf/black/releases/new
[pyinstaller]: https://www.pyinstaller.org/
[sdist]:
https://packaging.python.org/en/latest/glossary/#term-source-distribution-or-sdist
[trusted-publishing]: https://docs.pypi.org/trusted-publishers/
[wheels]: https://packaging.python.org/en/latest/glossary/#term-wheel
+152
View File
@@ -0,0 +1,152 @@
# 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`.
#### `--print-full-tree`
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
```
#### `--print-tree-diff`
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)
```
<!---
The Next PR Number link uses HTML because of a bug in MyST-Parser that double-escapes the ampersand, causing the query parameters to not be processed.
MyST-Parser issue: https://github.com/executablebooks/MyST-Parser/issues/760
MyST-Parser stalled fix PR: https://github.com/executablebooks/MyST-Parser/pull/929
-->
Note that X should be your PR number, not issue number! To workout X, please use
<a href="https://ichard26.github.io/next-pr-number/?owner=psf&name=black">Next PR
Number</a>. 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](labels/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.
+139
View File
@@ -0,0 +1,139 @@
# Frequently Asked Questions
The most common questions and issues users face are aggregated to this FAQ.
```{contents}
:local:
:backlinks: none
:class: this-will-duplicate-information-and-it-is-still-useful-here
```
## Why spaces? I prefer tabs
PEP 8 recommends spaces over tabs, and they are used by most of the Python community.
_Black_ provides no options to configure the indentation style, and requests for such
options will not be considered.
However, we recognise that using tabs is an accessibility issue as well. While the
option will never be added to _Black_, visually impaired developers may find conversion
tools such as `expand/unexpand` (for Linux) useful when contributing to Python projects.
A workflow might consist of e.g. setting up appropriate pre-commit and post-merge git
hooks, and scripting `unexpand` to run after applying _Black_.
## Does Black have an API?
Not yet. _Black_ is fundamentally a command line tool. Many
[integrations](/integrations/index.md) are provided, but a Python interface is not one
of them. A simple API is being [planned](https://github.com/psf/black/issues/779)
though.
## Is Black safe to use?
Yes. _Black_ is strictly about formatting, nothing else. Black strives to ensure that
after formatting the AST is
[checked](the_black_code_style/current_style.md#ast-before-and-after-formatting) with
limited special cases where the code is allowed to differ. If issues are found, an error
is raised and the file is left untouched. Magical comments that influence linters and
other tools, such as `# noqa`, may be moved by _Black_. See below for more details.
## How stable is Black's style?
Stable. _Black_ aims to enforce one style and one style only, with some room for
pragmatism. See [The Black Code Style](the_black_code_style/index.md) for more details.
Starting in 2022, the formatting output is stable for the releases made in the same year
(other than unintentional bugs). At the beginning of every year, the first release will
make changes to the stable style. It is possible to opt in to the latest formatting
styles using the `--preview` flag.
## Why is my file not formatted?
Most likely because it is ignored in `.gitignore` or excluded with configuration. See
[file collection and discovery](usage_and_configuration/file_collection_and_discovery.md)
for details.
## Why is my Jupyter Notebook cell not formatted?
_Black_ is timid about formatting Jupyter Notebooks. Cells containing any of the
following will not be formatted:
- automagics (e.g. `pip install black`)
- non-Python cell magics (e.g. `%%writefile`)
- multiline magics
- code which `IPython`'s `TransformerManager` would transform magics into
- invalid syntax
See
[Using _Black_ with Jupyter Notebooks](guides/using_black_with_jupyter_notebooks.md#cells-that-black-will-skip)
for details.
## Why does Flake8 report warnings?
Some of Flake8's rules conflict with Black's style. We recommend disabling these rules.
See [Using _Black_ with other tools](labels/why-pycodestyle-warnings).
## Which Python versions does Black support?
_Black_ generally supports all Python versions supported by CPython (see
[the Python devguide](https://devguide.python.org/versions/) for current information).
We promise to support at least all Python versions that have not reached their end of
life. This is the case for both running _Black_ and formatting code.
Support for formatting Python 2 code was removed in version 22.0. While we've made no
plans to stop supporting older Python 3 minor versions immediately, their support might
also be removed some time in the future without a deprecation period.
`await`/`async` as soft keywords/identifiers are no longer supported as of 25.9.0.
Runtime support for 3.6 was removed in version 22.10.0, for 3.7 in version 23.7.0, for
3.8 in version 24.10.0, and for 3.9 in version 25.12.0.
## Why does my linter or typechecker complain after I format my code?
Some linters and other tools use magical comments (e.g., `# noqa`, `# type: ignore`) to
influence their behavior. While Black does its best to recognize such comments and leave
them in the right place, this detection is not and cannot be perfect. Therefore, you'll
sometimes have to manually move these comments to the right place after you format your
codebase with _Black_.
## Can I run Black with PyPy?
Yes, there is support for PyPy 3.8 and higher.
## Why does Black not detect syntax errors in my code?
_Black_ is an autoformatter, not a Python linter or interpreter. Detecting all syntax
errors is not a goal. It can format all code accepted by CPython (if you find an example
where that doesn't hold, please report a bug!), but it may also format some code that
CPython doesn't accept.
(labels/mypyc-support)=
## What is `compiled: yes/no` all about in the version output?
While _Black_ is indeed a pure Python project, we use [mypyc] to compile _Black_ into a
C Python extension, usually doubling performance. These compiled wheels are available
for 64-bit versions of Windows (both AMD and ARM), Linux (via the manylinux standard),
and macOS across all supported CPython versions.
Platforms including musl-based and/or ARM Linux distributions are currently **not**
supported. These platforms will fall back to the slower pure Python wheel available on
PyPI.
If you are experiencing exceptionally weird issues or even segfaults, you can try
passing `--no-binary black` to your pip install invocation. This flag excludes all
wheels (including the pure Python wheel), so this command will use the [sdist].
[mypyc]: https://mypyc.readthedocs.io/en/stable/
[sdist]:
https://packaging.python.org/en/latest/glossary/#term-Source-Distribution-or-sdist
## Why are emoji not displaying correctly on Windows?
When using Windows, the emoji in _Black_'s output may not display correctly. This is not
fixable from _Black_'s end.
Instead, run your chosen command line/shell through [Windows Terminal], which will
properly handle rendering the emoji.
[Windows Terminal]: https://aka.ms/terminal
+62
View File
@@ -0,0 +1,62 @@
# Getting Started
New to _Black_? Don't worry, you've found the perfect place to get started!
## Do you like the _Black_ code style?
Before using _Black_ on some of your code, it might be a good idea to first understand
how _Black_ will format your code. _Black_ isn't for everyone and you may find something
that is a dealbreaker for you personally, which is okay! The current _Black_ code style
[is described here](./the_black_code_style/current_style.md).
## Try it out quickly
If you want a quick taste of _Black_ without creating a file first, format a snippet
from the command line:
```sh
black --code "x = { 'a':1,'b':2 }"
```
## Installation
_Black_ can be installed by running `pip install black`. It requires Python 3.10+ to
run.
If you use pipx, you can install Black with `pipx install black`.
If you want to format Jupyter Notebooks, install with `pip install "black[jupyter]"`.
See the [Jupyter Notebooks guide](./guides/using_black_with_jupyter_notebooks.md) for
more details.
If you want to run _Black_ without installing Python, download one of the
PyInstaller-built standalone executables from the
[latest GitHub release](https://github.com/psf/black/releases/latest).
If you can't wait for the latest _hotness_ and want to install from GitHub, use:
`pip install git+https://github.com/psf/black`
## Basic 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}...
```
## Next steps
Took a look at [the _Black_ code style](./the_black_code_style/current_style.md) and
tried out _Black_? Fantastic, you're ready for more. Why not explore some more on using
_Black_ by reading
[Usage and Configuration: The basics](./usage_and_configuration/the_basics.md).
Alternatively, you can check out the
[Introducing _Black_ to your project](./guides/introducing_black_to_your_project.md)
guide.
+18
View File
@@ -0,0 +1,18 @@
# 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`
@@ -0,0 +1,52 @@
# 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](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revltrevgt)
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](https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view)
and
[GitLab (since version 17.10)](https://about.gitlab.com/releases/2025/03/20/gitlab-17-10-released/#ignore-specific-revisions-in-git-blame)
both support `.git-blame-ignore-revs` in blame views by default.
@@ -0,0 +1,134 @@
# Using _Black_ with Jupyter Notebooks
_Black_ supports formatting Jupyter Notebooks (`.ipynb` files) natively.
## Installation
To format Jupyter Notebooks, install _Black_ with the `jupyter` extra:
```sh
pip install "black[jupyter]"
```
```{note}
Without the `jupyter` extra, _Black_ will not be able to format `.ipynb` files.
```
## Basic usage
Once installed, you can format notebooks the same way you format Python files:
```sh
black notebook.ipynb
```
You can also format entire directories containing a mix of `.py` and `.ipynb` files:
```sh
black .
```
_Black_ will automatically detect Jupyter Notebooks by their `.ipynb` extension and
format them accordingly.
### Formatting via standard input
If you're piping notebook content on standard input, use the `--ipynb` flag to tell
_Black_ to treat the input as a Jupyter Notebook:
```sh
cat notebook.ipynb | black --ipynb -
```
## What is (and isn't) formatted
_Black_ formats the Python code cells in your notebook while preserving:
- Markdown cells
- Cell outputs
- Cell metadata
- Notebook metadata
Only the source code within Python code cells is reformatted.
### Cells that _Black_ will skip
_Black_ is cautious about formatting notebook cells. The following cells will **not** be
formatted:
- **Automagics** — e.g. `pip install black` (without the `%` prefix)
- **Non-Python cell magics** — e.g.:
```python
%%writefile script.py
print("hello")
```
- **Multiline magics** — e.g.:
```python
%timeit f(1, \
2, \
3)
```
- **IPython internal calls** — code that `IPython`'s `TransformerManager` would
transform, e.g.:
```python
get_ipython().system('ls')
```
- **Invalid syntax** — as it cannot be safely distinguished from automagics without a
running IPython kernel.
If you notice a cell is not being formatted, it is likely because it contains one of the
above constructs.
Additionally, _Black_ cannot format Jupyter Notebooks with the `--line-ranges` option.
### Cell magics
_Black_ understands IPython magics, but is conservative about which cells it will
format. By default, _Black_ recognizes standard IPython magics.
#### Custom python cell magics
If you use custom cell magics that contain Python code, you can tell _Black_ about them
using the `--python-cell-magics` flag:
```sh
black --python-cell-magics writefile notebook.ipynb
```
This also works in `pyproject.toml`:
```toml
[tool.black]
python-cell-magics = ["writefile", "my_custom_magic"]
```
## Integrations
### pre-commit
Simply replace the `black` hook with `black-jupyter`.
```yaml
repos:
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.5.1
hooks:
- id: black-jupyter
language_version: python3.11
```
See the [source version control integration](../integrations/source_version_control.md)
docs for more examples of using Black with pre-commit.
### GitHub Actions
Set the `jupyter` option to `true`.
```yaml
- uses: psf/black@stable
with:
jupyter: true
```
See the [GitHub Actions integration](../integrations/source_version_control.md) docs for
more examples of using Black with GitHub Actions.
+303
View File
@@ -0,0 +1,303 @@
# 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](https://github.com/psf/black/blob/main/docs/compatible_configs/).
### isort
[isort](https://isort.readthedocs.io/) 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](https://isort.readthedocs.io/en/latest/configuration/profiles.html) to allow
easy interoperability with common code styles. You can set the black profile in any of
the
[config files](https://isort.readthedocs.io/en/latest/configuration/config_files.html)
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](../the_black_code_style/current_style.md#how-black-wraps-lines).
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
<details>
<summary>.isort.cfg</summary>
```ini
[settings]
profile = black
```
</details>
<details>
<summary>setup.cfg</summary>
```ini
[isort]
profile = black
```
</details>
<details>
<summary>pyproject.toml</summary>
```toml
[tool.isort]
profile = 'black'
```
</details>
<details>
<summary>.editorconfig</summary>
```ini
[*.py]
profile = black
```
</details>
### pycodestyle
[pycodestyle](https://pycodestyle.pycqa.org/en/stable/) is a code linter. It warns you
of syntax errors, possible bugs, stylistic errors, etc. For the most part, pycodestyle
follows [PEP 8](https://peps.python.org/pep-0008/) 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](https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b#diff-64ec08cc46db7540f18f2af46037f599).
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
<details>
<summary>setup.cfg, .pycodestyle, tox.ini</summary>
```ini
[pycodestyle]
max-line-length = 88
ignore = E203,E701
```
</details>
### Flake8
[Flake8](https://flake8.pycqa.org/en/stable/) 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](https://github.com/PyCQA/flake8-bugbear)
and enable
[its B950 check](https://github.com/PyCQA/flake8-bugbear#opinionated-warnings#:~:text=you%20expect%20it.-,B950,-%3A%20Line%20too%20long)
instead of using Flake8's E501, because it aligns with
[Black's 10% rule](labels/line-length).
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](labels/why-pycodestyle-warnings) above.
#### Formats
<details>
<summary>.flake8, setup.cfg, tox.ini</summary>
```ini
[flake8]
max-line-length = 88
extend-ignore = E203,E701
```
</details>
### Pylint
[Pylint](https://pylint.readthedocs.io/) 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
<details>
<summary>pylintrc</summary>
```ini
[format]
max-line-length = 88
```
</details>
<details>
<summary>setup.cfg</summary>
```ini
[pylint]
max-line-length = 88
```
</details>
<details>
<summary>pyproject.toml</summary>
```toml
[tool.pylint.format]
max-line-length = "88"
```
</details>
+136
View File
@@ -0,0 +1,136 @@
<!--
black documentation master file, created by
sphinx-quickstart on Fri Mar 23 10:53:30 2018.
-->
# The uncompromising code formatter
> “Any color you like.”
By using _Black_, 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.
_Black_ makes code review faster by producing the smallest diffs possible. 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.
```{admonition} Note - Black is now stable!
_Black_ is [successfully used](https://github.com/psf/black#used-by) by many projects,
small and big. _Black_ has a comprehensive test suite, with efficient parallel tests,
our own auto formatting and parallel Continuous Integration runner. Now that we have
become stable, you should not expect large changes to formatting in the future.
Stylistic changes will mostly be responses to bug reports and support for new Python
syntax.
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](./the_black_code_style/current_style.md#pragmatism)
section for details). If you're feeling confident, use `--fast`.
```
```{note}
{doc}`Black is licensed under the MIT license <license>`.
```
## Testimonials
**Mike Bayer**, creator of [`SQLAlchemy`](https://www.sqlalchemy.org/):
> _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](https://www.amazon.com/stores/Dusty-Phillips/author/B00HSYG5BO):
> _Black is opinionated so you don't have to be._
**Hynek Schlawack**, creator of [`attrs`](https://www.attrs.org/), core developer of
Twisted and CPython:
> _An auto-formatter that doesn't suck is all I want for Xmas!_
**Carl Meyer**, [Django](https://www.djangoproject.com/) core developer:
> _At least the name is good._
**Kenneth Reitz**, creator of [`requests`](https://requests.readthedocs.io/en/stable/)
and [pipenv](https://pipenv.pypa.io/en/stable/):
> _This vastly improves the formatting of our code. Thanks a ton!_
## Show your style
Use the badge in your project's README.md:
```md
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](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:
```{image} https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
```
## Contents
```{toctree}
---
maxdepth: 3
includehidden:
---
the_black_code_style/index
```
```{toctree}
---
maxdepth: 3
includehidden:
caption: User Guide
---
getting_started
usage_and_configuration/index
integrations/index
guides/index
faq
```
```{toctree}
---
maxdepth: 2
includehidden:
caption: Development
---
contributing/index
change_log
authors
```
```{toctree}
---
hidden:
caption: Project Links
---
GitHub <https://github.com/psf/black>
PyPI <https://pypi.org/project/black>
Chat <https://discord.gg/RtVdv86PrH>
```
# Indices and tables
- {ref}`genindex`
- {ref}`search`
+102
View File
@@ -0,0 +1,102 @@
# Doctest Formatting
While _Black_ makes some decisions about styling for docstrings, it does not make any
assumptions about the contents of documentation. Thus, executable Python code inside
docstrings or documentation files (e.g. doctests), will not be formatted by _Black_.
Listed below are tools that apply _Black_ formatting to code inside docstrings and
documentation files.
> Note: There are some observed inconsistencies between the below packages. Because of
> this, we hesitate to make any recommendations. Any installed packages are installed at
> your own risk. We also encourage anyone to contribute documentation for additional
> packages that apply _Black_ formatting to doctests.
## blacken-docs
[`blacken-docs`](https://github.com/adamchainz/blacken-docs) is primarily used to apply
_Black_ formatting to code in documentation files (e.g. `.rst`, `.md`, `.tex`).
`blacken-docs` supports the following:
- Python code blocks in Markdown, reStructuredText, and LaTeX files. Similar to
`blackdoc`, normal _Black_ formatting is applied, so doctests inside Python code
blocks will not be formatted.
````md
```python
print("Hello world!")
```
````
```rst
.. code-block:: python
print("Hello world!")
```
```latex
\begin{minted}{python}
print("Hello world!")
\end{minted}
```
- Doctests inside Pycon code blocks in Markdown and reStructuredText. The code blocks
may be included in a `.md` or `.rst` file, or inside a docstring in a Python file.
````md
```python
>>> print("Hello world!")
```
````
```rst
.. code-block:: pycon
>>> print("Hello world!")
```
````python
def add_one(n: int) -> int:
"""
Examples
--------
```pycon
>>> add_one(1) == 2
```
"""
return n + 1
````
## blackdoc
[`blackdoc`](https://blackdoc.readthedocs.io/en/stable) is primarily used to apply
_Black_ formatting to doctests in Python files. It will not format any file contents
that are otherwise covered by _Black_.
`blackdoc` supports the following:
- Doctests in Python files.
```python
def add_one(n: int) -> int:
"""
Examples
--------
>>> add_one(1) == 2
"""
return n + 1
```
- Python code blocks in Markdown or reStructuredText files. In these cases, normal
_Black_ formatting is applied, i.e., doctests inside Python code blocks will not be
formatted.
````md
```python
print("Hello world!")
```
````
```rst
.. code-block:: python
print("Hello world!")
```
+493
View File
@@ -0,0 +1,493 @@
# Editor integration
## Emacs
Options include the following:
- [emacs-python-black](https://github.com/wbolster/emacs-python-black)
- [Blacken](https://github.com/pythonic-emacs/blacken)
- [Elpy](https://elpy.readthedocs.io/en/stable/).
## 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.
1. As local server using the BlackConnect plugin. This option formats the fastest. It
spins up {doc}`Black's HTTP server </usage_and_configuration/black_as_a_server>`, to
avoid the startup cost on subsequent formats.
1. As external tool.
1. As file watcher.
### Built-in _Black_ integration
1. Install `black`.
```console
$ pip install black
```
1. 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]'
```
1. Install
[BlackConnect IntelliJ IDEs plugin](https://plugins.jetbrains.com/plugin/14321-blackconnect).
1. Open plugin configuration in PyCharm/IntelliJ IDEA
On macOS:
`PyCharm -> Preferences -> Tools -> BlackConnect`
On Windows / Linux / BSD:
`File -> Settings -> Tools -> BlackConnect`
1. In `Local Instance (shared between projects)` section:
1. Check `Start local blackd instance when plugin loads`.
1. Press the `Detect` button near `Path` input. The plugin should detect the `blackd`
executable.
1. In `Trigger Settings` section check `Trigger on code reformat` to enable code
reformatting with _Black_.
1. Format the currently opened file by selecting `Code -> Reformat Code` or using a
shortcut.
1. 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
```
1. 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`.
1. Open External tools in PyCharm/IntelliJ IDEA
On macOS:
`PyCharm -> Preferences -> Tools -> External Tools`
On Windows / Linux / BSD:
`File -> Settings -> Tools -> External Tools`
1. Click the + icon to add a new external tool with the following values:
- Name: Black
- Description: Black is the uncompromising Python code formatter.
- Program: \<install_location_from_step_2>
- Arguments: `"$FilePath$"`
1. 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
```
1. 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`.
1. Make sure you have the
[File Watchers](https://plugins.jetbrains.com/plugin/7177-file-watchers) plugin
installed.
1. Go to `Preferences or Settings -> Tools -> File Watchers` and click `+` to add a new
watcher:
- Name: Black
- File type: Python
- Scope: Project Files
- Program: \<install_location_from_step_2>
- 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](https://wingware.com/doc/edit/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`.
1. Set **Auto-Reformat** from `disable` (default) to `Line after edit` or
`Whole files before save`.
1. 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`.
1. Set **Auto-Reformat** from `Use Preferences setting` (default) to `Line after edit`
or `Whole files before save`.
1. 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](https://junegunn.github.io/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](../contributing/release_process.md) 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](https://github.com/VundleVim/Vundle.vim):
```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`](https://archlinux.org/packages/extra/any/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](https://github.com/psf/black/blob/stable/plugin/black.vim) and
[autoload/black.vim](https://github.com/psf/black/blob/stable/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`](https://github.com/dense-analysis/ale)
1. Install `black`
1. Add this to your vimrc:
```vim
let g:ale_fixers = {}
let g:ale_fixers.python = ['black']
```
## Neovim
### Via conform.nvim
[conform.nvim](https://github.com/stevearc/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`)
1. Install `conform.nvim` using your plugin manager and add the following to your Neovim
configuration:
```lua
require("conform").setup({
formatters_by_ft = {
python = { "black" },
},
})
```
1. 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](https://github.com/dense-analysis/ale) supports both Vim and Neovim. See the
[Vim section](#with-ale) 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`
1. Search for `external tools` and activate it.
1. In `Tools menu -> Manage external tools`
1. Add a new tool using `+` button.
1. 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
- Use the
[Python extension](https://marketplace.visualstudio.com/items?itemName=ms-python.python)
([instructions](https://code.visualstudio.com/docs/python/formatting)).
- Alternatively the pre-release
[Black Formatter](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter)
extension can be used which runs a [Language Server Protocol](https://langserver.org/)
server for Black. Formatting is much more responsive using this extension, **but the
minimum supported version of Black is 22.3.0**.
## SublimeText
Use [LSP](#python-lsp-server) with the
[python-lsp-black](https://github.com/python-lsp/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](https://langserver.org/) (Atom,
Sublime Text, Visual Studio Code and many more), you can use the
[Python LSP Server](https://github.com/python-lsp/python-lsp-server) with the
[python-lsp-black](https://github.com/python-lsp/python-lsp-black) plugin.
## Gradle (the build tool)
Use the [Spotless](https://plugins.gradle.org/plugin/com.diffplug.spotless) plugin.
## Kakoune
Add the following hook to your kakrc, then run _Black_ with `:format`.
```
hook global WinSetOption filetype=python %{
set-option window formatcmd 'black -q -'
}
```
## Thonny
Use [Thonny-black-formatter](https://github.com/ettore-galli/thonny-black-formatter).
+110
View File
@@ -0,0 +1,110 @@
# GitHub Actions integration
You can use _Black_ within a GitHub Actions workflow without setting your own Python
environment. Great for enforcing that your code matches the _Black_ code style.
## Compatibility
This action is known to support all GitHub-hosted runner OSes. In addition, only
published versions of _Black_ are supported (i.e. whatever is available on PyPI).
Finally, this action installs _Black_ with the `colorama` extra so the `--color` flag
should work fine.
## Usage
Create a file named `.github/workflows/black.yml` inside your repository with:
```yaml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: psf/black@stable
```
We recommend the use of the `@stable` tag, but per version tags also exist if you prefer
that. Note that the action's version you select is independent of the version of _Black_
the action will use.
### Versions
The version of _Black_ the action will use can be configured via `version` or read from
the `pyproject.toml` file. The action defaults to the latest release available on PyPI.
`version` can be any
[valid version specifier](https://packaging.python.org/en/latest/glossary/#term-Version-Specifier)
or just the version number if you want an exact version.
If you want to match versions covered by Black's
[stability policy](labels/stability-policy), you can use the compatible release operator
(`~=`):
```yaml
- uses: psf/black@stable
with:
options: "--check --verbose"
src: "./src"
version: "~= 26.0"
```
To read the version from the `pyproject.toml` file instead, set `use_pyproject` to
`true`. This will first look into the `tool.black.required-version` field, then the
`dependency-groups` table, then the `project.dependencies` array and finally the
`project.optional-dependencies` table. Note that this requires Python >= 3.11, so using
the setup-python action may be required, for example:
**Security note:** `use_pyproject` only accepts standard version specifiers for `black`
(for example `==`, `~=`, `>=` and ranges like `>=25,<26`). Direct references such as
`black @ https://...` are not supported. If your workflow runs on untrusted pull
requests (for example from forks), prefer setting `with.version` explicitly.
```yaml
- uses: actions/setup-python@v6
with:
python-version: "3.13"
- uses: psf/black@stable
with:
options: "--check --verbose"
src: "./src"
use_pyproject: true
```
Only versions available from PyPI are supported, so no commit SHAs or branch names.
### Jupyter Notebooks
If you want to include Jupyter Notebooks, it can be enabled by setting `jupyter` to
`true` (default is `false`):
```yaml
- uses: psf/black@stable
with:
jupyter: true
```
See the [Jupyter Notebooks guide](../guides/using_black_with_jupyter_notebooks.md) for
more details.
### CLI Options
You can also configure the arguments passed to _Black_ via `options` (defaults to
`'--check --diff'`) and `src` (default is `'.'`). Please note that the
[`--check` flag](labels/exit-code) is required so that the workflow fails if _Black_
finds files that need to be formatted.
Here's an example configuration:
```yaml
- uses: psf/black@stable
with:
options: "--check --verbose"
src: "./src"
jupyter: true
version: "21.5b1"
```
+33
View File
@@ -0,0 +1,33 @@
# Integrations
```{toctree}
---
hidden:
---
editors
github_actions
source_version_control
doctest_formatting
```
_Black_ can be integrated into many environments, providing a better and smoother
experience. Documentation for integrating _Black_ with a tool can be found for the
following areas:
- {doc}`Editor / IDE <./editors>`
- {doc}`GitHub Actions <./github_actions>`
- {doc}`Source version control <./source_version_control>`
- {doc}`Doctest formatting <./doctest_formatting>`
Editors and tools not listed will require external contributions.
Patches welcome! ✨ 🍰 ✨
Any tool can pipe code through _Black_ using its stdio mode (just
[use `-` as the file name](https://www.tldp.org/LDP/abs/html/special-chars.html#DASHREF2)).
The formatted code will be returned on stdout (unless `--check` was passed). _Black_
will still emit messages on stderr but that shouldn't affect your use case.
This can be used for example with PyCharm's or IntelliJ's
[File Watchers](https://www.jetbrains.com/help/pycharm/file-watchers.html).
+102
View File
@@ -0,0 +1,102 @@
# Version control integration
Use [pre-commit](https://pre-commit.com/). Once you
[have it installed](https://pre-commit.com/#install), add this to the
`.pre-commit-config.yaml` in your repository:
```yaml
repos:
# Using this mirror lets us use mypyc-compiled black, which is about 2x faster
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.5.1
hooks:
- id: black
# 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.11
```
Feel free to switch out the `rev` value to a different version of Black.
Note if you'd like to use a specific commit in `rev`, you'll need to swap the repo
specified from the mirror to https://github.com/psf/black. We discourage the use of
branches or other mutable refs since the hook [won't auto update as you may
expect][pre-commit-mutable-rev].
## Jupyter Notebooks
There is an alternate hook `black-jupyter` that expands the targets of `black` to
include Jupyter Notebooks. To use this hook, simply replace the hook's `id: black` with
`id: black-jupyter` in the `.pre-commit-config.yaml`:
```yaml
repos:
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.5.1
hooks:
- id: black-jupyter
language_version: python3.11
```
```{note}
The `black-jupyter` hook became available in version 21.8b0.
```
See the [Jupyter Notebooks guide](../guides/using_black_with_jupyter_notebooks.md) for
more details.
## Excluding files with pre-commit
When using pre-commit, there's an important distinction in how file exclusions work.
Pre-commit passes files directly to Black via the command line, rather than letting
Black discover files recursively. This means Black's `--exclude` option won't work as
expected because it only applies to files discovered during recursive directory
traversal.
To exclude files when using pre-commit, you have two options:
### Option 1: Use pre-commit's exclude (Recommended)
Configure exclusions directly in `.pre-commit-config.yaml`:
```yaml
repos:
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.5.1
hooks:
- id: black
exclude: ^migrations/|^generated/
```
This is the recommended approach because pre-commit filters files before passing them to
Black, avoiding unnecessary processing.
### Option 2: Use Black's force-exclude in pyproject.toml
Black's `force-exclude` configuration option excludes files even when they are passed
explicitly as command-line arguments (which is how pre-commit invokes Black). Simply add
the pattern to your `pyproject.toml`:
```toml
[tool.black]
force-exclude = '''
(
^migrations/
| ^generated/
)
'''
```
Black automatically reads this configuration—no additional CLI arguments are needed in
your `.pre-commit-config.yaml`.
```{note}
The `force-exclude` option was added in version 20.8b0 specifically to support
workflows where files are passed directly via CLI, such as pre-commit hooks and
editor plugins.
```
[pre-commit-mutable-rev]:
https://pre-commit.com/#using-the-latest-version-for-a-repository
+9
View File
@@ -0,0 +1,9 @@
---
orphan: true
---
# License
```{include} ../LICENSE
```
+36
View File
@@ -0,0 +1,36 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
set SPHINXPROJ=black
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end
popd
+505
View File
@@ -0,0 +1,505 @@
# The _Black_ code style
## Code style
_Black_ aims for consistency, generality, readability and reducing git diffs. Similar
language constructs are formatted with similar rules. Style configuration options are
deliberately limited and rarely added. Previous formatting is taken into account as
little as possible, with rare exceptions like the magic trailing comma. The coding style
used by _Black_ follows PEP 8 in spirit and enforces a consistent subset of its
formatting recommendations. It does not implement every style rule covered by PEP 8.
This document describes the current formatting style. If you're interested in trying out
where the style is heading, see [future style](./future_style.md) and try running
`black --preview`.
### How _Black_ wraps lines
_Black_ ignores previous formatting and applies uniform horizontal and vertical
whitespace to your code. The rules for horizontal whitespace can be summarized as: do
whatever makes `pycodestyle` happy.
As for vertical whitespace, _Black_ tries to render one full expression or simple
statement per line. If this fits the allotted line length, great.
```python
# in:
j = [1,
2,
3
]
# out:
j = [1, 2, 3]
```
If not, _Black_ will look at the contents of the first outer matching brackets and put
that in a separate indented line.
```python
# in:
ImportantClass.important_method(exc, limit, lookup_lines, capture_locals, extra_argument)
# out:
ImportantClass.important_method(
exc, limit, lookup_lines, capture_locals, extra_argument
)
```
If that still doesn't fit the bill, it will decompose the internal expression further
using the same rule, indenting matching brackets every time. If the contents of the
matching brackets pair are comma-separated (like an argument list, or a dict literal,
and so on) then _Black_ will first try to keep them on the same line with the matching
brackets. If that doesn't work, it will put all of them in separate lines.
```python
# in:
def very_important_function(template: str, *variables, file: os.PathLike, engine: str, header: bool = True, debug: bool = False):
"""Applies `variables` to the `template` and writes to `file`."""
with open(file, 'w') as f:
...
# out:
def very_important_function(
template: str,
*variables,
file: os.PathLike,
engine: str,
header: bool = True,
debug: bool = False,
):
"""Applies `variables` to the `template` and writes to `file`."""
with open(file, "w") as f:
...
```
If a data structure literal (tuple, list, set, dict) or a line of "from" imports cannot
fit in the allotted length, it's always split into one element per line. This minimizes
diffs as well as enables readers of code to find which commit introduced a particular
entry. This also makes _Black_ compatible with
[isort](../guides/using_black_with_other_tools.md#isort) with the ready-made `black`
profile or manual configuration.
You might have noticed that closing brackets are always dedented and that a trailing
comma is always added. Such formatting produces smaller diffs; when you add or remove an
element, it's always just one line. Also, having the closing bracket dedented provides a
clear delimiter between two distinct sections of the code that otherwise share the same
indentation level (like the arguments list and the docstring in the example above).
(labels/why-no-backslashes)=
_Black_ prefers parentheses over backslashes, and will remove backslashes if found.
```python
# in:
if some_short_rule1 \
and some_short_rule2:
...
# out:
if some_short_rule1 and some_short_rule2:
...
# in:
if some_long_rule1 \
and some_long_rule2:
...
# out:
if (
some_long_rule1
and some_long_rule2
):
...
```
Backslashes and multiline strings are one of the two places in the Python grammar that
break significant indentation. You never need backslashes, they are used to force the
grammar to accept breaks that would otherwise be parse errors. That makes them confusing
to look at and brittle to modify. This is why _Black_ always gets rid of them.
If you're reaching for backslashes, that's a clear signal that you can do better if you
slightly refactor your code. I hope some of the examples above show you that there are
many ways in which you can do it.
(labels/line-length)=
### Line length
You probably noticed the peculiar default line length. _Black_ defaults to 88 characters
per line, which happens to be 10% over 80. This number was found to produce
significantly shorter files than sticking with 80 (the most popular), or even 79 (used
by the standard library). In general,
[90-ish seems like the wise choice](https://youtu.be/wf-BqAjZb8M?t=260).
If you're paid by the lines of code you write, you can pass `--line-length` with a lower
number. _Black_ will try to respect that. However, sometimes it won't be able to without
breaking other rules. In those rare cases, auto-formatted code will exceed your allotted
limit.
You can also increase it, but remember that people with sight disabilities find it
harder to work with line lengths exceeding 100 characters. It also adversely affects
side-by-side diff review on typical screen resolutions. Long lines also make it harder
to present code neatly in documentation or talk slides.
#### Flake8 and other linters
See [Using _Black_ with other tools](../guides/using_black_with_other_tools.md) about
linter compatibility.
### Empty lines
_Black_ avoids spurious vertical whitespace. This is in the spirit of PEP 8 which says
that in-function vertical whitespace should only be used sparingly.
_Black_ will allow single empty lines inside functions, and single and double empty
lines on module level left by the original editors, except when they're within
parenthesized expressions. Since such expressions are always reformatted to fit minimal
space, this whitespace is lost.
```python
# in:
def function(
some_argument: int,
other_argument: int = 5,
) -> EmptyLineInParenWillBeDeleted:
print("One empty line above me will be kept!")
def this_is_okay_too():
print("No empty line here")
# out:
def function(
some_argument: int,
other_argument: int = 5,
) -> EmptyLineInParenWillBeDeleted:
print("One empty line above me will be kept!")
def this_is_okay_too():
print("No empty line here")
```
It will also insert proper spacing before and after function definitions. It's one line
before and after inner functions and two lines before and after module-level functions
and classes. _Black_ will not put empty lines between function/class definitions and
standalone comments that immediately precede the given function/class.
_Black_ will enforce single empty lines between a class-level docstring and the first
following field or method. This conforms to
[PEP 257](https://peps.python.org/pep-0257/#multi-line-docstrings).
_Black_ won't insert empty lines after function docstrings unless that empty line is
required due to an inner function starting immediately after.
### Comments
_Black_ does not format comment contents, but it enforces two spaces between code and a
comment on the same line, and a space before the comment text begins. Some types of
comments that require specific spacing rules are respected: shebangs (`#! comment`), doc
comments (`#: comment`), section comments with long runs of hashes, and Spyder cells.
Non-breaking spaces after hashes are also preserved. Comments may sometimes be moved
because of formatting changes, which can break tools that assign special meaning to
them. See [AST before and after formatting](#ast-before-and-after-formatting) for more
discussion.
### Trailing commas
_Black_ will add trailing commas to expressions that are split by comma where each
element is on its own line. This includes function signatures.
One exception to adding trailing commas is function signatures containing `*`, `*args`,
or `**kwargs`. In this case a trailing comma is only safe to use on Python 3.6. _Black_
will detect if your file is already 3.6+ only and use trailing commas in this situation.
If you wonder how it knows, it looks for f-strings and existing use of trailing commas
in function signatures that have stars in them. In other words, if you'd like a trailing
comma in this situation and _Black_ didn't recognize it was safe to do so, put it there
manually and _Black_ will keep it.
A pre-existing trailing comma informs _Black_ to always explode contents of the current
bracket pair into one item per line. Read more about this in the
[Pragmatism](#pragmatism) section below.
(labels/strings)=
### Strings
_Black_ prefers double quotes (`"` and `"""`) over single quotes (`'` and `'''`). It
will replace the latter with the former as long as it does not result in more backslash
escapes than before.
_Black_ also standardizes string prefixes. Prefix characters are made lowercase with the
exception of [capital "R" prefixes](#rstrings-and-rstrings), unicode literal markers
(`u`) are removed because they are meaningless in Python 3, and in the case of multiple
characters "r" is put first as in spoken language: "raw f-string".
Another area where Python allows multiple ways to format a string is escape sequences.
For example, `"\uabcd"` and `"\uABCD"` evaluate to the same string. _Black_ normalizes
such escape sequences to lowercase, but uses uppercase for `\N` named character escapes,
such as `"\N{MEETEI MAYEK LETTER HUK}"`.
The main reason to standardize on a single form of quotes is aesthetics. Having one kind
of quotes everywhere reduces reader distraction. It will also enable a future version of
_Black_ to merge consecutive string literals that ended up on the same line (see
[#26](https://github.com/psf/black/issues/26) for details).
Why settle on double quotes? They anticipate apostrophes in English text. They match the
docstring standard described in
[PEP 257](https://peps.python.org/pep-0257/#what-is-a-docstring). An empty string in
double quotes (`""`) is impossible to confuse with a one double-quote regardless of
fonts and syntax highlighting used. On top of this, double quotes for strings are
consistent with C which Python interacts a lot with.
On certain keyboard layouts like US English, typing single quotes is a bit easier than
double quotes. The latter requires use of the Shift key. My recommendation here is to
keep using whatever is faster to type and let _Black_ handle the transformation.
If you are adopting _Black_ in a large project with pre-existing string conventions
(like the popular
["single quotes for data, double quotes for human-readable strings"](https://stackoverflow.com/a/56190)),
you can pass `--skip-string-normalization` on the command line. This is meant as an
adoption helper, avoid using this for new projects.
_Black_ also processes docstrings. Firstly the indentation of docstrings is corrected
for both quotations and the text within, although relative indentation in the text is
preserved. Superfluous trailing whitespace on each line and unnecessary new lines at the
end of the docstring are removed. All leading tabs are converted to spaces, but tabs
inside text are preserved. Whitespace leading and trailing one-line docstrings is
removed.
### Numeric literals
_Black_ standardizes most numeric literals to use lowercase letters for the syntactic
parts and uppercase letters for the digits themselves: `0xAB` instead of `0XAB` and
`1e10` instead of `1E10`.
### Line breaks & binary operators
_Black_ will break a line before a binary operator when splitting a block of code over
multiple lines. This is so that _Black_ is compliant with the recent changes in the
[PEP 8](https://peps.python.org/pep-0008/#should-a-line-break-before-or-after-a-binary-operator)
style guide, which emphasizes that this approach improves readability.
Almost all operators will be surrounded by single spaces, the only exceptions are unary
operators (`+`, `-`, and `~`), and power operators when both operands are simple. For
powers, an operand is considered simple if it's only a NAME, numeric CONSTANT, or
attribute access (chained attribute access is allowed), with or without a preceding
unary operator.
```python
# For example, these won't be surrounded by whitespace
a = x**y
b = config.base**5.2
c = config.base**runtime.config.exponent
d = 2**5
e = 2**~5
# ... but these will be surrounded by whitespace
f = 2 ** get_exponent()
g = get_x() ** get_y()
h = config['base'] ** 2
```
### Slices
PEP 8
[recommends](https://peps.python.org/pep-0008/#whitespace-in-expressions-and-statements)
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.
### Parentheses
Some parentheses are optional in the Python grammar. Any expression can be wrapped in a
pair of parentheses to form an atom. There are a few interesting cases:
- `if (...):`
- `while (...):`
- `for (...) in (...):`
- `assert (...), (...)`
- `from X import (...)`
- assignments like:
- `target = (...)`
- `target: type = (...)`
- `some, *un, packing = (...)`
- `augmented += (...)`
In those cases, parentheses are removed when the entire statement fits in one line, or
if the inner expression doesn't have any delimiters to further split on. If there is
only a single delimiter and the expression starts or ends with a bracket, the
parentheses can also be successfully omitted since the existing bracket pair will
organize the expression neatly anyway. Otherwise, the parentheses are added.
Please note that _Black_ does not add or remove any additional nested parentheses that
you might want to have for clarity or further code organization. For example those
parentheses are not going to be removed:
```python
return not (this or that)
decision = (maybe.this() and values > 0) or (maybe.that() and values < 0)
```
### Call chains
Some popular APIs, like ORMs, use call chaining. This API style is known as a
[fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). _Black_ formats
those by treating dots that follow a call or an indexing operation like a very low
priority delimiter. It's easier to show the behavior than to explain it. Look at the
example:
```python
def example(session):
result = (
session.query(models.Customer.id)
.filter(
models.Customer.account_id == account_id,
models.Customer.email == email_address,
)
.order_by(models.Customer.id.asc())
.all()
)
```
### Typing stub files
PEP 484 describes the syntax for type hints in Python. One of the use cases for typing
is providing type annotations for modules which cannot contain them directly (they might
be written in C, or they might be third-party, or their implementation may be overly
dynamic, and so on).
To solve this,
[stub files with the `.pyi` file extension](https://peps.python.org/pep-0484/#stub-files)
can be used to describe typing information for an external module. Those stub files omit
the implementation of classes and functions they describe, instead they only contain the
structure of the file (listing globals, functions, and classes with their members). The
recommended code style for those files is more terse than PEP 8:
- prefer `...` on the same line as the class/function signature;
- avoid vertical whitespace between consecutive module-level functions, names, or
methods and fields within a single class;
- use a single blank line between top-level class definitions, or none if the classes
are very small.
_Black_ enforces the above rules. There are additional guidelines for formatting `.pyi`
file that are not enforced yet but might be in a future version of the formatter:
- prefer `...` over `pass`;
- avoid using string literals in type annotations, stub files support forward references
natively (like Python 3.7 code with `from __future__ import annotations`);
- use variable annotations instead of type comments, even for stubs that target older
versions of Python.
### Line endings
_Black_ will normalize line endings (`\n` or `\r\n`) based on the first line ending of
the file.
### Form feed characters
_Black_ will retain form feed characters on otherwise empty lines at the module level.
Only one form feed is retained for a group of consecutive empty lines. Where there are
two empty lines in a row, the form feed is placed on the second line.
## 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. This section documents
what those exceptions are and why this is the case.
(labels/magic-trailing-comma)=
### The magic trailing comma
_Black_ in general does not take existing formatting into account.
However, there are cases where you put a short collection or function call in your code
but you anticipate it will grow in the future.
For example:
```python
TRANSLATIONS = {
"en_us": "English (US)",
"pl_pl": "polski",
}
```
Early versions of _Black_ used to ruthlessly collapse those into one line (it fits!).
Now, you can communicate that you don't want that by putting a trailing comma in the
collection yourself. When you do, _Black_ will know to always explode your collection
into one item per line.
How do you make it stop? Just delete that trailing comma and _Black_ will collapse your
collection into one line if it fits.
If you must, you can recover the behaviour of early versions of _Black_ with the option
`--skip-magic-trailing-comma` / `-C`.
### r"strings" and R"strings"
_Black_ normalizes string quotes as well as string prefixes, making them lowercase. One
exception to this rule is r-strings. It turns out that the very popular
[MagicPython](https://github.com/MagicStack/MagicPython/) syntax highlighter, used by
default by (among others) GitHub and Visual Studio Code, differentiates between
r-strings and R-strings. The former are syntax highlighted as regular expressions while
the latter are treated as true raw strings with no special semantics.
(labels/ast-changes)=
### AST before and after formatting
When run with `--safe` (the default), _Black_ checks that the code before and after is
semantically equivalent. This check is done by comparing the AST of the source with the
AST of the target. There are three limited cases in which the AST does differ:
1. _Black_ cleans up leading and trailing whitespace of docstrings, re-indenting them if
needed. It's been one of the most popular user-reported features for the formatter to
fix whitespace issues with docstrings. While the result is technically an AST
difference, due to the various possibilities of forming docstrings, all real-world
uses of docstrings that we're aware of sanitize indentation and leading/trailing
whitespace anyway.
1. _Black_ manages optional parentheses for some statements. In the case of the `del`
statement, presence of wrapping parentheses or lack thereof changes the resulting AST
but is semantically equivalent in the interpreter.
1. _Black_ might move comments around, which includes type comments. Those are part of
the AST as of Python 3.8. While the tool implements a number of special cases for
those comments, there is no guarantee they will remain where they were in the source.
Note that this doesn't change runtime behavior of the source code.
To put things in perspective, the code equivalence check is a feature of _Black_ which
other formatters don't implement at all. It is of crucial importance to us to ensure
code behaves the way it did before it got reformatted. We treat this as a feature and
there are no plans to relax this in the future. The exceptions enumerated above stem
from either user feedback or implementation details of the tool. In each case we made
due diligence to ensure that the AST divergence is of no practical consequence.
+500
View File
@@ -0,0 +1,500 @@
# The (future of the) Black code style
## Preview style
(labels/preview-style)=
Experimental, potentially disruptive style changes are gathered under the `--preview`
CLI flag. At the end of each year, these changes may be adopted into the default style,
as described in [The Black Code Style](index.md). Because the functionality is
experimental, feedback and issue reports are highly encouraged!
(labels/preview-features)=
Currently, the following features are included in the preview style:
- `wrap_comprehension_in`: Wrap the `in` clause of list and dictionary comprehensions
across lines if it would otherwise exceed the maximum line length.
([see below](labels/wrap-comprehension-in))
- `simplify_power_operator_hugging`: Use a simpler implementation of the power operator
"hugging" logic (removing whitespace around `**` in simple expressions), which applies
also in the rare case the exponentiation is split into separate lines.
([see below](labels/simplify-power-operator))
- `wrap_long_dict_values_in_parens`: Add parentheses around long values in dictionaries.
([see below](labels/wrap-long-dict-values))
- `fix_if_guard_explosion_in_case_statement`: fixed exploding of the if guard in case
patterns which have trailing commas in them, even if the guard expression fits in one
line
- `pyi_overload_group_blank_lines`: In `.pyi` stub files, improve heuristics around when
blank lines should appear before, after and within decorated function groups.
([see below](labels/pyi-overload-group))
- `pyi_blank_line_before_decorated_class`: In `.pyi` stub files, enforce a blank line
before a decorated class definition when it follows a function definition.
([see below](labels/pyi-blank-line-before-decorated-class))
- `fix_unnecessary_parens_in_indexed_assignment`: Remove unnecessary parentheses around
the right-hand side of indexed assignments (e.g. `x[key] = expr`) when the subscripted
target is too long to fit on one line and the expression fits on the tail line.
([see below](labels/fix-unnecessary-parens-indexed-assignment))
- `pyi_blank_line_after_function_docstring`: In `.pyi` stub files, enforce a blank line
after a function or method body that consists of a docstring.
([see below](labels/pyi-blank-line-after-function-docstring))
- `hug_comparator`: Don't break a comparator (`not in`, `==`, `is`, ...) away from its
left operand when the right operand is a bracketed expression that has to break
anyway; let the bracket explode instead. ([see below](labels/hug-comparator))
- `parenthesize_tuple_in_yield`: Add parentheses around tuple expressions in `yield`
statements.
(labels/wrap-comprehension-in)=
### Wrapping long comprehension `in` clauses
When a list or dictionary comprehension has a long `in` clause that would exceed the
maximum line length, Black will wrap it across multiple lines for better readability.
This helps keep comprehensions readable when the iterable expression is complex or
lengthy.
For example:
```python
# Before
result = [
very_very_very_very_very_long_item
for very_very_very_very_very_long_item in some_very_very_very_very_very_very_long_function_name
]
```
will be formatted to:
```python
# After
result = [
very_very_very_very_very_long_item
for very_very_very_very_very_long_item in (
some_very_very_very_very_very_very_long_function_name
)
]
```
This also applies to dictionary comprehensions:
```python
# Before
mapping = {
very_long_key: very_very_very_long_item
for very_long_key, very_very_very_long_item in very_very_very_very_long_function_name
}
```
will be formatted to:
```python
# After
mapping = {
very_long_key: very_very_very_long_item
for very_long_key, very_very_very_long_item in (
very_very_very_very_long_function_name
)
}
```
(labels/simplify-power-operator)=
### Simplified power operator whitespace handling
Black's power operator "hugging" logic removes whitespace around `**` in simple
expressions (e.g., `x**2` instead of `x ** 2`). This feature uses a simpler, more
consistent implementation that also applies when exponentiation is split across lines.
For example:
```python
# Simple expressions - whitespace is removed
result = x**2 + y**3
value = base**exponent
```
When the exponentiation is split across lines (rare), the simplified logic ensures
consistent formatting:
```python
# Complex expression split across lines
result = (
some_very_long_base_expression
**some_very_long_exponent_expression
**some_very_long_third_expression
)
```
This feature primarily improves the internal consistency of Black's formatting logic
rather than making dramatic visual changes to most code.
(labels/wrap-long-dict-values)=
### Improved parentheses management in dicts
For dict literals with long values, they are now wrapped in parentheses. Unnecessary
parentheses are now removed. For example:
```python
my_dict = {
"a key in my dict": a_very_long_variable
* and_a_very_long_function_call()
/ 100000.0,
"another key": (short_value),
}
```
will be changed to:
```python
my_dict = {
"a key in my dict": (
a_very_long_variable * and_a_very_long_function_call() / 100000.0
),
"another key": short_value,
}
```
(labels/pyi-overload-group)=
### Improved overload groups in stub files
In `.pyi` stub files, Black now has improved heuristics regarding when blank lines
should appear before, after or within groups of decorated functions that share the same
name (such as `@overload` groups). Two rules are applied when a decorated function is
determined to be part of a series of >=2 decorated functions with the same name:
1. **Before the decorated function**: a blank line is always inserted, unless the
preceding statement is a same-name decorated function (i.e. part of an `@overload`
group) or the function is the first statement in its block.
2. **After the decorated function**: a blank line is always inserted, unless the
following statement is a same-name decorated function.
These rules apply regardless of what the adjacent statement is — whether it's another
function definition, a variable annotation, or any other statement.
Previously, Black could insert unwanted blank lines _within_ an overload group when one
of the overloads had a docstring, and did not consistently enforce blank lines at the
boundaries of overload groups:
```python
# Before
@overload
def foo(x: int) -> int:
"""Docs."""
@overload # unwanted blank line within group
def foo(x: str) -> str: ...
def bar(x): ... # no blank line after group
```
With this feature enabled, the group is kept together and clearly separated from
surrounding code:
```python
# After (with --preview)
@overload
def foo(x: int) -> int:
"""Docs."""
@overload
def foo(x: str) -> str: ...
def bar(x): ...
```
(labels/pyi-blank-line-before-decorated-class)=
### Blank line before decorated classes in stub files
In `.pyi` stub files, Black already enforces blank lines around class definitions in
many situations. However, when a class has a decorator, Black previously failed to
enforce this, instead _removing_ the blank line between a function and the decorator:
```diff
# Before
def foo(): ...
-
@decorator
class Bar: ...
def baz(): ...
@decorator
class Spam: ...
```
With this feature enabled, a blank line is enforced, consistent with how undecorated
classes are handled:
```diff
# After (with --preview)
def foo(): ...
@decorator
class Bar: ...
def baz(): ...
+
@decorator
class Spam: ...
```
(labels/fix-unnecessary-parens-indexed-assignment)=
### Unnecessary parentheses in indexed assignments
When an assignment target ends with a subscript (e.g. `x[key] = expr`) and is too long
to fit on one line, Black has to split at the subscript's brackets. Previously it would
additionally wrap the right-hand side expression in parentheses, even when the
expression fits on the closing line. With this feature enabled, Black omits those
unnecessary parentheses.
For example:
```python
# Before
dictionary_of_arrays["long_key_name_for_the_example"][
very_long_index_name, index_zero
] = (10 - 5)
```
will be formatted to:
```python
# After (with --preview)
dictionary_of_arrays["long_key_name_for_the_example"][
very_long_index_name, index_zero
] = 10 - 5
```
Assignments whose target fits on one line are not affected: wrapping the right-hand side
in parentheses remains the preferred style there.
(labels/pyi-blank-line-after-function-docstring)=
### Blank line after function docstrings in stub files
In `.pyi` stub files, functions and methods sometimes use a docstring as their whole
body. Black already separated these definitions from a following function definition,
but did not consistently do the same before a following comment, conditional block,
variable annotation, or other statement:
```python
# Before
class Example:
def method(self) -> None:
"""Documentation."""
# comment for the next member
attr: int
```
With this feature enabled, the docstring-only function body is consistently separated
from the next comment or statement:
```python
# After (with --preview)
class Example:
def method(self) -> None:
"""Documentation."""
# comment for the next member
attr: int
```
Black still keeps same-name decorated functions, such as `@overload` groups and property
setters, together without inserting blank lines between them.
(labels/hug-comparator)=
### Keep comparators next to their left operand
When a comparator (`not in`, `==`, `is`, ...) sits inside another bracketed construct
and its right operand is a bracketed expression that has to break (either via a magic
trailing comma or because the line is too long), Black used to split the line right
before the comparator. The left operand ended up alone on its own line, visually
disconnected from the operator and the operand that explains it:
```python
# Before
x = [
t
for t in y
if t
not in {
LongNameOne,
LongNameTwo,
LongNameThree,
}
]
```
With this feature enabled, Black skips that comparator split and lets the right-hand
bracket explode instead, which it would have done anyway:
```python
# After (with --preview)
x = [
t
for t in y
if t not in {
LongNameOne,
LongNameTwo,
LongNameThree,
}
]
```
The fix is not limited to comprehensions. The same shape appears inside `if`/`elif`
chains, `assert` statements, and parenthesized expressions, and gets the same treatment:
```python
# Before
if (
is_scalar(value)
and self.dtype
in (np.dtype("float64"), np.dtype("float32"), np.dtype("object"))
and (limit is not None or inplace)
):
...
assert (
bool
is _AnnotationExtractor(attr.fields(C).x.converter.__call__).get_return_type()
)
```
```python
# After (with --preview)
if (
is_scalar(value)
and self.dtype in (
np.dtype("float64"),
np.dtype("float32"),
np.dtype("object"),
)
and (limit is not None or inplace)
):
...
assert (
bool is _AnnotationExtractor(
attr.fields(C).x.converter.__call__
).get_return_type()
)
```
## Unstable style
(labels/unstable-style)=
In the past, the preview style included some features with known bugs, so that we were
unable to move these features to the stable style. Therefore, such features are now
moved to the `--unstable` style. All features in the `--preview` style are expected to
make it to next year's stable style; features in the `--unstable` style will be
stabilized only if issues with them are fixed. If bugs are discovered in a `--preview`
feature, it is demoted to the `--unstable` style. To avoid thrash when a feature is
demoted from the `--preview` to the `--unstable` style, users can use the
`--enable-unstable-feature` flag to enable specific unstable features.
(labels/unstable-features)=
The unstable style additionally includes the following features:
- `hug_parens_with_braces_and_square_brackets`: More compact formatting of nested
brackets. ([see below](labels/hug-parens))
- `string_processing`: Split long string literals and related changes.
([see below](labels/string-processing))
(labels/hug-parens)=
### Improved multiline dictionary and list indentation for sole function parameter
For better readability and less verticality, _Black_ now pairs parentheses ("(", ")")
with braces ("{", "}") and square brackets ("[", "]") on the same line. For example:
```python
foo(
[
1,
2,
3,
]
)
nested_array = [
[
1,
2,
3,
]
]
```
will be changed to:
```python
foo([
1,
2,
3,
])
nested_array = [[
1,
2,
3,
]]
```
This also applies to list and dictionary unpacking:
```python
foo(
*[
a_long_function_name(a_long_variable_name)
for a_long_variable_name in some_generator
]
)
```
will become:
```python
foo(*[
a_long_function_name(a_long_variable_name)
for a_long_variable_name in some_generator
])
```
You can use a magic trailing comma to avoid this compacting behavior; by default,
_Black_ will not reformat the following code:
```python
foo(
[
1,
2,
3,
],
)
```
(labels/string-processing)=
### Improved string processing
_Black_ will split long string literals and merge short ones. Parentheses are used where
appropriate. When split, parts of f-strings that don't need formatting are converted to
plain strings. f-strings will not be merged if they contain internal quotes and it would
change their quotation mark style. Line continuation backslashes are converted into
parenthesized strings. Unnecessary parentheses are stripped. The stability and status of
this feature is tracked in [this issue](https://github.com/psf/black/issues/2188).
+54
View File
@@ -0,0 +1,54 @@
# The Black Code Style
```{toctree}
---
hidden:
---
Current style <current_style>
Future style <future_style>
```
_Black_ is a PEP 8 compliant opinionated formatter with its own style.
While keeping the style unchanged throughout releases has always been a goal, the
_Black_ code style isn't set in stone. It evolves to accommodate for new features in the
Python language and, occasionally, in response to user feedback. Large-scale style
preferences presented in {doc}`current_style` are very unlikely to change, but minor
style aspects and details might change according to the stability policy presented
below. Ongoing style considerations are tracked on GitHub with the
[style](https://github.com/psf/black/labels/T%3A%20style) issue label.
(labels/stability-policy)=
## Stability Policy
The following policy applies for the _Black_ code style, in non pre-release versions of
_Black_:
- If code has been formatted with _Black_, it will remain unchanged when formatted with
the same options using any other release in the same calendar year.
This means projects can safely use `black ~= 26.0` without worrying about formatting
changes disrupting their project in 2026. We may still fix bugs where _Black_ crashes
on some code, and make other improvements that do not affect formatting.
In rare cases, we may make changes affecting code that has not been previously
formatted with _Black_. For example, we have had bugs where we accidentally removed
some comments. Such bugs can be fixed without breaking the stability policy.
- The first release in a new calendar year _may_ contain formatting changes, although
these will be minimised as much as possible. This is to allow for improved formatting
enabled by newer Python language syntax as well as due to improvements in the
formatting logic.
- The `--preview` and `--unstable` flags are exempt from this policy. There are no
guarantees around the stability of the output with these flags passed into _Black_.
They are intended for allowing experimentation with proposed changes to the _Black_
code style. The `--preview` style at the end of a year should closely match the stable
style for the next year, but we may always make changes.
Documentation for both the current and future styles can be found:
- {doc}`current_style`
- {doc}`future_style`
@@ -0,0 +1,116 @@
# Black as a server (blackd)
`blackd` is a small HTTP server that exposes _Black_'s functionality over a simple
protocol. The main benefit of using it is to avoid the cost of starting up a new _Black_
process every time you want to blacken a file.
```{warning}
`blackd` should not be run as a publicly accessible server as there are no security
precautions in place to prevent abuse. **It is intended for local use only**.
```
## Usage
`blackd` is not packaged alongside _Black_ by default because it has additional
dependencies. You will need to execute `pip install 'black[d]'` to install it.
You can start the server on the default port, binding only to the local interface by
running `blackd`. You will see a single line mentioning the server's version, and the
host and port it's listening on. `blackd` will then print an access log similar to most
web servers on standard output, merged with any exception traces caused by invalid
formatting requests.
`blackd` provides even less options than _Black_. You can see them by running
`blackd --help`:
```{program-output} blackd --help
```
You can test that blackd is working using `curl`:
```sh
blackd --bind-port 9090 & # or let blackd choose a port
curl -s -XPOST "localhost:9090" -d "print('valid')"
```
Or using the python client:
```python
import asyncio
from blackd.client import BlackDClient
async def main():
client = BlackDClient(url="http://127.0.0.1:9090")
unformatted_code = "def hello(): print('Hello, World!')"
formatted_code = await client.format_code(unformatted_code)
print(formatted_code)
if __name__ == "__main__":
asyncio.run(main())
```
Cross-origin browser requests are rejected by default. If you need to access `blackd`
from a browser-based client, pass one or more `--cors-allow-origin` options to allow
specific origins.
## Protocol
`blackd` only accepts `POST` requests at the `/` path. The body of the request should
contain the python source code to be formatted, encoded according to the `charset` field
in the `Content-Type` request header. If no `charset` is specified, `blackd` assumes
`UTF-8`. Request bodies are limited to 5 MiB by default; use `--max-body-size` to change
that limit.
There are a few HTTP headers that control how the source code is formatted. These
correspond to command line flags for _Black_. There is one exception to this:
`X-Protocol-Version` which if present, should have the value `1`, otherwise the request
is rejected with `HTTP 501` (Not Implemented).
The headers controlling how source code is formatted are:
- `X-Line-Length`: corresponds to the `--line-length` command line flag.
- `X-Skip-Source-First-Line`: corresponds to the `--skip-source-first-line` command line
flag. If present and its value is not an empty string, the first line of the source
code will be ignored.
- `X-Skip-String-Normalization`: corresponds to the `--skip-string-normalization`
command line flag. If present and its value is not the empty string, no string
normalization will be performed.
- `X-Skip-Magic-Trailing-Comma`: corresponds to the `--skip-magic-trailing-comma`
command line flag. If present and its value is not an empty string, trailing commas
will not be used as a reason to split lines.
- `X-Preview`: corresponds to the `--preview` command line flag. If present and its
value is not an empty string, experimental and potentially disruptive style changes
will be used.
- `X-Unstable`: corresponds to the `--unstable` command line flag. If present and its
value is not an empty string, experimental style changes that are known to be buggy
will be used.
- `X-Enable-Unstable-Feature`: corresponds to the `--enable-unstable-feature` flag. The
contents of the flag must be a comma-separated list of unstable features to be
enabled. Example: `X-Enable-Unstable-Feature: feature1, feature2`.
- `X-Fast-Or-Safe`: if set to `fast`, `blackd` will act as _Black_ does when passed the
`--fast` command line flag.
- `X-Python-Variant`: if set to `pyi`, `blackd` will act as _Black_ does when passed the
`--pyi` command line flag. Otherwise, its value must correspond to a Python version or
a set of comma-separated Python versions, optionally prefixed with `py`. For example,
to request code that is compatible with Python 3.5 and 3.6, set the header to
`py3.5,py3.6`.
- `X-Diff`: corresponds to the `--diff` command line flag. If present, a diff of the
formats will be output.
If any of these headers are set to invalid values, `blackd` returns a `HTTP 400` error
response, mentioning the name of the problematic header in the message body.
Apart from the above, `blackd` can produce the following response codes:
- `HTTP 204`: If the input is already well-formatted. The response body is empty.
- `HTTP 200`: If formatting was needed on the input. The response body contains the
blackened Python code, and the `Content-Type` header is set accordingly.
- `HTTP 400`: If the input contains a syntax error. Details of the error are returned in
the response body.
- `HTTP 500`: If there was any other kind of error while trying to format the input. The
response body contains a textual representation of the error.
The response headers include a `X-Black-Version` header containing the version of
_Black_.
@@ -0,0 +1,53 @@
# Black Docker image
Official _Black_ Docker images are available on
[Docker Hub](https://hub.docker.com/r/pyfound/black).
_Black_ images with the following tags are available:
- release numbers, e.g. `21.5b2`, `21.6b0`, `21.7b0` etc.\
Recommended for users who want to use a particular version of _Black_.
- `latest_release` - tag created when a new version of _Black_ is released.\
Recommended for users who want to use released versions of _Black_. It maps to
[the latest release](https://github.com/psf/black/releases/latest) of _Black_.
- `latest_prerelease` - tag created when a new alpha (prerelease) version of _Black_ is
released.\
Recommended for users who want to preview or test alpha versions of _Black_. Note
that the most recent release may be newer than any prerelease, because no prereleases
are created before most releases.
- `latest` - tag used for the newest image of _Black_.\
Recommended for users who always want to use the latest version of _Black_, even
before it is released.
There is one more tag used for _Black_ Docker images - `latest_non_release`. It is
created for all unreleased
[commits on the `main` branch](https://github.com/psf/black/commits/main). This tag is
not meant to be used by external users.
From version 23.11.0 the Docker image installs a compiled black into the image.
## Usage
A permanent container doesn't have to be created to use _Black_ as a Docker image. It's
enough to run _Black_ commands for the chosen image denoted as `:tag`. In the below
examples, the `latest_release` tag is used. If `:tag` is omitted, the `latest` tag will
be used.
More about _Black_ usage can be found in
[Usage and Configuration: The basics](./the_basics.md).
### Check Black version
```console
$ docker run --rm pyfound/black:latest_release black --version
```
### Check code
```console
$ docker run --rm --volume $(pwd):/src --workdir /src pyfound/black:latest_release black --check .
```
_Remark_: besides [regular _Black_ exit codes](./the_basics.md) returned by `--check`
option, [Docker exit codes](https://docs.docker.com/engine/reference/run/#exit-status)
should also be considered.
@@ -0,0 +1,49 @@
# File collection and discovery
You can directly pass _Black_ files, but you can also pass directories and _Black_ will
walk them, collecting files to format. It determines what files to format or skip
automatically using the inclusion and exclusion regexes and as well their modification
time.
## Ignoring unmodified files
_Black_ remembers files it has already formatted, unless the `--diff` flag is used or
code is passed via standard input. This information is stored per-user. The exact
location of the file depends on the _Black_ version and the system on which _Black_ is
run. The file is non-portable. The standard location on common operating systems is:
- Windows:
`C:\Users\<username>\AppData\Local\black\black\Cache\<version>\cache.<line-length>.<file-mode>.pickle`
- macOS:
`/Users/<username>/Library/Caches/black/<version>/cache.<line-length>.<file-mode>.pickle`
- Linux:
`/home/<username>/.cache/black/<version>/cache.<line-length>.<file-mode>.pickle`
`file-mode` is an int flag that determines whether the file was formatted as 3.6+ only,
as .pyi, and whether string normalization was omitted.
To override the location of these files on all systems, set the environment variable
`BLACK_CACHE_DIR` to the preferred location. Alternatively on macOS and Linux, set
`XDG_CACHE_HOME` to your preferred location. For example, if you want to put the cache
in the directory you're running _Black_ from, set `BLACK_CACHE_DIR=.cache/black`.
_Black_ will then write the above files to `.cache/black`. Note that `BLACK_CACHE_DIR`
will take precedence over `XDG_CACHE_HOME` if both are set.
### Disabling the cache with --no-cache
If you need Black to always perform a fresh analysis and not consult or update the
on-disk cache, use the `--no-cache` flag. When provided, Black will neither read from
nor write to the per-user cache. This is useful for debugging, for CI runs where you
want a deterministic fresh run, or when you suspect cache corruption.
Example:
python -m black --no-cache .
## .gitignore
If `--exclude` is not set, _Black_ will automatically ignore files and directories in
`.gitignore` file(s), if present.
If you want _Black_ to continue using `.gitignore` while also configuring the exclusion
rules, please use `--extend-exclude`.
+28
View File
@@ -0,0 +1,28 @@
# Usage and Configuration
```{toctree}
---
hidden:
---
the_basics
file_collection_and_discovery
black_as_a_server
black_docker_image
```
Sometimes, running _Black_ with its defaults and passing filepaths to it just won't cut
it. Passing each file using paths will become burdensome, and maybe you would like
_Black_ to not touch your files and just output diffs. And yes, you _can_ tweak certain
parts of _Black_'s style, but please know that configurability in this area is
purposefully limited.
Using many of these more advanced features of _Black_ will require some configuration.
Configuration that will either live on the command line or in a TOML configuration file.
This section covers features of _Black_ and configuring _Black_ in detail:
- {doc}`The basics <./the_basics>`
- {doc}`File collection and discovery <file_collection_and_discovery>`
- {doc}`Black as a server (blackd) <./black_as_a_server>`
- {doc}`Black Docker image <./black_docker_image>`
+604
View File
@@ -0,0 +1,604 @@
# The basics
Foundational knowledge on using and configuring Black.
_Black_ is a well-behaved Unix-style command-line tool:
- it does nothing if it finds no sources to format;
- it will read from standard input and write to standard output if `-` is used as the
filename;
- it only outputs messages to users on standard error;
- exits with code 0 unless an internal error occurred or a CLI option prompted it.
## Usage
_Black_ will reformat entire files in place. 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}
```
### Ignoring sections
Black will not reformat lines that contain `# fmt: skip` or blocks that start with
`# fmt: off` and end with `# fmt: on`. `# fmt: skip` can be mixed with other
pragmas/comments either with multiple comments (e.g. `# fmt: skip # pylint # noqa`) or
as a semicolon separated list (e.g. `# fmt: skip; pylint; noqa`). `# fmt: on/off` must
be on the same level of indentation and in the same block, meaning no unindents beyond
the initial indentation level between them. Black also recognizes
[YAPF](https://github.com/google/yapf)'s block comments to the same effect, as a
courtesy for straddling code.
### Command line options
The CLI options of _Black_ can be displayed by running `black --help`. All options are
also covered in more detail below.
While _Black_ has quite a few knobs these days, it is still opinionated so style options
are deliberately limited and rarely added.
Note that all command-line options listed above can also be configured using a
`pyproject.toml` file (more on that below).
#### `-h`, `--help`
Show available command-line options and exit.
#### `-c`, `--code`
Format the code passed in as a string.
```console
$ black --code "print ( 'hello, world' )"
print("hello, world")
```
#### `-l`, `--line-length`
How many characters per line to allow. The default is 88.
See also [the style documentation](labels/line-length).
#### `-t`, `--target-version`
Python versions that should be supported by Black's output. You can run `black --help`
and look for the `--target-version` option to see the full list of supported versions.
You should include all versions that your code supports. If you support Python 3.11
through 3.13, you should write:
```console
$ black -t py311 -t py312 -t py313
```
In a [configuration file](#configuration-via-a-file), you can write:
```toml
target-version = ["py311", "py312", "py313"]
```
By default, Black will infer target versions from the project metadata in
`pyproject.toml`, specifically the `[project.requires-python]` field. If this does not
yield conclusive results, Black will use per-file auto-detection.
_Black_ uses this option to decide what grammar to use to parse your code. In addition,
it may use it to decide what style to use. For example, support for a trailing comma
after `*args` in a function call was added in Python 3.5, so _Black_ will add this comma
only if the target versions are all Python 3.5 or higher:
```console
$ black --line-length=10 --target-version=py35 -c 'f(a, *args)'
f(
a,
*args,
)
$ black --line-length=10 --target-version=py34 -c 'f(a, *args)'
f(
a,
*args
)
$ black --line-length=10 --target-version=py34 --target-version=py35 -c 'f(a, *args)'
f(
a,
*args
)
```
#### `--pyi`
Format all input files like typing stubs regardless of file extension. This is useful
when piping source on standard input.
#### `--ipynb`
Format all input files like Jupyter Notebooks regardless of file extension. This is
useful when piping source on standard input.
#### `--python-cell-magics`
When processing Jupyter Notebooks, add the given magic to the list of known python-
magics. Useful for formatting cells with custom python magics. See the
[Jupyter Notebooks guide](../guides/using_black_with_jupyter_notebooks.md) for more
details.
#### `-x, --skip-source-first-line`
Skip the first line of the source code.
#### `-S, --skip-string-normalization`
By default, _Black_ uses double quotes for all strings and normalizes string prefixes,
as described in [the style documentation](labels/strings). If this option is given,
strings are left unchanged instead.
#### `-C, --skip-magic-trailing-comma`
By default, _Black_ uses existing trailing commas as an indication that short lines
should be left separate, as described in
[the style documentation](labels/magic-trailing-comma). If this option is given, the
magic trailing comma is ignored.
#### `--preview`
Enable potentially disruptive style changes that we expect to add to Black's main
functionality in the next major release. Use this if you want a taste of what next
year's style will look like.
Read more about [our preview style](labels/preview-style).
There is no guarantee on the code style produced by this flag across releases.
#### `--unstable`
Enable all style changes in `--preview`, plus additional changes that we would like to
make eventually, but that have known issues that need to be fixed before they can move
back to the `--preview` style. Use this if you want to experiment with these changes and
help fix issues with them.
There is no guarantee on the code style produced by this flag across releases.
#### `--enable-unstable-feature`
Enable specific features from the `--unstable` style. See
[the preview style documentation](labels/unstable-features) for the list of supported
features. This flag can only be used when `--preview` is enabled. Users are encouraged
to use this flag if they use `--preview` style and a feature that affects their code is
moved from the `--preview` to the `--unstable` style, but they want to avoid the thrash
from undoing this change.
There are no guarantees on the behavior of these features, or even their existence,
across releases.
(labels/exit-code)=
#### `--check`
Don't write the files back, just return the status. _Black_ will exit with:
- code 0 if nothing would change;
- code 1 if some files would be reformatted; or
- code 123 if there was an internal error
If used in combination with `--quiet` then only the exit code will be returned, unless
there was an internal error.
```console
$ black test.py --check
All done! ✨ 🍰 ✨
1 file would be left unchanged.
$ echo $?
0
$ black test.py --check
would reformat test.py
Oh no! 💥 💔 💥
1 file would be reformatted.
$ echo $?
1
$ black test.py --check
error: cannot format test.py: INTERNAL ERROR: Black produced code that is not equivalent to the source. Please report a bug on https://github.com/psf/black/issues. This diff might be helpful: /tmp/blk_kjdr1oog.log
Oh no! 💥 💔 💥
1 file would fail to reformat.
$ echo $?
123
```
#### `--diff`
Don't write the files back, just output a diff to indicate what changes _Black_ would've
made. They are printed to stdout so capturing them is simple.
If you'd like colored diffs, you can enable them with `--color`.
```console
$ black test.py --diff
--- test.py 2021-03-08 22:23:40.848954+00:00
+++ test.py 2021-03-08 22:23:47.126319+00:00
@@ -1 +1 @@
-print ( 'hello, world' )
+print("hello, world")
would reformat test.py
All done! ✨ 🍰 ✨
1 file would be reformatted.
```
#### `--no-cache`
Do not consult or update Black's per-user cache during this run. When `--no-cache` is
specified, Black will perform fresh analysis for all files and will neither read from
nor write to the cache. This is helpful for reproducing formatting results from a clean
run, debugging cache-related issues, or ensuring CI executes a fresh formatting analysis
every time.
#### `--color` / `--no-color`
Show (or do not show) colored diff. Only applies when `--diff` is given.
#### `--line-ranges`
When specified, _Black_ will try its best to only format these lines.
This option can be specified multiple times, and a union of the lines will be formatted.
Each range must be specified as two integers connected by a `-`: `<START>-<END>`. The
`<START>` and `<END>` integer indices are 1-based and inclusive on both ends.
_Black_ may still format lines outside of the ranges for multi-line statements.
Formatting more than one file or any Jupyter Notebooks with this option is not
supported. This option cannot be specified in the `pyproject.toml` config.
Example: `black --line-ranges=1-10 --line-ranges=21-30 test.py` will format lines from
`1` to `10` and `21` to `30`.
This option is mainly for editor integrations, such as "Format Selection".
```{note}
Due to [#4052](https://github.com/psf/black/issues/4052), `--line-ranges` might format
extra lines outside of the ranges when there are unformatted lines with the exact
formatted content next to the requested lines. It also disables _Black_'s formatting
stability check in `--safe` mode.
```
#### `--fast` / `--safe`
By default, _Black_ performs [an AST safety check](labels/ast-changes) after formatting
your code. The `--fast` flag turns off this check and the `--safe` flag explicitly
enables it.
#### `--required-version`
Require a specific version of _Black_ to be running. This is useful for ensuring that
all contributors to your project are using the same version, because different versions
of _Black_ may format code a little differently. This option can be set in a
configuration file for consistent results across environments.
```console
$ black --version
black, 26.5.1 (compiled: yes)
$ black --required-version 26.5.1 -c "format = 'this'"
format = "this"
$ black --required-version 31.5b2 -c "still = 'beta?!'"
Oh no! 💥 💔 💥 The required version does not match the running version!
```
You can also pass just the major version:
```console
$ black --required-version 22 -c "format = 'this'"
format = "this"
$ black --required-version 31 -c "still = 'beta?!'"
Oh no! 💥 💔 💥 The required version does not match the running version!
```
Because of our [stability policy](../the_black_code_style/index.md), this will guarantee
stable formatting, but still allow you to take advantage of improvements that do not
affect formatting.
#### `--exclude`
A regular expression that matches files and directories that should be excluded on
recursive searches. An empty value means no paths are excluded. Use forward slashes for
directories on all platforms (Windows, too). By default, Black also ignores all paths
listed in `.gitignore`. Changing this value will override all default exclusions.
Default Exclusions:
`['.direnv', '.eggs', '.git', '.hg', '.ipynb_checkpoints', '.mypy_cache', '.nox', '.pytest_cache', '.ruff_cache', '.tox', '.svn', '.venv', '.vscode', '__pypackages__', '_build', 'buck-out', 'build', 'dist', 'venv'] `
If the regular expression contains newlines, it is treated as a
[verbose regular expression](https://docs.python.org/3/library/re.html#re.VERBOSE). This
is typically useful when setting these options in a `pyproject.toml` configuration file;
see [Configuration format](#configuration-format) for more information.
#### `--extend-exclude`
Like `--exclude`, but adds additional files and directories on top of the default values
instead of overriding them.
#### `--force-exclude`
Like `--exclude`, but files and directories matching this regex will be excluded even
when they are passed explicitly as arguments. This is useful when invoking Black
programmatically on changed files, such as in a pre-commit hook or editor plugin.
#### `--stdin-filename`
The name of the file when passing it through stdin. Useful to make sure Black will
respect the `--force-exclude` option on some editors that rely on using stdin.
#### `--include`
A regular expression that matches files and directories that should be included on
recursive searches. An empty value means all files are included regardless of the name.
Use forward slashes for directories on all platforms (Windows, too). Overrides all
exclusions, including from `.gitignore` and command line options.
Default Inclusions: `['.pyi', '.ipynb']`
#### `-W`, `--workers`
When _Black_ formats multiple files, it may use a process pool to speed up formatting.
This option controls the number of parallel workers. This can also be specified via the
`BLACK_NUM_WORKERS` environment variable. Defaults to the number of CPUs in the system.
#### `-q`, `--quiet`
Stop emitting all non-critical output. Error messages will still be emitted (which can
silenced by `2>/dev/null`).
```console
$ black src/ -q
error: cannot format src/black_primer/cli.py: Cannot parse: 5:6
mport asyncio
^
ParseError: bad input
```
#### `-v`, `--verbose`
Emit messages about files that were not changed or were ignored due to exclusion
patterns. If _Black_ is using a configuration file, a message detailing which one it is
using will be emitted.
```console
$ black src/ -v
Using configuration from /tmp/pyproject.toml.
src/blib2to3 ignored: matches the --extend-exclude regular expression
src/_black_version.py wasn't modified on disk since last run.
src/black/__main__.py wasn't modified on disk since last run.
error: cannot format src/black_primer/cli.py: Cannot parse: 5:6
mport asyncio
^
ParseError: bad input
reformatted src/black_primer/lib.py
reformatted src/blackd/__init__.py
reformatted src/black/__init__.py
Oh no! 💥 💔 💥
3 files reformatted, 2 files left unchanged, 1 file failed to reformat
```
#### `--version`
You can check the version of _Black_ you have installed using the `--version` flag.
```console
$ black --version
black, 26.5.1
```
#### `--config`
Read configuration options from a configuration file. See
[below](#configuration-via-a-file) for more details on the configuration file.
### Environment variable options
_Black_ supports the following configuration via environment variables.
#### `BLACK_CACHE_DIR`
The directory where _Black_ should store its cache.
#### `BLACK_NUM_WORKERS`
The number of parallel workers _Black_ should use. The command line option `-W` /
`--workers` takes precedence over this environment variable.
### Code input alternatives
_Black_ supports formatting code via stdin, with the result being printed to stdout.
Just let _Black_ know with `-` as the path.
```console
$ echo "print ( 'hello, world' )" | black -
print("hello, world")
reformatted -
All done! ✨ 🍰 ✨
1 file reformatted.
```
**Tip:** if you need _Black_ to treat stdin input as a file passed directly via the CLI,
use `--stdin-filename`. Useful to make sure _Black_ will respect the `--force-exclude`
option on some editors that rely on using stdin.
You can also pass code as a string using the `--code` option.
### Writeback and reporting
By default _Black_ reformats the files given and/or found in place. Sometimes you need
_Black_ to just tell you what it _would_ do without actually rewriting the Python files.
There's two variations to this mode that are independently enabled by their respective
flags:
- `--check` (exit with code 1 if any file would be reformatted)
- `--diff` (print a diff instead of reformatting files)
Both variations can be enabled at once.
### Output verbosity
_Black_ in general tries to produce the right amount of output, balancing between
usefulness and conciseness. By default, _Black_ emits files modified and error messages,
plus a short summary.
```console
$ black src/
error: cannot format src/black_primer/cli.py: Cannot parse: 5:6
mport asyncio
^
ParseError: bad input
reformatted src/black_primer/lib.py
reformatted src/blackd/__init__.py
reformatted src/black/__init__.py
Oh no! 💥 💔 💥
3 files reformatted, 2 files left unchanged, 1 file failed to reformat.
```
The `--quiet` and `--verbose` flags control output verbosity.
## Configuration via a file
_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.
**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.
### What on Earth is a `pyproject.toml` file?
[PEP 518](https://peps.python.org/pep-0518/) defines `pyproject.toml` as a configuration
file to store build system requirements for Python projects. With the help of tools like
[Poetry](https://python-poetry.org/), [Flit](https://flit.pypa.io/), or
[Hatch](https://hatch.pypa.io/) it can fully replace the need for `setup.py` and
`setup.cfg` files.
### Where _Black_ looks for the file
By default _Black_ looks for `pyproject.toml` containing a `[tool.black]` section
starting from the common base directory of all files and directories passed on the
command line. If it's not there, it looks in parent directories. It stops looking when
it finds the file, or a `.git` directory, or a `.hg` directory, or the root of the file
system, whichever comes first.
If you're formatting standard input, _Black_ will look for configuration starting from
the current working directory.
You can use a "global" configuration, stored in a specific location in your home
directory. This will be used as a fallback configuration, that is, it will be used if
and only if _Black_ doesn't find any configuration as mentioned above. Depending on your
operating system, this configuration file should be stored as:
- Windows: `~\.black`
- Unix-like (Linux, macOS, etc.): `$XDG_CONFIG_HOME/black` (`~/.config/black` if the
`XDG_CONFIG_HOME` environment variable is not set)
Note that these are paths to the TOML file itself (meaning that they shouldn't be named
as `pyproject.toml`), not directories where you store the configuration (i.e.,
`black`/`.black` is the file to create and add your configuration options to, in the
`~/.config/` directory). Here, `~` refers to the path to your home directory. On
Windows, this will be something like `C:\Users\UserName` and stored in the environment
variable `%USERPROFILE%`.
You can also explicitly specify the path to a particular file that you want with
`--config`. In this situation _Black_ will not look for any other file.
If you're running with `--verbose`, you will see a message if a file was found and used.
Please note `blackd` will not use `pyproject.toml` configuration.
### Configuration format
As the file extension suggests, `pyproject.toml` is a [TOML](https://toml.io) file. It
contains separate sections for different tools. _Black_ is using the `[tool.black]`
section. The option keys are the same as long names of options on the command line.
Most command-line options can be configured in `[tool.black]` by using their long name
without the leading `--` (for example, `--line-length` becomes `line-length`). Options
that cannot be configured in `pyproject.toml` are called out explicitly in the option
reference above.
Note that you have to use single-quoted strings in TOML for regular expressions. It's
the equivalent of r-strings in Python. Multiline strings are treated as verbose regular
expressions by Black. Use `[ ]` to denote a significant space character.
<details>
<summary>Example <code>pyproject.toml</code></summary>
```toml
[tool.black]
line-length = 88
target-version = ['py37']
include = '\.pyi?$'
# 'extend-exclude' excludes files or directories in addition to the defaults
extend-exclude = '''
# A regex preceded with ^/ will apply only to files and directories
# in the root of the project.
(
^/foo.py # exclude a file named foo.py in the root of the project
| .*_pb2.py # exclude autogenerated Protocol Buffer files anywhere in the project
)
'''
```
</details>
<details>
<summary>More complete <code>pyproject.toml</code> template</summary>
```toml
[tool.black]
line-length = 88
target-version = ["py311"]
required-version = "26"
include = '\.pyi?$'
# Formatting behavior
skip-string-normalization = false
skip-magic-trailing-comma = false
preview = false
unstable = false
# File collection
extend-exclude = '''
(
^/foo.py
| .*_pb2.py
)
'''
force-exclude = '''
(
^/generated/
)
'''
```
</details>
### Lookup hierarchy
Command-line options have defaults that you can see in `--help`. A `pyproject.toml` can
override those defaults. Finally, options provided by the user on the command line
override both.
_Black_ will only ever use one `pyproject.toml` file during an entire run. It doesn't
look for multiple files, and doesn't compose configuration from different levels of the
file hierarchy.
## Next steps
A good next step would be configuring auto-discovery so `black .` is all you need
instead of laboriously listing every file or directory. You can get started by heading
over to [File collection and discovery](./file_collection_and_discovery.md).
Another good choice would be setting up an
[integration with your editor](../integrations/editors.md) of choice or with
[pre-commit for source version control](../integrations/source_version_control.md).
+94
View File
@@ -0,0 +1,94 @@
" black.vim
" Author: Łukasz Langa
" Created: Mon Mar 26 23:27:53 2018 -0700
" Requires: Vim Ver7.0+
" Version: 1.2
"
" Documentation:
" This plugin formats Python files.
"
" History:
" 1.0:
" - initial version
" 1.1:
" - restore cursor/window position after formatting
" 1.2:
" - use autoload script
if exists("g:load_black")
finish
endif
if v:version < 700 || !has('python3')
func! __ERROR()
let messages = []
if v:version < 700
call add(messages, "vim7.0+")
endif
if !has('python3')
call add(messages, "Python 3.10 support")
endif
echo "The black.vim plugin requires" join(messages, " and ")
endfunc
command! Black :call __ERROR()
command! BlackUpgrade :call __ERROR()
command! BlackVersion :call __ERROR()
finish
endif
let g:load_black = "py1.0"
if !exists("g:black_virtualenv")
if has("nvim")
let g:black_virtualenv = "~/.local/share/nvim/black"
else
let g:black_virtualenv = "~/.vim/black"
endif
endif
if !exists("g:black_fast")
let g:black_fast = 0
endif
if !exists("g:black_linelength")
let g:black_linelength = 88
endif
if !exists("g:black_skip_string_normalization")
if exists("g:black_string_normalization")
let g:black_skip_string_normalization = !g:black_string_normalization
else
let g:black_skip_string_normalization = 0
endif
endif
if !exists("g:black_skip_magic_trailing_comma")
if exists("g:black_magic_trailing_comma")
let g:black_skip_magic_trailing_comma = !g:black_magic_trailing_comma
else
let g:black_skip_magic_trailing_comma = 0
endif
endif
if !exists("g:black_quiet")
let g:black_quiet = 0
endif
if !exists("g:black_target_version")
let g:black_target_version = ""
endif
if !exists("g:black_use_virtualenv")
let g:black_use_virtualenv = 1
endif
if !exists("g:black_preview")
let g:black_preview = 0
endif
function BlackComplete(ArgLead, CmdLine, CursorPos)
return [
\ 'target_version=py310',
\ 'target_version=py311',
\ 'target_version=py312',
\ 'target_version=py313',
\ 'target_version=py314',
\ ]
endfunction
command! -nargs=* -complete=customlist,BlackComplete Black :call black#Black(<f-args>)
command! BlackUpgrade :call black#BlackUpgrade()
command! BlackVersion :call black#BlackVersion()
File diff suppressed because it is too large Load Diff
+41440
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+22431
View File
File diff suppressed because it is too large Load Diff
+1002
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+102
View File
@@ -0,0 +1,102 @@
config = some.Structure(
globalMap = {
103310322020340: [100000031211103,101042000320420,100100001202021,112320301100420,110101024402203,112001202000203,112101112010031,102130400200010,100401014300441,103000401422033],
110040120003212: [114413100031332,102101001412002,100210000032130,214000110100040,103031420121210,112114222301010,110133330100020,100001001203011,102210220202130,102200120234012],
244402003102200: [110212012114431,100001140020000,100012101223021,110031301200114,114002020044120,100021004302202,102202200240222,114102010220042,102021301441201,104103102103201],
122013242003223: [100014100100001,102100004130301,111120004100414,101034024000101,100021424301033,102003004003400,103340410140122,100102114100420,111012202111021,100103144302200],
1120010021223330: [110332202020000,104120130021200,112421004012141,111100220022101,100021104201130,102224410201003,110030021010001,101300401002320,112001321113132,101110434020010],
214100003030021: [102122000214201,100242141004122,102024240221040,110320011200230,100011114300334,102303004110022,100110201042101,110134201140010,112101044000202,100040024340013],
1000220132200020: [102231130213210,103214010102022,102000402041014,100043324210140,100023024211011,102404021403141,100010004313001,100003201021001,100122020011232,100121031014040],
1200041022422001: [100021300101110,103010301402112,100011401031000,100020034100101,100122214300222,103134021420204,102042210220100,100103200021130,103204214043011,103020320102002],
1000232101122040: [110011414240022,102202310203222,100042001020203,102002320220202,100010044300003,114130210231020,103301410110110,112114324040000,102124031023100,100204104320231],
110002000000001: [110010000111020,102011041320000,114240012324120,100022010022031,102014140200013,101240110302200,100031204311023,101232001021020,100012121040101,111243002222100],
200211022142211: [102231130213210,103214010102022,100043324210140,102324014112020,102022004012201,100023024211011,111130210020000,102404021403141,100003201021001,100122020011232],
114121130201204: [100040031020241,101100104000222,102324141000002,101010234004042,102041224010012,100411400030100,100002000102100,114340102322021,112033124022002,102120221120200],
104101002123040: [100032320000112,103140011442322,100312120141341,111144020011120,112142204020032,110044031204131,114012010020012,100001420412010,100102110020102,103022000123142],
241101103112120: [110333404433042,112240002043300,110021100132240,103104221443021,101100304000101,100202210410011,114402212310021,102411011111011,103020141414101,100113001040420],
1004020030320422: [100022214203010,110310011234031,110123111300000,100020031041304,102120004000101,102020002000420,110100302010110,100422020030044,101220100303222,100002220411002],
1041010100001110: [111124004101012,114103220220104,102120004001310,102430121110340,101021204000200,112141104020201,101200111020111,110001200422320,103210114021430,114223242332100],
121103011132000: [110021104200001,110441140102024,111140124100100,110310020040401,100002024303323,110030002130201,102103320232241,110302000400221,110111001302000,110210304220000],
1042022101004111: [110021104200001,111140124100100,110031301200114,102103320232241,110302000400221,110111001302000,110210304220000,102033124000111,111000212204213,110010324410130],
102220010222003: [114003212210013,110302012103114,103023101400002,110010120440200,110024140022040,100002100100320,110100034200300,100401201010220,103200024021204,102100204000234],
1442130103121040: [114413100031332,112121020204344,102211030203010,100210000032130,214000110100040,103031420121210,112114222301010,100001001203011,114214404142034,102210220202130],
110204013021024: [110301402000211,103030201402004,110420104221220,103200004030020,100320014310021,102000110221110,110240214432004,102122141142000,103041204010000,114432234113040],
100001440133234: [102111040210242,114110000002430,102010011412143,100424220032043,114013422300032,102021004001004,100131414303044,100201010110320,100000221030033,110101101120302],
114002033000020: [100001121002141,102000040201003,101132131221321,100004440004031,102002011033030,110310300003402,110220022132003,101001000302103,110044112100220,100010120031210],
112123022000131: [100304201000221,100112021020320,103010001422020,102300124023122,114221004100020,100002100124101,102304100210334,100403210010142,112003100241220,102204304000304],
1143001230040001: [101033124003122,100313144100202,103201004024412,114014222302011,103011020110211,110203420111140,111003412201430,101411214000203,110222422042203],
1002403200000231: [100122004300410,102140014001101,102000104012232,112400202020003,102000224000011,114122134140002,102101010202004,114400202310210,100042030201341,112233332034000],
1003123041101031: [110043132100300,102220120203200,100002004201122,110132031134031,1320303202002000,1321200010022312,110130330012140,114102134002330,140403400240000,100003230110201],
242220101103400: [111130112100210,102202200240222,110131044200121,100100004102234,110223332120231,100001024301322,114013044102010,114220114140122,101023021034304,110200210110130],
121030040400021: [110011011212100,101134030011000,103220211421421,110123230124040,131000001020102,112200412033030,110420001000202,100102110402220,110412310030001,114012022302022],
100104011300401: [110320414420310,110100100101041,100420124100211,103010211222002,101040120320230,110013021300010,101043234000412,101220000040002,100422001002123,114010010010002],
1004003211220032: [102400100230000,101100300302102,114120420223002,100002210201212,102302020212101,112410424012010,100030004104210,103030201434002,110232110004010,103021201430000],
223011102020040: [110012420131001,100132040031022,100020310000200,100220004030002,110020002003334,110014000442004,101441204020001,102014201411102,103231320100042,104121201242032],
100200110422111: [103100221440010,114003344011001,100021101000000,102140000212141,101014201030204,101203001010111,102424114020143,100031201030102,101041001003300,114012444020220],
134300111030221: [112100124023402,101020044011003,100002414210010,102010042000041,102242204040102,100021014100124,100130244302034,100122040012210,100014010104404,101020104000001],
114001000330100: [401142101000022,400114001102410,102100000012031,431232000323104,1012100023110102,232023302143031,120200122422404,1040100003200241,111414004440203,1020220210340010],
211222012120321: [112000112000031,100121214300000,102123214020000,102022124012030,114002320022312],
1122000200402140: [102401141113031,103042420143020,102304314110202,110210400002012,113032012204012,112310002020302,100204311000400,100403012200201,112002111121013,114211100001224],
332000024200013: [102120010220042,110103312142034,102210210312302,101120100320100,114140014100000,102110004002301,100130020001030,112022100213011,100101231202322,111210020001013],
120041442412123: [102133011413110,111001200041102,101223020300040,102034324000220,100210000032400,101230020303000,111340130010314,110200422121211,110214220002020,112220414010040],
1011011320300100: [100102024301030,100111134302041,100112234000041,110004244214343,101002101020003,102214021120301,114221224100022,101330210310300,112003021111000,102012141134211],
220020021000101: [100301001000202,104101112102403,100023121223031,114201432320014,120000002023011,102133120200123,101014020301201,102000031130401,101010111002141,114123124143310],
1024011342000021: [102001001130100,111204203012002,124020002020003,122222120003214,133332002141010,144000013213001,124010030100142,112310202021010,110014020020011,100140044020011],
1131011002310011: [102230040200031,110122001010214,114043140010022,102101204000010,110022300420031,100100401040001,114230230000123,100222024320003,103323001400013,114013012300240],
1142024120224002: [102203344011410,100021324100000,102103430210003,100012014300120,102414014022212,102012220241003,101004411032102,101430211012120,100204021000012,103242044020102],
1100004410231120: [110013202003320,101031241000010,102120231343224,110030332100203,100314114322101,114404232310120,103100034001310,114002202210331,100031301020100,110111032140220],
1440220030001122: [114010330030011,103021220104200,101010020320000,112000210211020,100010324210003,101000000343443,110002400011111,100402132200000,111100300024000,103144040104204],
121414301110004: [110144240011020,110413401240204,112000244001222,114441114123013,103220211421421,114000012334102,101000014012442,100312401002102,111022210021013,103110001420121],
130004004220120: [111240340004003,102021024000010,111101222244030,112011012004300,102300010242330,102000401120420,102004012043122,114011102210402,100120001014040,114300100000041],
1013303000401020: [101000024004442,100002100000100,110130030020000],
220041302111231: [100002014200331,100034244210020,102012004000003,100411000030110,102041201121230,103011014042120,100000030120242,102110400210023,101012204221200,111212422222300],
1000031031200013: [101302134233230,100000130010033,101030404212000,114102224000201,100022021041122,100020001042002,100013011020311,100120041020012,102012204000242,114143024003322],
1000303301100221: [111333104124202,101000304014100,100040011023101,110301030010140,104100002101431,101123232010002,114421242204443,110100222001100,103102000121300,110010331230210],
1410211342331412: [111002100000102,114021010040140,114222302321101,102101024002121,110014024202014,110220130100010,100020011030330,102404221402210,110203022032320,101222014230110],
1411020122202044: [100141401021003,102010000231120,101000400320211,101001010300214,103010020142023,110132002212113,110010100040100,102101002002002,111020302232033,110224030114311],
101010042001102: [101221020040220,100103104302044,101041030320401,102141212000200,101203121020430,102020004000014,100000211023014,114144014122041,100201111002224,101410304041000],
204204011102020: [100212030414010,101400004022210,102031021441200,101200020303202,102301324112020,111340300010010,102013224003020,103013020123142,102240344041020,102140202001100],
240000420312002: [110002004410202,102103114000024,102240221000001,112041002002124,114000024101102,140343100002103,400200234320200,100020124204330,100001424102041,100100021040230],
1030000001422430: [102343230224321,103211200100400,102112231020231,100022004300020,102320000240102,100042144200000,102030304001101,100020420121003,103020004011414,100001104301200],
1104234221030010: [110000322130121,101023001002020,111300222202234,100200001210021,103204230111030,104130020011020,101114422122000,102001314013400,114110414140400,111201100011141],
121341130003000: [111102004100101,102021100220101,114000040010421,112042110220004,100000214240410,100433201004014,102301102004413,102003000220111,102010100204023,102414040230400],
100101220022002: [100010024102110,101041200320012,114303400002201,110204211000331,112121014003422,114430102311021,100240444100022,103004411424400,111014002140322],
1023303420422001: [100043104240004,110002034200042,100001240100033,114100304002030,102100001340122,112030010234104,103414101212410,100123021223100,112302011102312,101020030343002],
101114102124321: [110403244220202,103113014002100,110120400402324,100402340010310,112010020211000,100102200000211,103030201240100,102300210210222,114100332340213,111031030024010],
1422302020100030: [114020000030002,114031000022030,100201211003004,102014002000401,103103241421322,114121012340044,102000400240203,102104304023201,103310300140324,100002224244002],
1121202400231120: [101211201202134,103120104030100,100004000100101,102020030220200,110031404423144,110003434410403,111110000014401,100000204312321,101004000304012,110300121220201],
1042001221000013: [114032104100141,101213114040141,102210101002412,111140100011101,110122421241103,112001144002010,101013030304101,100012011022000,102000004000013,102021241324040],
1102433033042110: [110104112010103,111102004100101,100122004300410,102202414041044,102140014001101,102000104012232,102021100220101,114443330001442,100230120001003,114000040010421],
100103201011144: [110102401201204,102400100230000,100212030414010,101200020303202,114120420223002,102013224003020,100002210201212,103013020123142,102302020212101,114303340000001],
240343043023011: [110120144200000,114022412330004,101200221022044,110241112020204,100002004104004,102100224000210,102310140240012,100014204201000,102103321411004,100400001001300],
1020301032424304: [101302134233230,100000130010033,101030404212000,114102224000201,100431000032001,100020001042002,100013011020311,102103331400000,100120041020012,100020001041231],
114200022220040: [100014100100001,102100004130301,111120004100414,101034024000101,101243024011000,103340410140122,100010021221221,111012202111021,100103144302200,101414100300221],
142041243300010: [102102002002242,101130104022002,101230331020012,100004244210201,102420124024204,122312222240401,102041014011340,110200130004300,100140101012000,101400000302141],
1002203102111022: [100434000032200,110004020020022,114032412303041,112000301122111,102020130212402,100010001020000,200000020021022,114321212322303,112302112002211,114202002333330],
1110102121041413: [101012310301211,103112200123144,114242304004011,102302200241241,110001420021023,110201040003402,112301421130130,110020012100302,114412202320010,110021030030202],
114020200220012: [102010114022011,103340041403223,114002200000421,101020321002002,114302210010001,114030004104220,100104004301000,102443211401140,102301041000014,100001111201214],
202011212123200: [102203301123001,103210400110122,101112020300011,114104302341000,100400201010000,102244400201444,101010001000121,102304000220032,102002131132000,100000031024222],
201032103003132: [110212041114210,113210300100002,112404024011000,102131034000220,111212124130140,101002014013010,103402020120010,112110100230023,112003044002004,103020200102200],
120222032001012: [110121100004131,111400214442024,111122200021102,101041100300001,102140011440001,101011220342010,110200004221020,103114211441300,110000222010004,100114000101041],
1100013040001020: [100003031030034,101001044211204,102100010233022,102120400212001,114313022302101,103001324000110,100002014200021,102300401001010,103212320212011,111120034400000],
1001031021300022: [102000020220000,101020104000040,114412142320040,100003044100101,114012402332300,102220211122102,101010110302010,100032121020101,100013224313301,100012244240030],
124000010122242: [100032320000112,103140011442322,100312120141341,111144020011120,112142204020032,110044031204131,114012010020012,100001420412010,100102110020102,102002204001140],
1121211020204132: [110020301320101,102014001130210,110401041140300,110002302201420,102202001120002,110200010003201,102421004041011,102240040202421,101001110300111,100130004300103],
121320202004301: [111014240041102,101100004200110,112021221130424,112200041103002,110400040402041,112001011112202,100112004304314,100232041001122,100223030001010,100104231000300],
1024242230240244: [110322104424202,101202421002031,102102220312102,103004204021310,112220102043102,110012310020200,102030130241300,103030120100220,100232224340041,112400002011010],
1002100010130110: [101400001011042,100002011020211,100100110010010,111110002213142,100002131030310,111102214100400,103220201402330,102321000221140,103113124030200,102110300311400],
200010402222410: [101210320301302,102100221340112,100114104101001,114002244103320,101023221000031,101400014040400,102012034000402,114221004002212,102100122002001,101000011021414],
112300020202111: [103141411420221,122102400312000,110002100110002,1340024302404122,100002001043010,113110330121030,410020013004430,1002300040412102,1210020204140003,123211320000102],
100102203210034: [102023021100022,111200302222011,112040241120204,111000022200000,100010011232324,110220030000133,110000330430311,101211221014003,103111230120100,102221220200021],
1021001032000012: [102020010203200,100011144312020,102011204001010,102001410221023,110130201302200,103041021430301,101100440320434,114000402211404,101000100302003,110000030430422],
1031102424140120: [100011010414200,111121102240240,102002121101110,102403100202003,110000100041101,100400000010033,100101211001320,101141020321000,103224101400400,102000002043020],
102001021434201: [110131122012210,114010200040441,110032014420232,100000344100100,111304022202211,102302011002003,102011021121200,100012441030002,110222042022111,103131004002200],
220100132400104: [1010400230221020,111320012221132,102302144110440,114140004123122,102143202000400,111020002202333,101321311004010,102110241342210,114122302311011,100002320411400],
1110121023020002: [100022041001002,111240340004003,111101222244030,114032424122040,112011012004300,101021401003220,100301020420101,102002202000000,100022024100041,102010410213111],
1042030001044121: [101230040301234,110033032100000,102303014024221,100100224304110,100400432200321,100020200012311,114140144122230,101400201102014,100000020004004,101040040303102],
1100100224104011: [111130112100210,102202200240222,110131044200121,100100004102234,101023014004000,110223332120231,100001024301322,114013044102010,114220114140122,110200210110130],
212002042300000: [100030220100110,110011202100142,112400102013231,114012002212100,100002114314022,114203110001031,112030122000211,111004012200210,100413131013301,110001102103432],
221001240043040: [100420021010013,112101302302202,102212011120200,102344111104233,100432104320110,114021014020000,102121321340000,114200214002024,100111221011100,100023104101340],
1040021200420124: [100042111220111,112220100202000,100042041220010,100403211010100,103240301400123,114102210214041,100021300103041,101010204000242,111334004121414,114101000213410],
},
)
+246
View File
@@ -0,0 +1,246 @@
# Example configuration for Black.
# NOTE: you have to use single-quoted strings in TOML for regular expressions.
# It's the equivalent of r-strings in Python.
# Multiline strings are treated as verbose regular expressions by Black.
# Use [ ] to denote a significant space character.
[tool.black]
line-length = 88
target-version = ["py310"]
include = '\.pyi?$'
extend-exclude = '''
/(
# The following are specific to Black, you probably don't want those.
tests/data/
| profiling/
)
'''
# We use the unstable style for formatting Black itself. If you
# want bug-free formatting, you should keep this off. If you want
# stable formatting across releases, you should also keep `preview = true`
# (which is implied by this flag) off.
unstable = true
# Build system information and other project-specific configuration below.
# NOTE: You don't need this in your own Black configuration.
[build-system]
requires = ["hatch-fancy-pypi-readme", "hatch-vcs>=0.3.0", "hatchling>=1.27.0"]
build-backend = "hatchling.build"
[project]
name = "black"
description = "The uncompromising code formatter."
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.10"
authors = [{ name = "Łukasz Langa", email = "lukasz@langa.pl" }]
keywords = ["automation", "autopep8", "formatter", "gofmt", "pyfmt", "rustfmt", "yapf"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
]
dependencies = [
"click>=8.0.0",
"mypy-extensions>=0.4.3",
"packaging>=22.0",
"pathspec>=1.0.0",
"platformdirs>=2",
"pytokens~=0.4.0",
"tomli>=1.1.0; python_version<'3.11'",
"typing-extensions>=4.0.1; python_version<'3.11'",
]
dynamic = ["readme", "version"]
[project.optional-dependencies]
colorama = ["colorama>=0.4.3"]
uvloop = [
"uvloop>=0.15.2; sys_platform != 'win32'",
"winloop>=0.5.0; sys_platform == 'win32'"
]
d = ["aiohttp>=3.10"]
jupyter = ["ipython>=7.8.0", "tokenize-rt>=3.2.0"]
[dependency-groups]
hatch = ["hatch==1.15.1", "hatch-fancy-pypi-readme", "hatch-vcs", "virtualenv<21.0.0"]
cibw = ["cibuildwheel==3.4.0", "pypyp"]
pyinstaller = ["pyinstaller"]
dev = [{ include-group = "cov-tests" }, { include-group = "tox" }, "pre-commit"]
cov-tests = [
{ include-group = "coverage" },
{ include-group = "tests" },
"pytest-cov>=4.1.0",
]
docs = [
"docutils==0.22.4",
"furo==2025.12.19",
"myst-parser==5.0.0",
"sphinx-copybutton==0.5.2",
"sphinx==9.1.0",
"sphinxcontrib-programoutput==0.20",
]
tox = ["tox>=4.22"]
tests = ["pytest>=7", "pytest-xdist>=3.0.2"]
coverage = ["coverage>=5.3"]
fuzz = [{ include-group = "coverage" }, "hypothesis", "hypothesmith"]
diff-shades = [
"diff-shades @ https://github.com/ichard26/diff-shades/archive/stable.zip",
]
diff-shades-comment = ["click>=8.1.7", "packaging>=22.0", "urllib3"]
width-table = ["wcwidth==0.2.14"]
[project.scripts]
black = "black:patched_main"
blackd = "blackd:patched_main [d]"
[project.entry-points."validate_pyproject.tool_schema"]
black = "black.schema:get_schema"
[project.urls]
Documentation = "https://black.readthedocs.io/"
Changelog = "https://github.com/psf/black/blob/main/CHANGES.md"
Repository = "https://github.com/psf/black"
Issues = "https://github.com/psf/black/issues"
[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"
fragments = [{ path = "README.md" }, { path = "CHANGES.md" }]
[tool.hatch.version]
source = "vcs"
[tool.hatch.build.hooks.vcs]
version-file = "src/_black_version.py"
template = """
version = "{version}"
"""
[tool.hatch.build.targets.sdist]
exclude = ["/profiling"]
[tool.hatch.build.targets.wheel]
only-include = ["src"]
sources = ["src"]
# Note that we change the behaviour of this flag below
macos-max-compat = true
[tool.hatch.build.targets.wheel.hooks.mypyc]
enable-by-default = false
dependencies = ["hatch-mypyc>=0.16.0", "mypy==1.20.2"]
require-runtime-dependencies = true
exclude = [
# There's no good reason for blackd to be compiled.
"/src/blackd",
# Not performance sensitive, so save bytes + compilation time:
"/src/blib2to3/__init__.py",
"/src/blib2to3/pgen2/__init__.py",
"/src/black/output.py",
"/src/black/concurrency.py",
"/src/black/files.py",
"/src/black/report.py",
# Breaks the test suite when compiled (and is also useless):
"/src/black/debug.py",
# Compiled modules can't be run directly and that's a problem here:
"/src/black/__main__.py",
]
mypy-args = ["--ignore-missing-imports"]
options = { debug_level = "0" }
[tool.cibuildwheel]
build-verbosity = 1
# So these are the environments we target:
# - Python: CPython 3.10+ only
# - Architecture (64-bit only): amd64 / x86_64, universal2, and arm64
# - OS: Linux (no musl), Windows, and macOS
build = "cp31*"
skip = [
"*-manylinux_i686",
"*-musllinux_*",
"*-win32",
"pp*",
"cp31?t-*", # mypyc doesn't have great support for free threaded builds
]
test-groups = ["tests"]
test-command = 'pytest {project} -k "not incompatible_with_mypyc" -n auto'
test-extras = ["d", " jupyter"]
# Skip trying to test arm64 builds on Intel Macs. (so cross-compilation doesn't
# straight up crash)
test-skip = ["*-macosx_arm64", "*-macosx_universal2:arm64"]
[tool.cibuildwheel.environment]
HATCH_BUILD_HOOKS_ENABLE = "1"
MYPYC_OPT_LEVEL = "3"
MYPYC_DEBUG_LEVEL = "0"
CC = "clang"
[tool.cibuildwheel.linux]
manylinux-x86_64-image = "manylinux_2_28"
before-build = ["yum install -y clang"]
[tool.isort]
atomic = true
profile = "black"
line_length = 88
skip_gitignore = true
skip_glob = ["tests/data", "profiling"]
known_first_party = ["black", "blib2to3", "blackd", "_black_version"]
[tool.pytest.ini_options]
# Option below requires `tests/optional.py`
addopts = "--strict-config --strict-markers"
optional-tests = [
"no_blackd: run when `d` extra NOT installed",
"no_jupyter: run when `jupyter` extra NOT installed",
]
markers = ["incompatible_with_mypyc: run when testing mypyc compiled black"]
xfail_strict = true
filterwarnings = ["error"]
[tool.coverage.report]
omit = ["src/blib2to3/*", "tests/data/*", "*/site-packages/*", ".tox/*"]
[tool.coverage.run]
relative_files = true
branch = true
[tool.mypy]
# Specify the target platform details in config, so your developers are
# free to run mypy on Windows, Linux, or macOS and get consistent
# results.
python_version = "3.10"
mypy_path = "src"
strict = true
strict_bytes = true
local_partial_types = true
# Unreachable blocks have been an issue when compiling mypyc, let's try to avoid 'em in the first place.
warn_unreachable = true
implicit_reexport = true
show_error_codes = true
show_column_numbers = true
[[tool.mypy.overrides]]
module = ["pathspec.*", "IPython.*", "colorama.*", "tokenize_rt.*", "uvloop.*"]
ignore_missing_imports = true
# CI only checks src/, but in case users are running LSP or similar we explicitly ignore
# errors in test data files.
[[tool.mypy.overrides]]
module = ["tests.data.*"]
ignore_errors = true
View File

Some files were not shown because too many files have changed in this diff Show More