# Black: what changed from 25 to 26 - Product: Black (https://whatsnew.fyi/product/black) - Vendor: Python Software Foundation - Range: changelog entries numbered after 25.12.0 up to and including 26.5.1, stable releases only - Entries below: 5 releases (newest first) - Resolved: 25 is 25.12.0 and 26 is 26.5.1, the newest stable release of each major we track - Carrying security changes: 1 · CVEs mentioned: 0 · Mentioning breaking changes: 0 · Removing or deprecating something: 1 - Page: https://whatsnew.fyi/product/black/compare/25...26 What's New is an index, not a publisher: every entry below links to the vendor's own release notes, which are the authoritative source. Entries are labelled where they are hand-curated sample data, pre-releases, or drawn from a secondary source such as a developer blog. Reuse: the summaries, labels and curation here are © What's New. Quote freely with attribution and a link back; wholesale republication of the corpus is not permitted — terms: https://whatsnew.fyi/terms. The vendors' own release notes remain their publishers'. ## What changed (44 changes, grouped by kind) ### Added #### 26.5.1 (2026-05-18) - Add Neovim integration guide covering conform.nvim, ALE, and simple command approaches #### 26.5.0 (2026-05-16) - Support for unpacking in comprehensions (PEP 798) and lazy imports (PEP 810), new syntactic features in Python 3.15 - Python 3.15 support - Add `SourceASTParseError` to distinguish source parse failures from internal safety errors #### 26.3.0 (2026-03-06) - Introduce winloop for Windows as an alternative to uvloop - Introduce winloop to be used when Windows is in use which enables blackd to run faster on Windows when winloop is installed #### 26.1.0 (2026-01-18) - Introduce the 2026 stable style with always_one_newline_after_import to force one blank line after import statements except when followed by a comment or import - Add multiline_string_handling to make expressions involving multiline strings more compact - Add normalize_cr_newlines to normalize file newlines with \r style newlines - Add remove_parens_around_except_types to remove parentheses around multiple exception types in except and except* without as - Add remove_parens_from_assignment_lhs to remove unnecessary parentheses from the left-hand side of assignments while preserving magic trailing commas - Add standardize_type_comments to format type comments to # type: (value) style ### Changed #### 26.5.0 (2026-05-16) - Improve heuristics around blank lines before, within and after groups of same-name decorated functions (such as `@overload` groups) in `.pyi` stub files - Improve parse error readability by showing multi-line output with an error pointer - Return HTTP 400 (Bad Request) for source parse failures instead of HTTP 500 in Blackd, keeping HTTP 500 only for genuine internal safety errors #### 26.3.1 (2026-03-12) - Always hash cache filename components derived from --python-cell-magics so custom magic names cannot affect cache paths - Disable browser-originated requests by default in Blackd, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure #### 26.3.0 (2026-03-06) - Simplify implementation of the power operator "hugging" logic - Rename maybe_install_uvloop function to maybe_use_uvloop to simplify loop installation and creation of either a uvloop/winloop evenloop or default eventloop - Emit a clear warning when the target Python version is newer than the running Python version, since AST safety checks cannot parse newer syntax, and replace the misleading "INTERNAL ERROR" message with an actionable error explaining the version mismatch #### 26.1.0 (2026-01-18) - Regenerate the _width_table.py with added tests for the Khmer language - Bump pathspec to v1 and fix inconsistencies with Git's .gitignore logic to match Git behavior for ignored patterns ### Fixed #### 26.5.1 (2026-05-18) - Fix unstable formatting of annotated assignments whose subscript annotation contains an inline comment - Preserve inline comments (including # type: ignore) immediately before a # fmt: skip line, avoiding AST equivalence failures - Correct the version in the published executables #### 26.5.0 (2026-05-16) - Fix `# fmt: skip` being ignored in nested `if` expressions with parenthesized `in` clauses - Fix crash when an f-string follows a `# fmt: off` comment inside brackets - Preserve multiline compound statement headers when `# fmt: skip` is placed on the colon line - Fix blank lines being removed between a function and a decorated class in `.pyi` stub files - Prevent string merger from creating unsplittable long lines when a pragma comment (e.g. `# type: ignore`) follows the closing bracket #### 26.3.1 (2026-03-12) - Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely #### 26.3.0 (2026-03-06) - Don't double-decode input, causing non-UTF-8 files to be corrupted - Fix crash on standalone comment in lambda default arguments - Preserve parentheses when # type: ignore comments would be merged with other comments on the same line, preventing AST equivalence failures - Fix bug where if guards in case blocks were incorrectly split when the pattern had a trailing comma - Fix string_processing crashing on unassigned long string literals with trailing commas - Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments #### 26.1.0 (2026-01-18) - Fix fmt: skip behavior on one-liner declarations to prevent incorrect collapsing - Fix module docstrings being treated as normal strings if preceded by comments - Fix type expansions split in generic functions - Explicitly shutdown the multiprocessing manager when run in diff mode ### Removed #### 26.3.0 (2026-03-06) - Remove deprecated function uvloop.install() in favor of uvloop.new_event_loop() - Remove unused gallery script ### Security #### 26.3.0 (2026-03-06) - Harden parsing of black requirements in the GitHub Action when use_pyproject is enabled so that only version specifiers are accepted and direct references such as black @ https://... are rejected ## Release notes ### 26.5.1 - Date: 2026-05-18 - Version: 26.5.1 - Original notes: https://github.com/psf/black/releases/tag/26.5.1 - Permalink: https://whatsnew.fyi/product/black/releases/26.5.1 - **fixed** — Fix unstable formatting of annotated assignments whose subscript annotation contains an inline comment - **fixed** — Preserve inline comments (including # type: ignore) immediately before a # fmt: skip line, avoiding AST equivalence failures - **fixed** — Correct the version in the published executables - **added** — Add Neovim integration guide covering conform.nvim, ALE, and simple command approaches ###### Stable style - Fix unstable formatting of annotated assignments whose subscript annotation contains an inline comment (e.g. `x: list[ # pyright: ignore[...]`) (#5130) - Preserve inline comments (including `# type: ignore`) immediately before a `# fmt: skip` line, avoiding AST equivalence failures (#5139) ###### Packaging - Correct the version in the published executables (#5137) ###### Documentation - Add Neovim integration guide covering conform.nvim, ALE, and simple command approaches (#5124) ### 26.5.0 - Date: 2026-05-16 - Version: 26.5.0 - Original notes: https://github.com/psf/black/releases/tag/26.5.0 - Permalink: https://whatsnew.fyi/product/black/releases/26.5.0 - **added** — Support for unpacking in comprehensions (PEP 798) and lazy imports (PEP 810), new syntactic features in Python 3.15 - **added** — Python 3.15 support - **fixed** — Fix `# fmt: skip` being ignored in nested `if` expressions with parenthesized `in` clauses - **fixed** — Fix crash when an f-string follows a `# fmt: off` comment inside brackets - **fixed** — Preserve multiline compound statement headers when `# fmt: skip` is placed on the colon line - **changed** — Improve heuristics around blank lines before, within and after groups of same-name decorated functions (such as `@overload` groups) in `.pyi` stub files - **fixed** — Fix blank lines being removed between a function and a decorated class in `.pyi` stub files - **fixed** — Prevent string merger from creating unsplittable long lines when a pragma comment (e.g. `# type: ignore`) follows the closing bracket - **changed** — Improve parse error readability by showing multi-line output with an error pointer - **added** — Add `SourceASTParseError` to distinguish source parse failures from internal safety errors - **changed** — Return HTTP 400 (Bad Request) for source parse failures instead of HTTP 500 in Blackd, keeping HTTP 500 only for genuine internal safety errors ###### Highlights - Add support for unpacking in comprehensions (PEP 798) and for lazy imports (PEP 810), both new syntactic features in Python 3.15 (#5048) - Python 3.15 is now supported. Compiled wheels are not yet provided for Python 3.15, so performance may be slower than on existing Python versions. Wheels will be provided once Python 3.15 is later in its release cycle. (#5127) ###### Stable style - Fix `# fmt: skip` being ignored in nested `if` expressions with parenthesized `in` clauses (#4903) - Add syntactic support for Python 3.15 (#5048) - Fix crash when an f-string follows a `# fmt: off` comment inside brackets (#5097) - Preserve multiline compound statement headers when `# fmt: skip` is placed on the colon line (#5117) ###### Preview style - Improve heuristics around whether blank lines should appear before, within and after groups of same-name decorated functions (such as `@overload` groups) in `.pyi` stub files (#5021) - Fix blank lines being removed between a function and a decorated class in `.pyi` stub files (#5092) - Prevent string merger from creating unsplittable long lines when a pragma comment (e.g. `# type: ignore`) follows the closing bracket (#5096) ###### Packaging - Run CI on 3.15 (#5127) ###### Output - Improve parse error readability by showing multi-line output with an error pointer. (#5068) - Add `SourceASTParseError` to distinguish source parse failures from internal safety errors, improving error reporting when Black's lenient parser accepts input that `ast.parse()` rejects (#5080) ###### _Blackd_ - Return HTTP 400 (Bad Request) for source parse failures instead of HTTP 500, keeping HTTP 500 only for genuine internal safety errors (#5080) ###### Integrations - Added documentation for doctest formatting tools and updated the integrations index to match (#4916) ###### Documentation - Use "Version X.Y.Z" headings in changelog for stable permalink anchors on ReadTheDocs (#5063) - Note in the editor integrations that the SublimeText `sublack` plugin is archived and unmaintained (#5082) ### 26.3.1 - Date: 2026-03-12 - Version: 26.3.1 - Original notes: https://github.com/psf/black/releases/tag/26.3.1 - Permalink: https://whatsnew.fyi/product/black/releases/26.3.1 - **fixed** — Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely - **changed** — Always hash cache filename components derived from --python-cell-magics so custom magic names cannot affect cache paths - **changed** — Disable browser-originated requests by default in Blackd, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure ###### Stable style - Prevent Jupyter notebook magic masking collisions from corrupting cells by using exact-length placeholders for short magics and aborting if a placeholder can no longer be unmasked safely (#5038) ###### Configuration - Always hash cache filename components derived from `--python-cell-magics` so custom magic names cannot affect cache paths (#5038) ###### _Blackd_ - Disable browser-originated requests by default, add configurable origin allowlisting and request body limits, and bound executor submissions to improve backpressure (#5039) ### 26.3.0 - Date: 2026-03-06 - Version: 26.3.0 - Original notes: https://github.com/psf/black/releases/tag/26.3.0 - Permalink: https://whatsnew.fyi/product/black/releases/26.3.0 - **fixed** — Don't double-decode input, causing non-UTF-8 files to be corrupted - **fixed** — Fix crash on standalone comment in lambda default arguments - **fixed** — Preserve parentheses when # type: ignore comments would be merged with other comments on the same line, preventing AST equivalence failures - **fixed** — Fix bug where if guards in case blocks were incorrectly split when the pattern had a trailing comma - **fixed** — Fix string_processing crashing on unassigned long string literals with trailing commas - **changed** — Simplify implementation of the power operator "hugging" logic - **fixed** — Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments - **added** — Introduce winloop for Windows as an alternative to uvloop - **removed** — Remove deprecated function uvloop.install() in favor of uvloop.new_event_loop() - **changed** — Rename maybe_install_uvloop function to maybe_use_uvloop to simplify loop installation and creation of either a uvloop/winloop evenloop or default eventloop - **changed** — Emit a clear warning when the target Python version is newer than the running Python version, since AST safety checks cannot parse newer syntax, and replace the misleading "INTERNAL ERROR" message with an actionable error explaining the version mismatch - **added** — Introduce winloop to be used when Windows is in use which enables blackd to run faster on Windows when winloop is installed - **removed** — Remove unused gallery script - **security** — Harden parsing of black requirements in the GitHub Action when use_pyproject is enabled so that only version specifiers are accepted and direct references such as black @ https://... are rejected ###### Stable style - Don't double-decode input, causing non-UTF-8 files to be corrupted (#4964) - Fix crash on standalone comment in lambda default arguments (#4993) - Preserve parentheses when `# type: ignore` comments would be merged with other comments on the same line, preventing AST equivalence failures (#4888) ###### Preview style - Fix bug where `if` guards in `case` blocks were incorrectly split when the pattern had a trailing comma (#4884) - Fix `string_processing` crashing on unassigned long string literals with trailing commas (one-item tuples) (#4929) - Simplify implementation of the power operator "hugging" logic (#4918) ###### Packaging - Fix shutdown errors in PyInstaller builds on macOS by disabling multiprocessing in frozen environments (#4930) ###### Performance - Introduce winloop for windows as an alternative to uvloop (#4996) - Remove deprecated function `uvloop.install()` in favor of `uvloop.new_event_loop()` (#4996) - Rename `maybe_install_uvloop` function to `maybe_use_uvloop` to simplify loop installation and creation of either a uvloop/winloop evenloop or default eventloop (#4996) ###### Output - Emit a clear warning when the target Python version is newer than the running Python version, since AST safety checks cannot parse newer syntax. Also replace the misleading "INTERNAL ERROR" message with an actionable error explaining the version mismatch (#4983) ###### _Blackd_ - Introduce winloop to be used when windows in use which enables blackd to run faster on windows when winloop is installed. (#4996) ###### Integrations - Remove unused gallery script (#5030) - Harden parsing of `black` requirements in the GitHub Action when `use_pyproject` is enabled so that only version specifiers are accepted and direct references such as `black @ https://...` are rejected. Users should upgrade to the latest version of the action as soon as possible. This update is received automatically when using `psf/black@stable`, and is independent of the version of Black installed by the action. (#5031) ###### Documentation - Expand preview style documentation with detailed examples for `wrap_comprehension_in`, `simplify_power_operator_hugging`, and `wrap_long_dict_values_in_parens` features (#4987) - Add detailed documentation for formatting Jupyter Notebooks (#5009) ### 26.1.0 - Date: 2026-01-18 - Version: 26.1.0 - Original notes: https://github.com/psf/black/releases/tag/26.1.0 - Permalink: https://whatsnew.fyi/product/black/releases/26.1.0 - **added** — Introduce the 2026 stable style with always_one_newline_after_import to force one blank line after import statements except when followed by a comment or import - **fixed** — Fix fmt: skip behavior on one-liner declarations to prevent incorrect collapsing - **fixed** — Fix module docstrings being treated as normal strings if preceded by comments - **fixed** — Fix type expansions split in generic functions - **added** — Add multiline_string_handling to make expressions involving multiline strings more compact - **added** — Add normalize_cr_newlines to normalize file newlines with \r style newlines - **added** — Add remove_parens_around_except_types to remove parentheses around multiple exception types in except and except* without as - **added** — Add remove_parens_from_assignment_lhs to remove unnecessary parentheses from the left-hand side of assignments while preserving magic trailing commas - **added** — Add standardize_type_comments to format type comments to # type: (value) style - **changed** — Regenerate the _width_table.py with added tests for the Khmer language - **changed** — Bump pathspec to v1 and fix inconsistencies with Git's .gitignore logic to match Git behavior for ignored patterns - **fixed** — Explicitly shutdown the multiprocessing manager when run in diff mode ###### Highlights Introduces the 2026 stable style (#4892), stabilizing the following changes: - `always_one_newline_after_import`: Always force one blank line after import statements, except when the line after the import is a comment or an import statement (#4489) - `fix_fmt_skip_in_one_liners`: Fix `# fmt: skip` behavior on one-liner declarations, such as `def foo(): return "mock" # fmt: skip`, where previously the declaration would have been incorrectly collapsed (#4800) - `fix_module_docstring_detection`: Fix module docstrings being treated as normal strings if preceded by comments (#4764) - `fix_type_expansion_split`: Fix type expansions split in generic functions (#4777) - `multiline_string_handling`: Make expressions involving multiline strings more compact (#1879) - `normalize_cr_newlines`: Add `\r` style newlines to the potential newlines to normalize file newlines both from and to (#4710) - `remove_parens_around_except_types`: Remove parentheses around multiple exception types in `except` and `except*` without `as` (#4720) - `remove_parens_from_assignment_lhs`: Remove unnecessary parentheses from the left-hand side of assignments while preserving magic trailing commas and intentional multiline formatting (#4865) - `standardize_type_comments`: Format type comments which have zero or more spaces between `#` and `type:` or between `type:` and value to `# type: (value)` (#4645) The following change was not in any previous stable release: - Regenerated the `_width_table.py` and added tests for the Khmer language (#4253) This release alo bumps `pathspec` to v1 and fixes inconsistencies with Git's `.gitignore` logic (#4958). Now, files will be ignored if a pattern matches them, even if the parent directory is directly unignored. For example, Black would previously format `exclude/not_this/foo.py` with this `.gitignore`: ``` exclude/ !exclude/not_this/ ``` Now, `exclude/not_this/foo.py` will remain ignored. To ensure `exclude/not_this/` and all of it's children are included in formatting (and in Git), use this `.gitignore`: ``` */exclude/* !*/exclude/not_this/ ``` This new behavior matches Git. The leading `*/` are only necessary if you wish to ignore matching subdirectories (like the previous behavior did), and not just matching root directories. ###### Output - Explicitly shutdown the multiprocessing manager when run in diff mode too (#4952) ###### Integrations - Upgraded PyPI upload workflow to use Trusted Publishing (#4611)