#black-formatter

1 messages ยท Page 10 of 1

flat krakenBOT
#

In src/black/concurrency.py, schedule_formatting() creates a multiprocessing.Manager() when write_back is DIFF or COLOR_DIFF, but the Manager is never explicitly shut down.
code location:

async def schedule_formatting(...):
lock = None
if write_back in (WriteBack.DIFF, WriteBack.COLOR_DIFF):
manager = Manager()
lock = manager.Lock()

Since Manager starts a separate server process, not calling shutdown(...

flat krakenBOT
#

Fix parsing error for backslash continuations with no indentation

Description

Fixes the parsing error that occurred when Black encountered multi-line expressions using backslash (\) line continuations followed by unindented lines.

Problem

Black would fail to parse valid Python code like:

if True:
    foo = 1+\
2
    print(foo)

With the error:

error: cannot format file.py: Cannot parse for target version Python 3.13: 3:0: 2

This is ...

silent knoll
#

#3 "allows including files from excluded directories" which seems like a good change to me

#

Also, it'd make sense to make that change in a major release

Btw, speaking of 26.1.0, I'm out of town this weekend but hoping to release it next week

flat krakenBOT
mint barn
#

sup

dense jungle
#

True though that the 26.1.0 release is a good time to make that kind of change

#

But if we do something that changes behavior we should clearly call it out in release notes

flat krakenBOT
#

Description

Fixes #4950.

src/black/concurrency.py:schedule_formatting() creates a multiprocessing.Manager()
when write_back is DIFF or COLOR_DIFF in order to share a lock and prevent
interleaved diff output across worker processes. Since multiprocessing.Manager()
starts a separate server process, not explicitly shutting it down can lead to
leaked processes and resources when Black is used as a library or invoked
repeatedly in long-running processes.

This issue is...

flat krakenBOT
#

When Black is run with --diff or --color-diff, it creates a multiprocessing.Manager() to share locks across worker processes. This Manager was never explicitly shut down, which can leave background processes running after Black finishes. This becomes problematic when Black is used as a library or invoked repeatedly in long-running environments such as editor integrations or CI pipelines.

This change ensures deterministic cleanup of the Manager by wrapping the main execution path in schedul...

silent knoll
#

bruh

silent knoll
#

fyi, ci is now failing due to the unexpected deprecation warnings

flat krakenBOT
#

Summary

Adds documentation explaining how to properly exclude files when using Black with pre-commit.

This addresses a common point of confusion: Black's --exclude option doesn't work with pre-commit because pre-commit passes files directly via the command line rather than letting Black discover files recursively.

The new section covers:

  • Why --exclude doesn't work: Pre-commit passes files via CLI, bypassing recursive discovery
  • Option 1 (Recommended): Using pre-commit's n...
flat krakenBOT
#

Description

Fixes #4944. Like I mentioned in the issue, I think (3) is the best. Even though it causes changes
for endusers, it's consistent with Git. Plus, the next release is 26.1.0, which is a good time to
make such a change.

Checklist - did you ...

  • [-] Implement any code style changes under the --preview style, following the stability policy?
  • [y] Add an entry in CHANGES.md if necessary?
  • [y] Add / update tests if necessary?
  • [-] Add new / update outdated...
silent knoll
#

would appreciate a quick review from another maintainer, since this is a breaking change (and it's also blocking 26.1 due to the deprecation warnings causing ci to fail)

flat krakenBOT
#

Description

Checklist - did you ...

  • [-] 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?
  • [y] Add new / update outdated documentation?
silent knoll
#

all ๐ŸŸข !

flat krakenBOT
silent knoll
elder tusk
#

btw does anyone here have maintainer on pytokens? have two PRs open that will make Black much faster

silent knoll
#

@lavish scroll

lavish scroll
#

I'm also in SF this week! if you're around we can meet for coffee

elder tusk
#

yeah i could come into SF some day! also sorry we missed last time, i missed the linkedin email notif

#

what days/times/places work for you?

lavish scroll
#

tomorrow also works if you have a holiday

lavish scroll
#

@elder tusk another thing that's not documented but probably very useful: give pytokens a very large python project and it'll validate itself against python's builtin tokenize module

python -m pytokens --validate ../black
#

even better if the folder has a virtual environment full of third party modules, the more files the better

elder tusk
elder tusk
lavish scroll
#

if saturday works that'd be great

lavish scroll
#

all the linux ones are solid

elder tusk
#

ah i made the uv change after verifying the build on all platforms. let me just remove it

lavish scroll
#

adding the uv install script would be ok i think

#

right after actions/checkout

elder tusk
#

the install script is different on windows, i think not worth it

lavish scroll
#

cool

#

I'll release a 0.4.0 tonight

#

We should add a >=0.4.0,<0.5 in the black pyproject, right now it just picks the latest

#

unless python understands 0ver and doesn't upgrade minor versions for 0.x

silent knoll
#

python tooling doesnt follow semver at all from what i can tell which is a major flaw imo coming from a node background

elder tusk
#

sg! although in this particular case it's actually quite nice that most black users will pick up the perf fix ๐Ÿ™‚

silent knoll
#

pathspec was at >=0.something and pip was installing v1 once it got released

lavish scroll
#

wow

lavish scroll
#

pytokens is a big enough part of black that we should update it lockstep with black versions imo

#

pytokens patches being upstreamed as black patch updates etc

silent knoll
#

I'm not certain how python dependencies get installed though
To my understanding if a user tries to install package==1.1.0 as well as black, but if black uses package~=1.0.0 i think that causes problems
So we should to avoid narrowing dependency versions when possible

#

We should definitely move dev-only dependencies to that though, especially now that most things are properly updated with Dependabot

#

Some deps don't even define a version and just install latest

lavish scroll
flat krakenBOT
#

Describe the bug

Black crashes with the mentioned error on a very old script that we have included for ages

To Reproduce

See: https://github.com/sabnzbd/sabnzbd/blob/develop/tools/pygettext.py

Log as mentioned in the error:
blk_ym54yfeb.log

This also happens when I use black.vercel.app.
It crashes.

Expected behavior

No failure

Environment

Black 26.1.0
Windows and black.vercel.app.

**Additional c...

silent knoll
#

don't think there's anything we can do at this point since it's been released

silent knoll
#

we could theoretically remove the normalization all together in a patch release, then change it to normalize to two lines next year
but that's the same noise two years in a row for everyone who already changed

#

i don't think we ever had a discussion on 1 vs 2 lines after imports but from the points made in the issue i think 2 lines is better (1 line is used between import groups already so 2 lines would be better to break imports up from the rest of the file; if the first thing after the imports is a function/class there's going to be 2 blank lines anyway so it should be 2 lines all the time)

azure plank
#

Trying to set up the project for dev again and doing my normal thing (clone, uv venv, uv pip install the things) I get this, was sphinx recently updated?

PS ~\Documents\python_projects\black>uv run .\src\black\__init__.py "C:\Users\GiGaGon\Downloads\pygettext.py"
  ร— No solution found when resolving dependencies for split (markers: python_full_version == '3.10.*' and sys_platform
  โ”‚ == 'win32'):
  โ•ฐโ”€โ–ถ Because the requested Python version (>=3.10) does not satisfy Python>=3.11 and sphinx==8.2.3 depends on
      Python>=3.11, we can conclude that sphinx==8.2.3 cannot be used.
      And because black:docs depends on sphinx==8.2.3 and your project requires black:docs, we can conclude that your
      project's requirements are unsatisfiable.

      hint: The `requires-python` value (>=3.10) includes Python versions that are not supported by your dependencies
      (e.g., sphinx==8.2.3 only supports >=3.11). Consider using a more restrictive `requires-python` value (like
      >=3.11).

      hint: While the active Python version is 3.14, the resolution failed for other Python versions supported by your
      project. Consider limiting your project's supported Python versions using `requires-python`.
silent knoll
# flat kraken

I'm looking in to this and so far my conclusion is I don't think this file is actually encoded using iso-8859-1, but I'm not sure what

azure plank
#

That's also what I'm trying to look at, I think I'm seeing the same thing? J\xfcrgen

#

No wait that is correct

>>> "Jรผrgen".encode("iso-8859-1")
b'J\xfcrgen'
>>> "Jรผrgen".encode("utf-8")
b'J\xc3\xbcrgen'
silent knoll
azure plank
#

Hm, so I guess that makes uv now see it and recognize a potential conflict

#

I wonder if I'm just using uv wrong

silent knoll
#

I've been using venv without an issue

azure plank
#

hm

#

Adding a print it looks like we should recognize the encoding correctly as iso-8859-1

#

It looks like the cause is from passing the normalized contents into lib2to3_parse instead of the src_contents

#

# 2002-11-22 Jรƒร‚รƒร‚ยผrgen Hermann <jh@web.de>

silent knoll
#

i think i found it

#

we call decode_bytes twice

#

once in format_file_in_place/format_stdin_to_stdout and again in _format_str_once

azure plank
#

Ah, so we're double-decoding it

#

I think we already did that in the past? But the newline handling worked fine, the issue now is that I passed that double normalized contents into lib2to3_parse when we normally only used it for newline detection in _format_str_once

silent knoll
#

we did not previously call decode_bytes in _fmt_str_once

#

src_contents here is already decoded, so we can ignore normalized_contents here entirely

silent knoll
#

oh i see

#

yeah, the double-decoded source was originally only used for this check, so we should still use src_contents in lib2to3_parse

#

i'm not sure what that check is doing, should we be double-decoding there?

#

apparently it's checking if the file is whitespace-only but i'm not sure how that works

azure plank
#

I think that check is for if a file put into black was nothing but newlines, since in that case the formatting process removes them all, so we return a single newline

silent knoll
#

ah i see now

#

what if we just

#

i believe the change there is it would format fully-empty files as one blank line instead of keeping them fully empty

azure plank
#

I think that's what it's trying to avoid

silent knoll
#

wait yeah'

#

because then it'd be two blank lines in the file, right

#

but yeah we could use the single-decoded version there just fine

#

yeah, src_contents isn't changed since it's decoded

azure plank
#

So the fix should be pretty simple, the question is what should we do on the releases side?

silent knoll
#

i mean this feels pretty small to warrant a patch, but then again, it's corrupting comments

#

possibly could corrupt more too

#

but it is very much an edge case

#

we should probably see if anything else pops up this week at least

silent knoll
azure plank
#

I think this would only affect non-utf-8 files?

silent knoll
#

yeah

azure plank
#

I'll prepare a PR for the encoding issue

#

Not sure about the import newlines issue

silent knoll
#

oh i've almost got one up already

azure plank
#

Then feel free

flat krakenBOT
#

Description

decode_bytes was already called in format_file_in_place/format_stdin_to_stdout, so
src_contents in _format_str_once had already been decoded.

Checklist - did you ...

  • [-] Implement any code style changes under the --preview style, following the stability policy?
  • [y] Add an entry in CHANGES.md if necessary?
  • [y] Add / update tests if necessary?
  • [-] Add new / update outdated documentation?
silent knoll
#

hm tests are failing

azure plank
#

It looks like it's not that PR? Since just running black on it's own fails too ```
PS ~\Documents\python_projects>uvx black -c "try:\\r# type: ignore\n pass\nfinally:\n pass\n"
try:\\r# type: ignore\n pass\nfinally:\n pass\n
error: cannot format <string>: Cannot parse: 1:3: Failed to parse: UnexpectedCharacterAfterBackslash

#

Oh wait I stupid

#

Ok it does work normally, I just forgot powershell is funny

azure plank
# silent knoll hm tests are failing

Oh wait that does make sense, the reason I used the normalized version in the first place is so that all the newlines would be \n and we didn't have to worry about \r breaking the parser

#

The actual fix would be passing in the encoding and using it instead of always defaulting to utf-8 in src_contents.encode("utf-8")

silent knoll
azure plank
#

It's the read call, reads in python by default make all newlines into \ns

silent knoll
#

interesting

azure plank
#

return tiow.read(), encoding, newline

silent knoll
#

why isn't that done the first time it's called then

azure plank
#

hm, it should be? src_contents, encoding, newline = decode_bytes(buf.read(), mode)

silent knoll
#

odd

azure plank
#

It might be because some calling paths don't go through that first decode_bytes call and skip straight to _format_str_once

silent knoll
#

oh yeah

#

places are calling format_str and not format_file_in_place

azure plank
#

So I think we should add an encoding: str = "utf-8" to _format_str_once and thread that through format_file_contents from those two other places that use decode_bytes (with the default argument since otherwise someone/our code will complain about the new arg)

silent knoll
#

maybe we could change format_file_in_place to just get the encoding and newlines, and pass the undecoded version to format_str, and decode in _format_str_once again

#

i have to go but will look at this more this evening, or you can feel free to push to my pr if you want

azure plank
#

Sounds good

azure plank
#

Thinking about it more I've found a better solution: The reason everything is going wrong is because while _format_str_once encoded the str as utf-8, tokenize.detect_encoding still sees the magic iso-8859-1 encoding sequence, so we decode the utf-8 with iso-8859-1, causing the whole mess. So the solution that prevents a bunch of non-local changes is to instead add an encoding_override parameter to decode_bytes that skips tokenize.detect_encoding if present to prevent the magic encoding sequence from messing it up

#

Though there is I guess a possible edge case? If tokenize.detect_encoding eats the first couple lines then the newline detection in decode_bytes actually is using not the first newline. Oh well I guess.

#

I also wonder if there are any encoding schemes that use newlines that aren't the standard bytes, which would make our newlines tests always give \n

runic monolith
#

@azure plank hello sir

azure plank
#

o/

runic monolith
azure plank
#

!rule 6 9

late dewBOT
#

6. Do not post unapproved advertising.

9. Do not offer or ask for paid work of any kind.

azure plank
#

I pushed the updated fix, but CI is still unhappy with the file :(

#

I guess I'll have tofigure out how to actually make it a test_black test

silent knoll
#

I actually already did that but hadn't pushed because it wasn't working yet

azure plank
#

Hopefully it will with our powers combined?

silent knoll
#

I'm realizing I might need to construct a buffer and convert it to a string

#

For now I edited it using a hex editor, let's see if that works

azure plank
#

Hm, it should already be right, since I used .write with a file opened in wb mode

silent knoll
#

tests/test_black.py needs to be readable as a utf8 file

azure plank
#

Oh if you're doing it in test black just use a b string

#

I was talking about in cases

silent knoll
#

ah

azure plank
#

That's what I was struggling on, we can't really use any of the existing things since they take strings and we want to test the double encoding, so it has to be a tempfle

#

Which are confusing ;-;

#

Unless you found some way around that

silent knoll
#

Lemme try running it with format_file_in_place instead

#

looks like it's working now

#

just forgot to format self

#

gtg

azure plank
#

gaming

#

I wonder if now that it's working in the data dir if it would be worth moving to a temp file so the binary data is more clearly exposed/editable, or if we should just accept that it works in the data dir and move on

silent knoll
#

i mean, i thought it was easy enough to use a hex editor, but either way if you can figure it out

#

also, I'm not sure why github isn't properly rendering it in first_line.py, it has the same hex data

azure plank
#

That's my main point of concern, the fact that some editors just perish

#

So if in the future we ever need to update these tests for whatever reason that persons editor may decide to be stupid and re-encode it as utf-8

silent knoll
#

we could add an assertion that the files have non-utf8 data

azure plank
#

Let me see if I can make it work with tempfile + the ff, and if not lets go with that

#

Got it working :)

#

This works, but the error you get when it fails kinda sucks thanks to the assertFalse just being "true is not false"

        with NamedTemporaryFile(delete_on_close=False) as first_line:
            first_line.write(
                b"# -*- coding: iso-8859-1 -*-\n# 2002-11-22 J\xfcrgen Hermann"
                b" <jh@web.de>\n"
            )
            first_line.close()
            self.assertFalse(ff(Path(first_line.name)))
        with NamedTemporaryFile(delete_on_close=False) as second_line:
            second_line.write(
                b"#! /usr/bin/env python3\n# -*- coding: iso-8859-1 -*-\n# 2002-11-22"
                b" J\xfcrgen Hermann <jh@web.de>\n"
            )
            second_line.close()
            self.assertFalse(ff(Path(second_line.name)))
#

though that also applies to the existing apporach, I wonder if there's a way to fix it

silent knoll
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

I'm seeing an issue when running nbqa black on Jupyter notebooks:

  1. In GitHub Actions, running:

    nbqa black . -l 120 --check --diff
    

    reports that some .ipynb files would be reformatted.

  2. Running:

    nbqa black . -l 120
    

    indicates the notebooks have been reformatted.

  3. However, running --check --diff again still reports the same notebooks need reformatting.

    In other words, nbqa black . -l 120 doesn't seem to resolve the formatting i...

silent knoll
flat krakenBOT
#

Is this related to a problem? Please describe.

There's no page detailing how to set up Black with Jupyter. There's parts of the docs that mention it, but there's nowhere that says "hey, Black supports Jupyter notebooks natively, here's how to set up, configure, and use it"

Describe the solution you'd like

A new page that has all that information. Most of the Jupyter information should be moved to that page instead of being scattered around or duplicated.

ie, right now the inst...

dense jungle
azure plank
#

I agree on thinking about it some more. A couple comments is all things considered fairly minor. If we were seeing a constant influx of new duplicate issues about it that would be cause for more concern, but it seems most people's CI should have run by now and they don't care.

#

My main concern right now (besides figuring out where the cases test infra is for the double encoding bug) is actually figuring out what to do about the playground, since it's very :/ that we still haven't been able to get that updated

flat krakenBOT
#

This PR adds a dedicated Jupyter integration page to the documentation and moves all Jupyter-related installation and usage instructions there.
Previously, information about Jupyter support was scattered across the docs and mentioned only in the installation page.

Now, users can find all details about setting up, configuring, and using Black with Jupyter notebooks in one place.

issue #4967.

silent knoll
#

We haven't gotten any other issues, so I think it's good to move on and not plan on releasing a patch

#

If we feel it's urgent we can release a 26.2.0 in not too long

silent knoll
winged mulch
silent knoll
winged mulch
#

oke

plain atlas
#

don't even try

#

darn bots already getting banned

flat krakenBOT
silent knoll
#

fuzz...

silent knoll
#

MRE for fuzz error:

if True:
    if True\
:
        pass

Doesn't matter where in the line the backslash is or what kind of block it is, the bug is triggered whenever the line after the backslash is indented less than the line the backslash is on

(so something like this is fine:

if True\
:
    pass
``` because the : is on the same level as the if)

there was also a mix of `\r` and `\n` in the generated code but it doesn't make a difference here
silent knoll
#

i think it's something that needs to be fixed in pytokens

lavish scroll
#

if you were able to get an MRE with pytokens that'd be great

#

if pytokens output is different from builtin tokenize output on python 3.14, then we should fix it in pytokens. else, fix in black

silent knoll
lavish scroll
#

great. I'll take that up

flat krakenBOT
#

Description

Closes #4967

This PR consolidates scattered Jupyter Notebook documentation into a comprehensive, dedicated page at docs/usage_and_configuration/jupyter_notebooks.md.

Problem: Currently, Jupyter-related information is scattered across multiple documentation files (README.md, getting_started.md, FAQ, source_version_control.md), making it difficult for users to find complete information about using Black with Jupyter Notebooks.

Solution: Created a single aut...

silent knoll
#

I feel like we should stop running Fuzz on PRs, it tends to just start failing unpredictability and usually unrelated to the PR

#

I wonder if it would be difficult to have the action open an issue instead of crash

barren flint
#

Hello, everyone, how i will get open issues so that i can contribute.

#

it seems every issue is solved or closed

young sand
#

These workflows run on a nightly cron job rather than on PRs, though

silent knoll
#

will make a pr

lavish scroll
#

@silent knoll I'm making a primer-like for pytokens, will be great to have that up to test your patch

silent knoll
#

good to know

#

right now i'm running --validate against black

flat krakenBOT
flat krakenBOT
#

Describe the bug

Black cannot parse when the first line following the function definition is not indented. If otherwise indented improperly, it works and adjusts as expected.

To Reproduce

Simple invocation with or without the --target-version parameter

For example, take this code as main.py:

#!/usr/bin/env python

def main():
print("Hello from test!")


if __name__ == "__main__":
    main()

And run it with these arguments:

$ black main.py --target-vers...
silent knoll
dense jungle
elder tusk
#

probably that black would add the whitespace

radiant linden
#

hola

flat krakenBOT
#

Description

Fixes #4945.

The parser did not correctly handle multiline statements that use explicit
backslash (\) line continuations. In certain cases, continued lines were
treated as separate logical units instead of a single statement, leading to
incorrect tokenization and formatting behavior.

This issue could surface when multiple backslash-continued lines were combined
with indentation or nested constructs, even though the input was valid Python
syntax.

This PR fixe...

flat krakenBOT
agile vale
# flat kraken

Hi! I've opened PR #4971 which consolidates Jupyter Notebook documentation into a single comprehensive page. It's a documentation-only change (no code changes). The changelog CI check is failing because I didn't add a CHANGES.md entry - I assumed docs-only changes don't need one. Could a maintainer add the 'skip news' label to the PR, or should I add a changelog entry instead? Thanks!

carmine coyote
#

Hello there! I have an

$ uv run black f.py -vvv
Identified `p` as project root containing a .git directory.
Using configuration from project root.
line_length: 100
target_version: ['py312', 'py313', 'py314']
Found input source: "f.py"
Traceback (most recent call last):
  File "src/black/__init__.py", line 909, in reformat_one
  File "src/black/__init__.py", line 952, in format_file_in_place
  File "src/black/__init__.py", line 1078, in format_file_contents
  File "src/black/__init__.py", line 1214, in format_str
  File "src/black/__init__.py", line 1225, in _format_str_once
  File "src/black/parsing.py", line 98, in lib2to3_parse
black.parsing.InvalidInput: Cannot parse for target version Python 3.14: 25:12:             <!DOCTYPE html>
error: cannot format f.py: Cannot parse for target version Python 3.14: 25:12:             <!DOCTYPE html>

Oh no! :boom: :broken_heart: :boom:
1 file failed to reformat.

issue - but https://black.vercel.app/?version=main works as expected ๐Ÿ˜•
... but it is outdated (Stable: 25.1.0 | Main: @314f8c, https://github.com/psf/black/commit/314f8c is from May 2025)

I am guessing that I have the correct executable - and not some "messed up" one

{ url = "https://files.pythonhosted.org/packages/e4/3d/51bdb3ecbfadfaf825ec0c75e1de6077422b4afa2091c6c9ba34fbfc0c2d/black-26.1.0-py3-none-any.whl", hash = "sha256:1054e8e47ebd686e078c0bb0eaf31e6ce69c966058d122f2c0c950311f9f3ede", ...

Idk - should I open an issue to discuss? or talk here?

dense jungle
carmine coyote
#

In that case, would you consider removing it from your instructions? ๐Ÿ™

dense jungle
#

Yeah we probably should

carmine coyote
#

Basically it seems that black doesn't like

with open(d / "DO_NOT_EDIT", "w") as f:
    f.write(
        textwrap.dedent(
            """\
            # Do Not Edit
            """
        )
    )

and prefers

with open(d / "DO_NOT_EDIT", "w") as f:
    f.write(
        textwrap.dedent("""\
            # Do Not Edit
            """)
    )

instead (which I don't like, but I get it, black is opinionated)

#

So I am trying to "outsmart" it by

with open(d / "DO_NOT_EDIT", "w") as f:
    f.write(
        textwrap.dedent(  # fmt: skip
            """\
            # Do Not Edit
            """
        )
    )

in the original case my string literal included <!DOCTYPE html>; in this case, I get

$ uv run black f.py -vvv
Identified `p` as project root containing a .git directory.
Using configuration from project root.
line_length: 100
target_version: ['py312', 'py313', 'py314']
Found input source: "f.py"
Traceback (most recent call last):
  File "src/black/__init__.py", line 909, in reformat_one
  File "src/black/__init__.py", line 952, in format_file_in_place
  File "src/black/__init__.py", line 1078, in format_file_contents
  File "src/black/__init__.py", line 1214, in format_str
  File "src/black/__init__.py", line 1225, in _format_str_once
  File "src/black/parsing.py", line 98, in lib2to3_parse
black.parsing.InvalidInput: Cannot parse for target version Python 3.14: 22:0: Unexpected EOF in multi-line statement
error: cannot format f.py: Cannot parse for target version Python 3.14: 22:0: Unexpected EOF in multi-line statement

Oh no! ๐Ÿ’ฅ ๐Ÿ’” ๐Ÿ’ฅ
1 file failed to reformat.
flat krakenBOT
flat krakenBOT
#

Description

A small followup to #4928 with a few more things I noticed since then

Notable changes:

  • Change Fuzz to run on schedule & on push instead of on PRs, and open an issue with failures
  • Add a post release workflow that adds a new changelog, and move the update-stable job to it
  • Pinned most dev/ci depedencies to a specific version, except for bigger projects with lots of updates
  • For runtime dependencies, I changed most >= to ~= to avoid bumping major versions
    I did...
silent knoll
#

i may still be misunderstanding how python dependency resolution works

lavish scroll
#

but we should be using 0.4.1 right now afaik

silent knoll
#

pytokens might be an exception though since it's so fundamental to black and it's unlikely to be used by anything else. not sure. again i need to do more research on dep resolution

dense jungle
#

yeah pytokens is one where it might make sense since the projects are closely tied

#

but if we add a bound now resolvers might in the future give people old black + new pytokens

#

which is probably the worst combination

silent knoll
#

hmm

#

wouldn't that be a possibility anyway?

little parrot
#

<@&831776746206265384> ^

civic bane
#

!compban 1146373822493241375

late dewBOT
#

:incoming_envelope: :ok_hand: applied ban to @upper raft until <t:1770337338:f> (4 days).

dense jungle
silent knoll
#

i believe it could happen if someone were to pin black to an old version, which obviously isn't supported but it's probably relatively common if people don't like a chance black made one version

#

if we added an upper bond it'd still be old but at least it should be old versions of both

lavish scroll
dense jungle
#

no

carmine coyote
flat krakenBOT
#

Describe the bug

Historic behaviour:

โฏ black --version && black --diff tests/test_cases/not_utf8.py
black, 23.9.1 (compiled: no)
Python (CPython) 3.13.5
All done! โœจ ๐Ÿฐ โœจ
1 file would be left unchanged.
โฏ black --version && black --diff tests/test_cases/not_utf8.py
black, 25.12.0 (compiled: no)
Python (CPython) 3.13.5
All done! โœจ ๐Ÿฐ โœจ
1 file would be left unchanged.

New behaviour:

โฏ black --version && black --diff tests/test_cases/not_utf8.py
black, 26.1.0 (compiled:...
silent knoll
#

Probably should release a 26.2.0 at some point then

silent knoll
flat krakenBOT
#

Describe the bug

Running Black with Python 3.12 but targeting Python 3.14 on a file containing an except clause with multiple parenthesized exception types fails with an internal error.

To Reproduce

These steps:

python3.12 -m venv venv
source venv/bin/activate
pip install black
printf "%s\n" 'try:' ' 1 / 0' 'except (a, b):' ' pass' >test.py
black -t py314 test.py

result in this error:

error: cannot format test.py: INTERNAL ERROR: Black 26.1.0 on Python (CPython...
glad pilot
# flat kraken

@silent knoll Can you clarify what it is that you're advocating for on this python3.12 -m black -t py314 issue? Am I correct in understanding that you're suggesting that Black should emit a warning saying that it may fail due to the use of -t with --safe, but then keep running and go on to fail with the same INTERNAL ERROR that it fails with today?

glad pilot
#

(I figure it's easier to have a conversation here that might involve some back and forth than on the issue ๐Ÿ™‚)

elder tusk
#

printing a warning with version mismatch instead of doing the safety check seems like a good idea to me (esp since black really is fairly safe these days)

#

mypy will be shifting to some new parsing tech soon and maybe we could reuse that instead of stdlib, would maybe be faster too (tho iirc we exclude a few things from ast safety and would need to figure out the equivalent)

glad pilot
#

Some whitespace changes to docstrings are definitely excluded from the AST safety check

flat krakenBOT
flat krakenBOT
#

Summary

Fixes #4980

When --target-version is set to a newer Python than the one running Black, the AST safety check fails with a misleading "INTERNAL ERROR: produced invalid code. Please report a bug" message. This PR:

  • Emits a clear warning at startup explaining that the running Python cannot parse syntax for the target version, with three actionable workarounds: (1) run Black with the target Python, (2) lower the target version, or (3) use --fast
  • Replaces the misleading "IN...
flat krakenBOT
flat krakenBOT
#

Summary

This PR adds a dedicated documentation page for Jupyter Notebooks usage, consolidating all Jupyter-related information that was previously scattered across multiple documentation files.

Fixes #4967

Changes

  • New file: docs/usage_and_configuration/jupyter_notebooks.md - A comprehensive guide covering:
    • Installation instructions (pip and pipx)
    • Basic usage and examples
    • Command-line options (--ipynb, --python-cell-magics)
    • Configuration via `pyproject.tom...
#

Summary

This PR adds documentation about third-party tools that can format doctests and code in docstrings, addressing issue #3083.

Fixes #3083

Changes

  • Added new section "Formatting doctests and docstrings" to docs/integrations/index.md

  • Documented blacken-docs tool:

    • Purpose: Formats code blocks in documentation files and docstrings
    • Supports doctests in Markdown/reStructuredText blocks
    • Installation and usage examples
  • Documented blackdoc tool:

    • Purpos...
#

Summary

This PR expands the documentation for preview style features by adding detailed sections with code examples, bringing them in line with how unstable features are documented.

Fixes #4429

Changes

Added detailed documentation sections for two preview features that previously only had single-line descriptions:

1. wrap_comprehension_in feature

  • New section: "Wrapping long comprehension in clauses"
  • Explains when and why comprehensions are wrapped
  • Includes before/...
flat krakenBOT
hollow temple
#

yo guys is github down for all of you ?

#

i'm getting this too many time

azure plank
hollow temple
flat krakenBOT
flat krakenBOT
#

Description

Add a new documentattion section explaining how to format Jupyter notebook using nbqa.Includes instructions and examples usage with nbqa black. I have gone through the official documentation to study the documentation structure and codes.

Checklist - did you ...

  • [ ] 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?
  • ...
flat krakenBOT
#

Description

My fix improves Black's syntex error reporting when parsing fails.

I have made a test file to see the error messege that reports

currently when Black encounters invalid python syntex, it reports something like this

The changes i have changes to enhance the error message reporting

  1. Reporting by lines and column so maintainer can easily find the error
  2. Displaying the error line and using caret(^) pointing to show exactly where the error is

...

flat krakenBOT
#

Summary

  • Fixes #4640
  • Black crashes with "Opening paren not found in 'leaves'" when a standalone comment appears inside parentheses in a lambda default argument with a trailing comma
  • Root cause: after line splitting, the opening bracket ends up in a different Line object than the closing bracket, so is_one_sequence_between() can't find it via identity comparison in the current line's leaves

Fix

Return False instead of raising LookupError when the opening bracket isn't fou...

flat krakenBOT
#

Describe the bug

Running Black on the example code below introduces a change in the meaning of the code.

To Reproduce

For example, take this code:

assert (
    # my comment
    my_var == 999 if abc == "TEST" else 0
)

Black updates it to:

assert (
    # my comment
    my_var == 999
    if abc == "TEST"
    else 0
)

This introduces a bug:

  • Original code: when abc == "TEST" this results in assert my_var == 0
  • Updated code: when abc == "TEST" t...
flat krakenBOT
#

Description

While I was going about writing a new tool for cython that would help me to format it's language and code neatly I was mainly trying to sift though this code in order to try and come up with some logical solutions or approaches for making a code / file writer since I'm implementing a new cython code formatting tool (and a few other cleaver tools in it's toolbag) since a formatting feature (as far as I am aware of) for cython does not exist. While attempting to read thou...

flat krakenBOT
flat krakenBOT
flat krakenBOT
#

In _calculate_lines_mappings, when the first matching_blocks entry doesn't start at offset 0, the content before it is different between original and modified. This block should be marked as is_changed_block=True, but it's currently marked False.

What goes wrong

The adjusted_lines function uses is_changed_block to decide how to remap line ranges:

  • For unchanged blocks, it applies a linear offset
  • For changed blocks, it expands to the full block extent

When the first chang...

#

In normalize_fstring_quotes, the loop that checks whether quote normalization would introduce more escaping overwrites orig_escape_count and new_escape_count on each iteration:

for middle, new_segment in zip(middles, new_segments, strict=True):
    orig_escape_count = middle.value.count("\\")
    new_escape_count = new_segment.count("\\")

if new_escape_count > orig_escape_count:
    return middles, quote  # Do not introduce more escaping

After the loop finishes, both va...

peak ridge
#

Hello how to learn python

flat krakenBOT
#

Description

I missed this when reviewing #4987, but these docs were wrong too.

Checklist - did you ...

  • [-] 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?
  • [y] Add new / update outdated documentation?
flat krakenBOT
#

Description

Black produces two different idempotent outputs for consecutive @overload function definitions depending on the initial whitespace between them. Both outputs are stable (running Black again produces no changes), but they correspond to the same AST.

This means Black does not converge to a single canonical form for this pattern โ€” the output depends on the input formatting, not only on the AST.

Steps to reproduce

Input A โ€” no blank lines between overloads:

flat krakenBOT
flat krakenBOT
#

Description

Closes #5002.
Removes the Atom/Nuclide editor integration section from the documentation, as these projects have been sunset and the linked resources now resolve to the Atom sunset announcement rather than active integration tooling.

Checklist - did you ...

  • [x] Implement any code style changes under the --preview style, following the stability policy?
  • [ ] Add an entry in CHANGES.md if necessary?
  • [x] Add / update tests if necessary?
  • [x] Add ...
flat krakenBOT
#

Description

Non-user facing change: fix the docs/Makefile recipe syntax introduced in b41acd6ebbe76e18b49286166924f73f01c3fd02

Each line in the recipe must start with a tab

https://www.gnu.org/software/make/manual/html_node/Recipe-Syntax.html

Checklist - did you ...

  • [ ] 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 ne...
flat krakenBOT
flat krakenBOT
#

Description

This PR improves the clarity of the error message raised when no target Python versions are specified.
Previously, the message referenced the internal variable name:
target_versions must not be empty
The updated message is more user-facing and clearer:
At least one target Python version must be specified.
This change improves readability without modifying behaviour.

Checklist - did you ...

  • [x] Implement any code style changes under the --preview...
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Summary

Add a comprehensive guide for using Black with Jupyter Notebooks, consolidating information that was previously scattered across multiple documentation pages.

Changes

  • New file: docs/guides/using_black_with_jupyter_notebooks.md โ€” a dedicated guide covering:
    • Installation with the jupyter extra
    • Basic usage and stdin formatting with --ipynb
    • How Black handles notebook cells
    • Cell magics and custom python cell magics (--python-cell-magics)
    • Which cel...
flat krakenBOT
#

Summary

This PR addresses issue #3083 by adding a new FAQ entry that documents Black's limitation with doctest formatting and mentions alternative tools users can use.

Changes

  • Added new FAQ section "Does Black format doctests?"
  • Explains that Black does not format doctests in docstrings (references issues #745 and #144)
  • Mentions two alternative tools:
    • docformatter - formats docstrings to follow PEP 257
    • doctestfmt - formats doctest code blocks
  • Notes that these t...
flat krakenBOT
#

Description

Hatch fails with virtualenv 21.0.0 https://github.com/pypa/hatch/issues/2193
(We don't depend on virtualenv directly, only through Hatch)
Hatch released an update that fixes this issue, but Docker builds started failing when Hatch 1.16 was released, so we pinned it.
TODO: Investigate Hatch 1.16 errors, unpin hatch, and remove dependency on virtualenv
Merging to unblock CI

Checklist - did you ...

  • [-] Implement any code style changes under the `--...
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Updated GitHub Actions to use version 6 for checkout and setup-python actions.

Description

Checklist - did you ...

  • [ ] 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?
flat krakenBOT
flat krakenBOT
#

โš ๏ธ I'm pretty unfamiliar with Black's codebase, so this patch was mostly authored by Claude. I verified that it has extensive test coverage, that it has the effect that I want, and that it's well documented, but I can't say much about whether it's making the change in the right way or not.

Description

In .pyi stub files, Black currently has no special handling for groups of consecutive decorated functions that share the same name. This comes up quite often with @overload groups,...

flat krakenBOT
flat krakenBOT
#

Thanks for this change! I agree that the current heuristic isn't ideal, and this definitely looks like an improvement.
I agree that overloaded functions with the same name should be grouped together, but does it make sense to apply this to all decorators? Otherwise, we end up with code like this - multiple undecorated functions grouped together, then groups of one decorated function each:

It might make more sense to only add the padding if there's multiple functions with the same name, not...

flat krakenBOT
flat krakenBOT
#

Description

This updates the sentence in current_style.md that currently says Black's style is a "strict subset of PEP 8".

The new wording makes the intent explicit:

  • Black follows PEP 8 in spirit
  • it enforces a consistent subset of PEP 8 formatting recommendations
  • it does not implement every style rule covered by PEP 8

This addresses ambiguity reported in #1272.

Fixes #1272

Checklist

  • [x] Add new / update outdated documentation?
#

Description

This PR improves the pyproject.toml configuration section by clarifying how CLI options map to [tool.black], calling out that non-configurable options are explicitly marked in the option reference, and adding a more complete template example for common setup patterns.

Fixes #2487

Checklist

  • [x] Implement any code style changes under the --preview style, following the stability policy?
  • [x] Add an entry in CHANGES.md if necessary?
  • [x] Add / update test...
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Security: Zip Slip / Tar Slip path traversal in gallery/gallery.py archive extraction

Repository: psf/black
Report Date: 2026-03-06
Reported By: Vext Labs โ€” security@tryvext.com
Scanner: Vext Labs Opus SAST (AI-powered static analysis)
Confirmed Findings: 1

Summary

The download_and_extract function in gallery/gallery.py calls archive.extractall() on archives downloaded from PyPI or user-specified URLs wit...

flat krakenBOT
#

This hasn't seen wide use and has potential security issues (#5029).

Description

Checklist - did you ...

  • [ ] 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?
flat krakenBOT
#

Summary

  • tighten the GitHub Action's use_pyproject version parsing so only version specifiers are accepted
  • reject direct references such as black @ https://...
  • document the security guidance in the action docs and changelog

Validation

  • python -m compileall action/main.py

Notes

  • users of psf/black@stable receive the fixed action automatically
  • this concerns the action version, not the version of Black installed by the action
silent knoll
#

I think it makes sense to encourage developing on 3.11+ (which again, we already implicitly do, but the only thing that explicitly says another version is release.py being documented as 3.12+), maybe even 3.12, but there's no PEP735 way to declare requires-python for specific dependency groups

#

I use venv and pip as recommended in the docs without an issue, even though there's "conflciting" versions, since i'm using 3.12 pip doesn't care

#

But some tools (uv) might yell at you

#

And we also don't get Dependabot PRs for 3.11+-only deps (see: the cibuildwheel pr was supposed to bump in pyproject.toml too, but didn't because it's 3.11+ and we "support" 3.10+)

silent knoll
#

uv does support it but it's not standardized for other tools

The main solution I can think of would be to set requires-python dynamically so we can use whatever deps in [dependency-groups] with dependabot supporting them and without uv or other tools getting mad, and people installing the built project still get the correct constraints

silent knoll
delicate sparrow
flat krakenBOT
#

Description

Two minor fixes I noticed in the release process while 26.3 was being cut

  • Fix typo in post_release.yml labels
  • Add path for Jupyter notebooks guide in release script

Checklist - did you ...

  • [-] 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?
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Hello,

Just doing some cleanup. Removed four internal items that are defined but never referenced anywhere in the codebase:

  • matches_grammar() in parsing.py โ€”> utility function with zero callers
  • lib2to3_unparse() in parsing.py โ€”> utility function with zero callers
  • is_function_or_class() in nodes.py โ€”> function with zero callers (note: `is_pare...
flat krakenBOT
#

Is your feature request related to a problem? Please describe.

Python 3.15 adds support for the lazy soft keyword:

This has now available for testing in Python 3.15.0a7:

Describe the solution you'd like

Add support for the lazy soft keyword.

Describe alternatives you've considered

Wait for the ...

flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Description:
Remove dead code identified by Skylos static analysis:

  • token.py: Remove unused functions ISTERMINAL, ISNONTERMINAL, ISEOF
  • pgen.py: Remove unused debug methods dump_nfa and dump_dfa
  • pytree.py: Remove unused class attribute was_checked

Each finding was verified by searching the entire codebase for references โ€” no usages found. No behavioural changes.

Found using Skylos.

Checklist:

  • N/A: no code...
flat krakenBOT
flat krakenBOT
#

Describe the style change

Minimizing diffs is nice but this can come at the cost of reduced code readability.
Notably, when reading code on a monitor, there is only so much screen real estate.
So the more lines the code is spread on, the more the user needs to scroll to read it and with the scrolling, the higher the cognitive load (need to remember parts that are not on screen).

One could argue that keeping brackets vertically aligned helps understand the code structure but modern IDEs ...

flat krakenBOT
#

Description

Checklist - did you ...

  • [ ] 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?
flat krakenBOT
flat krakenBOT
flat krakenBOT
#
  1. scripts/fuzz.py: fixed typo in FUNCTION NAME. I searched for references to the function, and the only references were within the module.

  2. What motivated starting this PR: in docs, fix Windows path syntax. C:\\ will usually work because the OS treats consecutive separators as only one separator. Nevertheless, C:\ is the correct syntax. See, e.g., https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file

  3. Since I had the repo open, I fixed some typos. Other than the ty...

flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Description

This PR addresses two documentation improvements:

1. Add Neovim integration guide (fixes #3960)

Neovim has grown significantly in popularity but was completely missing from the editor integrations docs. The Vim section only covers Vim-specific plugins.

The new Neovim section covers three common approaches:

  • conform.nvim โ€” the most popular modern formatter plugin for Neovim, with a format-on-save e...
jade thicket
#

๐Ÿ’ฏ

flat krakenBOT
#

Summary

  • Prefix all version headings in CHANGES.md with "Version " (e.g., ## Version 26.3.1) so that MyST-Parser generates stable, meaningful anchor IDs (like #version-2631) instead of the current generic auto-incremented ones (#id1, #id2, etc.) that shift with every release
  • Update scripts/release.py to produce ## Version X.Y.Z headings when cutting new releases
  • Update scripts/check_version_in_basics_example.py and scripts/check_pre_commit_rev_in_example.py to strip...
flat krakenBOT
flat krakenBOT
#

Description

Rename the CliRunner import to avoid future mistakes

In Debian we are still on the older Click version, so we need this patch

Checklist - did you ...

  • [x] Implement any code style changes under the --preview style, following the stability policy?
  • [x] Add an entry in CHANGES.md if necessary?
  • [x] Add / update tests if necessary?
  • [x] Add new / update outdated documentation?
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Description

#3350 seems to be fixed on stable

Checklist - did you ...

  • [-] Implement any code style changes under the --preview style, following the stability policy?
  • [-] Add an entry in CHANGES.md if necessary?
  • [y] Add / update tests if necessary?
  • [-] Add new / update outdated documentation?
flat krakenBOT
flat krakenBOT
#

Problem

When blackd receives code with invalid f-strings (e.g. f"{}"), ast.parse() raises ASTSafetyError. This falls through to the generic except Exception handler, returning HTTP 500 (Internal Server Error).

It should return HTTP 400 (Bad Request), consistent with how InvalidInput is handled.

Solution

Add a specific except ASTSafetyError handler before the generic except Exception, returning HTTP 400.

Fixes #3616

flat krakenBOT
#

Description

Fix the capitalization of GitHub in the diff-shades helper docstring.

Summary

  • Fix a non-user-facing typo in an internal helper docstring.

Related issue

  • N/A, trivial wording fix.

Guideline alignment

  • Non-user-facing change, so no CHANGES.md entry is needed.

Validation/testing note

  • Not run; comment/docstring-only change.

Checklist - did you ...

  • [x] Implement any code style changes under the --preview style, following the stability policy?
  • [x] Add an ent...
flat krakenBOT
#

When I run my Flutter app locally using flutter run, Bluetooth scanning works perfectly โ€” all nearby devices are detected. However, when I publish the app to Google Play Store (closed testing, release AAB), no Bluetooth devices are detected at all, even though I have manually accepted every permission in the device settings.

I initially thought the issue was caused by a UUID filter I had in place (only scanning for devices with a specific UUID). I removed that filter and pushed...

flat krakenBOT
#

Description

Fix the wording in two nearby comments/docstrings by changing formattings to formatting.

Summary

  • Correct a non-user-facing typo in src/black/lines.py.

Related issue

  • N/A, trivial wording fix.

Guideline alignment

  • Non-user-facing change, so no CHANGES.md entry is needed.

Validation/testing note

  • Not run; comment/docstring-only change.

Checklist - did you ...

  • [x] Implement any code style changes under the --preview style, following the stability polic...
flat krakenBOT
#

Summary

Per @JelleZijlstra's review feedback on #5074, this PR splits the error handling instead of treating all ASTSafetyError as 400.

Changes

  1. New exception: SourceASTParseError (src/black/parsing.py)

    • Raised when the source file cannot be parsed by ast.parse() but was accepted by Black's more lenient lib2to3 parser
    • This is a user input issue, not a Black bug
  2. Updated assert_equivalent (src/black/__init__.py)

    • Source AST parse failure โ†’ `SourceA...
flat krakenBOT
#

Summary

  • The sublack plugin repository has been archived and is no longer maintained, but the SublimeText editor integration docs still recommend it as the primary option for SublimeText 3.
  • Updated the SublimeText section in docs/integrations/editors.md to recommend the LSP-based approach (python-lsp-black) as the primary option for all Sublime Text versions, and added a note marking sublack as archived/unmaintained.

Test plan

  • [ ] Verify...
flat krakenBOT
#

Describe the bug

When a large number of files are passed into black for formatting, it will process them and succeed, but will exit with code 1.

First noticed this in our CI when upgrading from python 3.14.2 to 3.14.3. It does not happen in 3.14.2

To Reproduce

I have the following dockerfile that can be used to reproduce the error. It generates 5000 file to pass into black. I'm not sure how many files need to be passed in, but I think it is above 2000.

You can build the con...

flat krakenBOT
lyric rune
#

wow

flat krakenBOT
#

Description

  • fix formattings -> formatting in a docstring sentence

Checklist - did you ...

  • [x] Implement any code style changes under the --preview style, following the stability policy?
  • [x] Add an entry in CHANGES.md if necessary?
  • [x] Add / update tests if necessary?
  • [x] Add new / update outdated documentation?

Notes

  • This is a docs/comment wording fix only.
  • No behavior change.
  • No tests were run for this docstring-only change.
  • No changelog entry neede...
flat krakenBOT
#

Description

Fixes a grammar typo in a documentation configuration comment in docs/conf.py:

  • "a ISBN number" -> "an ISBN number"

Checklist - did you ...

  • [x] Implement any code style changes under the --preview style, following the stability policy? (N/A: no code style change)
  • [x] Add an entry in CHANGES.md if necessary? (N/A: docs comment typo fix only)
  • [x] Add / update tests if necessary? (N/A: docs comment typo fix only)
  • [x] Add new / update outdated documentation?
silent knoll
#

stop

flat krakenBOT
flat krakenBOT
#

Description

In .pyi stub files, Black already enforces a blank line before a (decorated or undecorated) class definition in many situations. However, it fails to do so if the decorated class definition is immediately preceded by a function.

For this example file, saved as foo.pyi:

def a(): ...
class A: ...

@deco
class B: ...
@deco
class C: ...

def d(): ...

@deco
class D: ...

def e(): ...
@deco
class E: ...

Black applies this formatting on `ma...

flat krakenBOT
#

Description

Fixes #4280.

When a match/case statement uses the soft keyword case as a pattern name with a guard clause (case case if True:), Black crashed with Cannot parse at short line lengths (โ‰ค11).

Root cause: In normalize_invisible_parens, after the keyword case sets check_lpar=True, the pattern leaf case is wrapped in invisible parens. But because the pattern's value is also "case" (matching parens_after), check_lpar remained True, causing the guard node ...

flat krakenBOT
#

Description

  • Remove outdated comment from .pre-commit-config.yml
  • Update some workflow comments to fix some minor Zizmor audits
  • Add back hatch plugins for docker's sake

Checklist - did you ...

  • [-] 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?
flat krakenBOT
#

Summary

Fixes #4349.

When an assignment target contains brackets (e.g. indexed access like x[key] = expr), Black would wrap the right-hand side expression in unnecessary parentheses when the line was too long.

Before:

dictionary_of_arrays["long_key_name_for_the_example"][
    very_long_index_name, index_zero
] = (10 - 5)

After:

dictionary_of_arrays["long_key_name_for_the_example"][
    very_long_index_name, index_zero
] = 10 - 5

Details

The ro...

#

Summary

Fixes #4510.

When multi-line strings are followed by a pragma comment (like # type: ignore) on a surrounding bracket, the StringMerger would merge them into a single long line. Because pragma comments prevent line splitting, this produced lines that violate the line length limit with no way to fix them.

Before (black --unstable):

# Input:
(
    "A very very very very very very very very very very long string "
    "continued on the next line."
)  # type: igno...
#

Summary

Fixes #4511.

Black crashes with an AssertionError when formatting code that contains an f-string after a # fmt: off comment inside brackets:

(
# fmt: off
f"""
"""
# fmt: on
)

Error:

error: cannot format: {' ', 'r', 'f', 'o', ':', 'm', 't', '#', '\n'} is NOT a subset of {'U', 'r', 'f', 'u', 'F', 'R', 'b', 'B'}.

Root Cause

normalize_fmt_off runs before line generation and converts content between # fmt: off/# fmt: on into STANDALONE_COMMENT ...

silent knoll
#

nnnno

#

we can't bump mypy without manual changes

flat krakenBOT
#

I receive a message with text please report a bug on https://github.com/psf/black/issues during my execution. I'm runnig a project with python 3.13 with pyproject.toml and pre-commit.

I will show all project configs bellow.

pre-commmit configuration

file: .pre-commit-config.yaml

# Pre-commit hooks para gn-api-property-service
# Usa as ferramentas instaladas localmente via pyproject.toml [project.optional-dependencies.dev]
# Setup: pip install -e ".[dev]" && pre-commit instal...
flat krakenBOT
flat krakenBOT
#

Add AI agent governance

AI coding tools (Claude Code, Cursor, Copilot, Codex, Gemini) work better when
they know your repo's actual rules. This PR adds governance configs generated
from your existing CI pipeline โ€” no manual authoring needed.

What's included

Generated by crag from your CI config:

  • CLAUDE.md โ€” Claude Code instructions
  • AGENTS.md โ€” Universal standard (Codex, Aider, 60K+ repos)
  • .cursor/rules/governance.mdc โ€” Cursor rules
  • `.github/copilot-...
silent knoll
#

oop didnt realize it had already been closed :p

dense jungle
flat krakenBOT
#

Description

I believe this is the last thing for 3.15 support.
Also updates a few other metadata version lists.

Checklist - did you ...

  • [-] Implement any code style changes under the --preview style, following the stability policy?
  • [y] Add an entry in CHANGES.md if necessary?
  • [y] Add / update tests if necessary?
  • [y] Add new / update outdated documentation?
silent knoll
#

oh, it's not even stable until october

#

didnt realize

#

only one more release until beta & no more new features though

dense jungle
#

yes, though it's likely we'll get a flurry of new features right before the beta

#

there's potentially a few that will affect Black, like the ones for d-strings and for mixing sync/async context managers

#

so probably best to wait for beta 1

silent knoll
# flat kraken

it looks like libcst (needed for fuzz) doesn't yet support 3.15

#

eh it's still a while off

flat krakenBOT
#

Description

Small docs typo fix in the Black code style docs

Checklist

  • [X] Implement any code style changes under the --preview style, following the stability policy?
  • [X] Add an entry in CHANGES.md if necessary?
  • [X] Add / update tests if necessary?
  • [X] Add new / update outdated documentation?

Docs typo only; I believe this should not need a changelog entry.

flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Summary

The parse_line_ranges function previously accepted invalid ranges without raising errors:

  • "5-3" where START > END
  • "0-5" or "-1-5" with non-positive line numbers

This adds validation to raise a clear ValueError with a descriptive message when invalid ranges are provided, instead of silently accepting them and producing unexpected formatting behavior.

Test Plan

Added test_parse_line_ranges_valid and test_parse_line_ranges_invalid parametrized tests in `tests/...

flat krakenBOT
#

Repo: psf/black (โญ 38000)
Type: docs
Files changed: 3
Lines: +7/-7

What

Replaces 7 occurrences of the legacy https://www.python.org/dev/peps/pep-XXXX/ URLs in the documentation with the canonical https://peps.python.org/pep-XXXX/ form. Touches docs/the_black_code_style/current_style.md, docs/usage_and_configuration/the_basics.md, and docs/guides/using_black_with_other_tools.md.

Why

The python.org/dev/peps/ URLs are legacy and redirect to peps.python.org,...

flat krakenBOT
#

Describe the bug

# fmt: skip is not handled properly in all cases with black 26.1 and newer.

To Reproduce

Our project has this code:

class Body(model.BaseBody[
    "Keyword", "For", "While", "Group", "If", "Try", "Var", "Return", "Continue",
    "Break", "model.Message", "Error"
]):  # fmt: skip
    __slots__ = ()

Older black versions have left that alone as expected, but starting from black 26.1 the result is this:

class Body(model.BaseBody["Keyword", ...
flat krakenBOT
#

Summary

Fixes #5112

When # fmt: skip is placed on the colon line of a multi-line class (or def/if) statement, Black still reformatted it โ€” collapsing multi-line type parameters onto a single line.

Root cause: In _generate_ignored_nodes_from_fmt_skip(), line 647 unconditionally sets prev_sibling = parent.prev_sibling when the leaf (NEWLINE) has no previous sibling. This causes the function to take the per-sibling traversal path (which stops at any leaf containing a ne...

flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Description

Supersedes #5110

The python.org/dev/peps/ URLs are legacy and redirect to peps.python.org. Use the canonical URLs to
match the convention already used elsewhere in the codebase (e.g. CHANGES.md, src/black/files.py,
src/black/linegen.py).

Checklist - did you ...

  • [-] 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?
  • [y] Add new / u...
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Fixes #5112.\n\n## Summary\n- handle on compound statement colon lines before same-line backtracking\n- preserve multiline class/function headers as a whole when the skip comment is on the colon line\n- add a regression fixture for a multiline class base list\n\n## Test Plan\n- ................ [100%]
16 passed, 195 deselected in 1.29s\n- ........................................................................ [ 34%]
......................

flat krakenBOT
#

So I came across this that bothers me a lot that after reaching max line length all the arguments inside a method goes to next line.

I want only the last one goes to the next line like this:

#####This is a long comment. This should be wrapped to fit within 80 characters.
urlpatterns = [
    path("/", ArticleDetailView.as_view(), name="article_detail"),
    path("/edit/", ArticleUpdateView.as_view(), name="article_edit"),
    path("/delete/", ArticleDeleteView.as_view(), 
          name...
flat krakenBOT
silent knoll
#

good idea, but would require larger changes to the release workflow

#

currently we upload assets in an action triggered on release, but you can't add new assets to an immutable release

#

the action would have to publish the release itself and upload the assets at publish-time

unique swallow
#

-to

#

/ -top

#

= switcher /bootom/u

drowsy jolt
#

one approach is upload assets into a draft release, then publish the release when ready

young sand
#

I think that's what we do for Python-build-standalone, IIRC

flat krakenBOT
flat krakenBOT
#

Describe the bug

Parsing a multiline case statement with # fmt: skip fails with black >= 26.

To Reproduce

For example, take this code:

# file.py
match (method, *path.split("/")):

    case ("GET", "parent", _, "resource", resource_id) \
            | ("GET", "resource", resource_id):  # fmt: skip
        pass

    case _:
        pass

And run it with these arguments:

$ black file.py

The resulting error is:

error: cannot format file.py: Cannot pars...

flat krakenBOT
#

Summary

  • Fixes #5122: black >= 26 crashes with Cannot parse when # fmt: skip is applied to a multiline case pattern using backslash line continuation (\)
  • Added _prefix_has_real_newline() helper to distinguish real newlines from backslash-continued ones
  • Updated the backward-traversal loop in _generate_ignored_nodes_from_fmt_skip to use the new helper
  • Added test case fmtskip14.py covering the reported scenario and multiple backslash continuations

Root cause

`_gen...

flat krakenBOT
#

Description

This PR addresses two documentation improvements:

1. Add Neovim integration guide (fixes #3960)

Neovim has grown significantly in popularity but was completely missing from the editor integrations docs. The Vim section only covers Vim-specific plugins.

The new Neovim section covers three common approaches:

  • conform.nvim โ€” the most popular modern formatter plugin for Neovim, with a format-on-save e...
flat krakenBOT
flat krakenBOT
#

Summary

Fix high severity security issue in autoload/black.vim.

Vulnerability

Field Value
ID V-002
Severity HIGH
Scanner multi_agent_ai
Rule V-002
File autoload/black.vim:77

Description: The Vim plugin at autoload/black.vim invokes subprocess.run at lines 77 and 152 to call the black formatter. If the command arguments include Vim variables derived from the file path, buffer name, or other editor-suppl...

drowsy jolt
#

Now Python 3.15 beta is out, would be nice to have a new Black release at some point to support lazy and unpacking in comprehensions. I think it's already supported in main?

quartz acorn
#

Hey Iโ€™m white can I talk here anyway?

dense jungle
dense jungle
#

we do already support PEPs 798 and 810

drowsy jolt
#

A pure Python release of Black would still be useful

elder tusk
#

fwiw i think mypyc should work on 3.15, it is just not itself compiled (but we shouldn't be uploading wheels prior to rc either)

flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Description

Fixes #4733.

Black crashes with INTERNAL ERROR: produced different code on the second pass of the formatter on inputs like:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: list[  # pyright: ignore[...]
    int
] = []

Root cause

The collapsed line is one char over the limit thanks to the inline comment
on the subscript's [. That's enough for run_transformer to try the
FORCE_OPTIONAL_PARENTHESES second opinion, which wraps the annotation in
...

jade hollow
silent knoll
#

Also unrelated, but would there be any objection if I went through and closed all the multi-year stale PRs?

dense jungle
#

agree on both!

azure plank
#

Cleanup :)

silent knoll
#

hmmm...still failing on windows

flat krakenBOT
silent knoll
#

okay, they all got uploaded now

young sand
#

(I looked because I wanted to update typeshed's black pin, and typeshed runs black via pre-commit ๐Ÿ˜„)

drowsy jolt
#

Forget security (don't tell Seth...), this is actually the biggest benefit of having a monthly Dependabot/Renovate update the actions! Hash pin them too, again not for security, but to more likely guarantee a monthly PR ๐Ÿ™ƒ

dense jungle
#

I pushed some buttons and now it should run

drowsy jolt
#

The actions have not been updated for 3 years, and have a deprecation warning, so do need a bump

dense jungle
#

I don't think I can do that while listening to Pablo talk

drowsy jolt
#

Is he faster in English or Spanish?

dense jungle
#

surprisingly, in English

#

the Spanish was not too hard to follow

silent knoll
flat krakenBOT
flat krakenBOT
silent knoll
toxic stormBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Describe the bug

Current black downloaded from GitHub Releases shows the wrong version

To Reproduce

wget https://github.com/psf/black/releases/download/26.5.0/black_linux
chmod +x black_linux
./black_linux --version
black_linux, 0.1.dev1+g6d0fff0d5 (compiled: no)
Python (CPython) 3.13.13

Expected behavior

Old version shows:

./black --version
black, 26.3.1 (compiled: no)
Python (CPython) 3.13.12
flat krakenBOT
#

Describe the bug

Fails with INTERNAL ERROR on small file

To Reproduce
Contents of repro.py:

    a = 1  # type: ignore
    b = 1  # fmt: skip

Reproduce:

    $ black --check repro.py
    error: cannot format repro.py: INTERNAL ERROR: Black 26.5.0 on Python
    (CPython) 3.12.11 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_XXXX.log

The diff is
`...

silent knoll
#

I had to rerun the actions on main with the fixed workflow, but it uses the tagged commit for the version, and main wasn't tagged once I fixed the workflow

dense jungle
flat krakenBOT
#

Description

Fixes #5138.

When # fmt: skip converts a line into a standalone comment leaf, the backwards scan to find the start of that physical line could clear the prefix on the preceding NEWLINE/INDENT boundary. If the previous line had an inline comment such as # type: ignore, that comment was lost in the formatted output, causing Black's AST equivalence check to fail because the TypeIgnore node disappeared.

This preserves prefixes on the boundary leaf when they contain co...

dense jungle
#

^ that one looks pretty good, maybe let's land it and make a new clean release? @silent knoll

silent knoll
#

sure, sounds good

#

5124 and 5130 also seem ready to merge, if we want to include them

dense jungle
silent knoll
#

๐Ÿ‘ shades was passing with no changes before, fwiw, i just merged main to fix the test failures caused by the click update

flat krakenBOT
#

Thanks a lot for this! The code looks good, and all the shades changes look excellent!
One last small note: looking at the shades changes, it affects a lot more than just comprehensions (in a good way). Could the docs examples and the tests be updated to show some of those changes as well? (Also, a lot of the current test cases feel a bit redundant since they all share the same general structure with comprehensions, and a few of them could probably be removed)

flat krakenBOT
#

Description

Regression tests for #4513, fixed in #4903. Each of these three inputs used to blow up with Cannot parse: ...; on current main Black leaves them alone.

# Case A: triple-quoted string in parens with a leading `# fmt: skip`
(
# fmt: skip
"""
"""
)

# Case B: line-continued string in parens with a leading `# fmt: skip`
(
# fmt: skip
"\
"
)

# Case C (from @jenstroeger): `# fmt: skip` on the opening paren of a comparator
foo = (  # fmt: skip
    so...
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
flat krakenBOT
#

Fixes #4280

Description

When case case if True is formatted at a small line length, Black can make the pattern parentheses visible but also wrap the guard itself. That produces invalid output shaped like case case ( if True ):, and the second formatting pass fails to parse it.

This keeps guard nodes from being wrapped as a whole and allows the case-pattern split to keep the visible pattern parentheses instead. The guard remains outside the pattern parentheses, matching the expected...

flat krakenBOT
#

Description

Closes #3667.

Black expands leading tabs in multiline docstrings before it computes the docstring indentation to strip. That expansion used Python's default 8-column tab stops, while Black normalizes surrounding code indentation to 4 spaces. As a result, nested tabs inside indented docstrings were doubled in the formatted output.

This changes the docstring-only leading-tab expansion to use 4-space columns, updates the existing tabbed docstring fixture, and adds a focused re...

flat krakenBOT
#

Fixes #4506.

Description

In #4506, MeGaGiGaGon flagged that the longest fixture files in tests/data/cases/ are painful to work with. preview_long_strings.py and preview_long_strings__regression.py are both 1000+ lines: input and output for any given case sit hundreds of lines apart, and when a test fails the assertion points at the end-of-file mismatch with nothing tying it back to the original case.

MeGaGiGaGon's first proposal was to split big files into folders of number...

flat krakenBOT
flat krakenBOT
#

Closes #4180

Note: This is a partial fix โ€” automated tests did not fully pass.
Gray investigated the issue and produced a best-effort patch for human review.

What this PR fixes

Issue: additional newline added to docstring when the previous line length is less than the line length limit minus 1

Issue description:

before

"""
87 characters ............................................................................
"""

after

"""
87 characters...
austere lava
#

o/

plain atlas
#

Oh nice

#

What files do you use to configure black?

#

I use pyproject.toml

prime gull
#

Welcome, people of the black formatter!

marble citrus
#

hey

onyx furnace
#

Hello

subtle mica
#

๐Ÿ‘‹

hazy spire
#

whats black-formatter

desert remnant
#

๐Ÿ‘‹

solid condor
#

๐Ÿ’™

marble citrus
#

i dont even know python why am i here

night hollow
#

Hello World!

prime gull
marble citrus
#

got pinged

woeful orbit
#

Hi

silent apex
neon loom
#

Howdy all

silent apex
#

I find it easiest to keep everything in one place

solid condor
late dewBOT
#

pyproject.toml lines 55 to 58

[tool.black]
line-length = 99
target-version = ['py38']
include = '\.pyi?$'```
silent apex
mint barn
#

ih

onyx furnace
#

Will it be available as a vsc extension in the future?

solid condor
#

the website and github issues are and some people will check pins first

mortal igloo
#

o/

bright glacier
#

Hi, it's @bright glacier ๐Ÿ‘‹

prime gull
mortal igloo
#

True

solid condor
#

yeah ๐Ÿ˜›

ripe jackal
#

Welcome! c:

idle grail
#

๐Ÿ–ค

bright glacier
#

It is what it is tho

rocky wharf
#

Hi :D

vivid pasture
#

o/

mellow grail
#

black is so good

jagged pivot
#

Black developers and users are invited to use this channel
very open to misinterpretation

bright glacier
#

yep, typically why I use "maintainers of black" as example

jagged pivot
#

yeah, perhaps "Users and developers of black are invited to use this channel..."

mellow grail
#

O.o

bright glacier
halcyon latch
#

_>
<_<
wdym it's always said that suggestion....

plain atlas
echo eagle
plain atlas
#

and right now vsc is causing me some issues so im not gonna talk about it atm.โ€ฆ

halcyon latch
bright glacier
#

We gave up on using IRC as our platform, it was just me and cooper on there most of the time anyway

halcyon latch
#

I miss the IRC days, but ngl, I love the emojis of discord bongocat

plain atlas
#

lol i know a still active irc

neon loom
#

Yeah, more messages here than the IRC cahnnel ever got already

#

*channel

jagged pivot
plain atlas
#

they sign in every day

#

its crazy

heavy summit
#

๐Ÿ‘‹

split merlin
#

Love black, been using it for ages for my personal projects. And help snippet for here.

rapid yoke
#

Hi, what is this?

heavy summit
rapid yoke
#

Thanks

bright glacier
#

This is a project specific channel, RIP IRC

rapid yoke
#

Seems odd to have a project specific channel

bright glacier
#

Whelp, we managed to convince Python Discord to start this so yeah

tribal thistle
#

Itโ€™s a new experiment

#

But weโ€™re hoping for the best

heavy summit
#

We might consider other partnerships in the future if this works out

tribal thistle
#

Glad to have yโ€™all here

neon juniper
rapid yoke
#

Glad to be here

neon loom
#

So others can join in and offer opinions and even help ๐Ÿ˜„

#

But I don't want to take over more generic channels on a busy day

rapid yoke
#

What, you input a code file and it outputs it in pep8 or something? I should really read the docs hang on

bright glacier
#

gasp

rapid yoke
#

Nice

neon juniper
#

I guess this isn't the place to be discussing tabs vs spaces haha

rapid yoke
#

4 spaces

silent apex
#

An editor that turns a tab into four spaces

heavy summit
#

Maybe we could add a black command that would format the code? Like
!black

def    foo  ()   ->   tuple [ int
        , str   ]        :
    return  (  ( bar )  )
late dewBOT
#
def foo() -> tuple[int, str]:
    return bar
neon juniper
#

haha

rapid yoke
#

Wait did u echo that?

delicate marsh
#

hahaha that's a fun idea

short forge
#

Eval args mayhap?

neon loom
#

@solid adder has done most. But the leading 4-5 contributors are here

rapid yoke
#

Lol

bright glacier
delicate marsh
rapid yoke
#

I might work on the thing that fix error suggested

austere lava
#

I've been outed

bright glacier
#

lol

#

apologies

heavy summit
neon juniper
#

oh no

bright glacier
#

why does that even exist

rapid yoke
#

๐Ÿคฎ

heavy summit
#

there's also a way to move the % and == to the right, but I'm lazy

austere lava
rapid yoke
#

Thatโ€™s actually pretty cool, not as actual code but still

bright glacier
#

I mean, you would've been uncovered eventually zsol ๐Ÿ˜‰

plain atlas
#

and run a blackd server

split merlin
#

Mostly recognise you from helping ichard

bright glacier
#

I have not looked at it in quite a while

plain atlas
#

yay finally someone gave you your roles

wooden socket
#

is there some problem with type annotations?
I'm getting a "Cannot parse" error on this line:

def write_event(session: str, type: str, xcoord: int, ycoord: int, direction: int, timestamp=None: str) -> None:```
heavy summit
#

are you ok? you're all purple

halcyon latch
#

so much purple in this channel, I love it lemon_hearteyes

bright glacier
heavy summit
tribal thistle
#

First legitimate help question. That was quick.

austere lava
plain atlas
#

can the black partner role be colored black

exotic swift
#

Hello

wooden socket
rapid yoke
#

@bright glacier what black magic is going on with your colours?

bright glacier
#

hmm, looks like a glitch lol

rapid yoke
#

Yeah it seems to have fixed itself when I reloaded discord, sorry for the ping lol

bright glacier
#

Ah, don't worry, it's not like I'm drowning in notifications already (email walking behind about to jump me)

rapid yoke
#

Lmao

bright glacier
#

See topic

spring egret
#

what is black formatter

bright glacier
#

Oh ok, so we wanted a more open and transparent area for our communication, we used to use a mix of private chats and IRC but they weren't great for reasons I don't want to get into right now

spring egret
#

Ooo

neon juniper
spring egret
#

Okay thank you

neon juniper
#

which is pretty in its own way...

bright glacier
#

nestingville

#

oops, did not mean to reply

halcyon latch
#

@little folioAre you familiar with PEP8, Python's style guide? This is a fantastic tool that will help your code stay within those guidelines making it more readable for everyone.

late dewBOT
#
**PEP 8 - Style Guide for Python Code**
Status

Active

Created

05-Jul-2001

Type

Process

neon juniper
#

yeah that seems fair haha

silent apex
#

That's better than what is was before

echo eagle
bright glacier
prime gull
neon juniper
rapid yoke
#

Hi sebastiaan ๐Ÿ‘‹

ionic nymph
#

black's amazing. I was a bit hesitant at first, because I was used to slightly different stylistic choices, but it just takes away having to discuss style.

bright glacier
dense jungle
#

I'd be happy to ๐Ÿ™‚

austere lava
#

Funny how that issue references the first stable release in april