Repository: peterjc/flake8-black
Branch: master
Commit: 18d752393b06
Files: 37
Total size: 35.4 KB
Directory structure:
gitextract_foj3g7v5/
├── .flake8
├── .github/
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE.rst
├── MANIFEST.in
├── README.rst
├── flake8_black.py
├── pyproject.toml
├── requirements.txt
└── tests/
├── conflicting_configurations/
│ ├── .flake8
│ ├── goodbye.py
│ ├── hello.py
│ └── pyproject.toml
├── non_conflicting_configurations/
│ ├── .flake8
│ ├── hello.py
│ └── pyproject.toml
├── run_tests.sh
├── test_cases/
│ ├── hello_world.py
│ ├── mixed_tab_spaces.py
│ ├── no_closing_bracket.py
│ └── stub.pyi
├── test_changes/
│ ├── black_preview.py
│ ├── black_preview.txt
│ ├── commas.py
│ ├── commas.txt
│ ├── hello_world.py
│ ├── hello_world.txt
│ ├── hello_world_EOF.py
│ └── hello_world_EOF.txt
├── with_bad_toml/
│ ├── hello_world.py
│ ├── hello_world.txt
│ └── pyproject.toml
├── with_pyproject_toml/
│ ├── ignoring_toml.txt
│ ├── ordinary_quotes.py
│ └── pyproject.toml
└── without_pyproject_toml/
└── ordinary_quotes.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .flake8
================================================
[flake8]
# Recommend matching the black line length (default 88),
# rather than using the flake8 default of 79:
max-line-length = 88
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
# flake8/pycodechecker give false positives on black code
E203,
# Most of our test cases deliberately violate style checks:
per-file-ignores =
# These are meant to trigger black changes:
tests/test_changes/hello_world.py: E201,E202,E211,W391,BLK100
tests/test_changes/hello_world_EOF.py: W292,BLK100
tests/without_pyproject_toml/ordinary_quotes.py: Q000,BLK100
# These are not meant to trigger black changes:
tests/test_cases/no_closing_bracket.py: E902
tests/test_fail/mixed_tab_spaces.py: E101,E999,W191
tests/with_pyproject_toml/ordinary_quotes.py: Q000
tests/test_cases/mixed_tab_spaces.py: E101,E999,W191
# The bad TOML file breaks black checking this file:
tests/with_bad_toml/hello_world.py: BLK997,
# =====================
# flake-quote settings:
# =====================
# Set this to match black style:
inline-quotes = double
================================================
FILE: .github/workflows/test.yml
================================================
name: test
on: [push, pull_request]
jobs:
run-tests:
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
black-version: ["23.9.1", "25.9.0"]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Git configuration
run: |
git config core.autocrlf false
git reset --hard
- name: Build packages, and install the wheel
run: |
pip install build black==${{ matrix.black-version }}
python -m build
cd dist
python -m pip install flake8_black-*.whl
cd ..
# Wheel should now be installed
flake8 --version
- name: Run tests
run: |
# Unpack the tests from the sdist tar-ball
# (want to confirm the manifest was complete)
tar -zxvf dist/flake8_black-*.tar.gz
cd flake8_black-*/tests/
WIN="$([ "$RUNNER_OS" == "Windows" ];echo $?)" bash ./run_tests.sh
================================================
FILE: .gitignore
================================================
#Ignore the build directory (and its sub-directories):
build
#Ignore the distribution directory
dist
#Ignore another Python specific build folder:
flake8_black.egg-info/
#Ignore backup files from some Unix editors,
*~
*.swp
*.bak
#Ignore patches and any original files created by patch command
*.diff
*.orig
*.rej
#Ignore these hidden files from Mac OS X
.DS_Store
#Ignore hidden files from Dolphin window manager
.directory
================================================
FILE: .pre-commit-config.yaml
================================================
# pre-commit run --all-files
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-executables-have-shebangs
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: check-symlinks
- id: check-yaml
- id: debug-statements
exclude: tests/
- id: destroyed-symlinks
- id: end-of-file-fixer
exclude: tests/test_changes/
files: \.(py|sh|rst|yml|yaml)$
- id: mixed-line-ending
- id: trailing-whitespace
files: \.(py|sh|rst|yml|yaml)$
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 26.3.1
hooks:
- id: black
exclude: tests/
args: [--check]
- repo: https://github.com/PyCQA/flake8
rev: 7.3.0
hooks:
- id: flake8
additional_dependencies: [
'flake8-blind-except',
'flake8-docstrings',
'flake8-bugbear',
'flake8-comprehensions',
'flake8-docstrings',
'flake8-implicit-str-concat',
'pydocstyle>=5.0.0',
]
exclude: ^tests/test_cases/no_closing_bracket\.py$
- repo: https://github.com/asottile/blacken-docs
rev: 1.20.0
hooks:
- id: blacken-docs
additional_dependencies: [black==24.8.0]
exclude: ^.github/
- repo: https://github.com/rstcheck/rstcheck
rev: v6.2.5
hooks:
- id: rstcheck
args: [
--report-level=warning,
]
- repo: https://github.com/codespell-project/codespell
rev: v2.4.2
hooks:
- id: codespell
files: \.(py|sh|rst|yml|yaml)$
ci:
# Settings for the https://pre-commit.ci/ continuous integration service
autofix_prs: true
# Default message is more verbose
autoupdate_commit_msg: '[pre-commit.ci] autoupdate'
# Default is weekly
autoupdate_schedule: monthly
================================================
FILE: LICENSE.rst
================================================
Copyright 2019, Peter Cock, The James Hutton Institute, UK.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MANIFEST.in
================================================
include README.rst
include LICENSE.rst
include requirements.txt
recursive-include tests *.py *.txt *.sh *.toml
================================================
FILE: README.rst
================================================
flake8-black
============
.. image:: https://img.shields.io/pypi/v/flake8-black.svg
:alt: Released on the Python Package Index (PyPI)
:target: https://pypi.org/project/flake8-black/
.. image:: https://img.shields.io/conda/vn/conda-forge/flake8-black.svg
:alt: Released on Conda
:target: https://anaconda.org/conda-forge/flake8-black
.. image:: https://results.pre-commit.ci/badge/github/peterjc/flake8-black/master.svg
:target: https://results.pre-commit.ci/latest/github/peterjc/flake8-black/master
:alt: pre-commit.ci status
.. image:: https://img.shields.io/github/actions/workflow/status/peterjc/flake8-black/test.yml?logo=github-actions
:alt: GitHub workflow status
:target: https://github.com/peterjc/flake8-black/actions
.. image:: https://img.shields.io/pypi/dm/flake8-black.svg
:alt: PyPI downloads
:target: https://pypistats.org/packages/flake8-black
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:alt: Code style: black
:target: https://github.com/python/black
Introduction
------------
This is an MIT licensed `flake8 <https://github.com/pycqa/flake8>`_ plugin
for validating Python code style with the command line code formatting tool
`black <https://github.com/python/black>`_. It is available to install from
the `Python Package Index (PyPI) <https://pypi.org/project/flake8-black/>`_.
Black, *"The Uncompromising Code Formatter"*, is normally run to edit your
Python code in place to match their coding style, a strict subset of the
`PEP 8 style guide <https://www.python.org/dev/peps/pep-0008/>`_.
The point of this plugin is to be able to run ``black --check ...`` from
within the ``flake8`` plugin ecosystem. You might use this via a ``git``
pre-commit hook, or as part of your continuous integration testing.
If you are using `pre-commit <https://pre-commit.com/>`_ configure it to call
black and/or flake8 directly - you do not need flake8-black at all.
Flake8 Validation codes
-----------------------
Early versions of flake8 assumed a single character prefix for the validation
codes, which became problematic with collisions in the plugin ecosystem. Since
v3.0, flake8 has supported longer prefixes, therefore this plugin uses ``BLK``
as its prefix.
====== =======================================================================
Code Description (*and notes*)
------ -----------------------------------------------------------------------
BLK100 Black would make changes.
BLK9## Internal error (*various, listed below*):
BLK900 Failed to load file: ...
BLK901 Invalid input.
BLK997 Invalid TOML file: ...
BLK998 Could not access flake8 line length setting (*no longer used*).
BLK999 Unexpected exception.
====== =======================================================================
Note that if your Python code has a syntax error, ``black --check ...`` would
report this as an error. Likewise ``flake8 ...`` will by default report the
syntax error, but importantly it does not seem to then call the plugins, so
you will *not* get an additional ``BLK`` error.
Installation
------------
Python 3.9 or later is required, but ``black`` can be used on Python code
written for older versions of Python.
You can install ``flake8-black`` using ``pip``, which should install ``flake8``
and ``black`` as well if not already present::
$ pip install flake8-black
Alternatively, if you are using the Anaconda packaging system, the following
command will install the plugin with its dependencies::
$ conda install -c conda-forge flake8-black
The new validator should be automatically included when using ``flake8`` which
may now report additional validation codes starting with ``BLK`` (as defined
above). For example::
$ flake8 example.py
You can request only the ``BLK`` codes be shown using::
$ flake8 --select BLK example.py
Python package management
-------------------------
For large projects especially, you should consider pinning the exact
version of black you want to use as their updates do sometimes introduce
changes which would show up as new ``BLK100`` violations via flake8.
You should be able to specify your black version in your conda or pip
requirements or environment, or using using pipenv or poetry etc.
Configuration
-------------
We assume you are familiar with `flake8 configuration
<http://flake8.pycqa.org/en/latest/user/configuration.html>`_ and
`black configuration
<https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#configuration-via-a-file>`_.
We recommend using the following settings in your ``flake8`` configuration,
for example in your ``.flake8``, ``setup.cfg``, or ``tox.ini`` file::
[flake8]
# Recommend matching the black line length (default 88),
# rather than using the flake8 default of 79:
max-line-length = 88
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
E203,
Note currently ``pycodestyle`` gives false positives on the spaces ``black``
uses for slices, which ``flake8`` reports as ``E203: whitespace before ':'``.
Until `pyflakes issue 373 <https://github.com/PyCQA/pycodestyle/issues/373>`_
is fixed, and ``flake8`` is updated, we suggest disabling this style check.
Separately ``pyproject.toml`` is used for ``black`` configuration - if this
file is found, the plugin will look at the following ``black`` settings:
* ``target_version``
* ``skip_string_normalization``
* ``line_length``
You can specify a particular path for the ``pyproject.toml`` file (e.g.
global development settings) using ``--black-config FILENAME`` at the
command line, or using ``black-config = FILENAME`` in your ``flake8``
configuration file.
Ignoring validation codes
-------------------------
Using the flake8 no-quality-assurance pragma comment is not recommended (e.g.
adding ``# noqa: BLK100`` to the first line black would change). Instead use
the black pragma comments ``# fmt: off`` at the start, and ``# fmt: on`` at
the end, of any region of your code which should not be changed. Or, add
``# fmt: skip`` to single lines. Or, exclude the entire file by name (see
below).
Ignoring files
--------------
The plugin does *NOT* currently consider the ``black`` settings ``include``
and ``exclude``, so if you have certain Python files which you do not use
with ``black`` and have told it to ignore, you will *also* need to tell
``flake8`` to ignore them (e.g. using ``exclude`` or ``per-file-ignores``).
Version History
---------------
======= ============ ===========================================================
Version Release date Changes
------- ------------ -----------------------------------------------------------
v0.4.0 *Pending* - Now tested on Python 3.9 through 3.13, and black 23.9.1
(as before) and black 25.9.0 (current latest).
- Support the API change in ``decode_bytes`` in black 25.9.0.
- Error ``BLK997`` does not have the bad TOML filename.
v0.3.7 2025-09-19 - Now tested on Python 3.8 though 3.13.
- Using ``black.Mode`` class name in place of legacy alias
``black.FileMode`` from beta release era.
- Does not work on black 25.9.0 onwards.
v0.3.6 2022-12-13 - Use standard library ``tomllib`` on Python 3.11 onwards,
contribution from
`Ganden Schaffner <https://github.com/gschaffner>`_.
v0.3.5 2022-11-21 - Fix regression clashing with ``flake8-rst-docstrings``.
v0.3.4 2022-11-17 - Replaces ``setup.py`` with ``pyproject.toml`` for build.
v0.3.3 2022-05-16 - Cope with line-length as string in pyproject.toml config.
v0.3.2 2022-02-25 - Use ``tomli`` library to match black, contribution from
`Brian Helba <https://github.com/brianhelba>`_.
- Adopted GitHub Actions to replace TravisCI testing.
- Python 3.7 or later required.
v0.3.0 2022-02-25 - Requires black v22.1.0 (first non-beta release) or later.
- Support options "preview", "skip-magic-trailing-comma"
in the black TOML file, contribution from
`Ferdy <https://github.com/ferdynice>`_.
v0.2.4 2022-01-30 - Support black v22.1.0 which changed a function call,
contribution from
`Raffaele Salmaso <https://github.com/rsalmaso>`_.
v0.2.3 2021-07-16 - Made ``toml`` dependency explicit in ``setup.py``.
v0.2.2 2021-07-16 - Declared ``toml`` dependency (for black 21.7b0).
v0.2.1 2020-07-25 - Detect ``*.pyi`` files via extension.
v0.2.0 2020-05-20 - Minimum requirement on black 19.3b0 or later is now
implicit. This is a workaround for `pipenv issue 3928
<https://github.com/pypa/pipenv/issues/3928>`_. Upgrade
black if running flake8 gives an error like this:
``Flake8 failed to load plugin "BLK" due to __call__()
got an unexpected keyword argument 'target_versions'.``
v0.1.2 2020-05-18 - Removed test broken by flake8 v3.8 change to resolve
configuration files relative to current directory.
v0.1.1 2019-08-26 - Option to use a (global) black configuration file,
contribution from
`Tomasz Grining <https://github.com/098799>`_.
- New ``BLK997`` if can't parse ``pyproject.toml`` file.
- Logs configuration files, use ``-v`` or ``--verbose``.
- Fixed flake8 "builtins" parameter warning.
- Now requires black 19.3b0 or later.
v0.1.0 2019-06-03 - Uses main black settings from ``pyproject.toml``,
contribution from `Alex <https://github.com/ADKosm>`_.
- WARNING: Now ignores flake8 ``max-line-length`` setting.
v0.0.4 2019-03-15 - Supports black 19.3b0 which changed a function call.
v0.0.3 2019-02-21 - Bug fix when ``W292 no newline at end of file`` applies,
contribution from
`Sapphire Becker <https://github.com/sapphire-janrain>`_.
v0.0.2 2019-02-15 - Document syntax error behaviour (no BLK error reported).
v0.0.1 2019-01-10 - Initial public release.
- Passes flake8 ``max-line-length`` setting to black.
======= ============ ===========================================================
Developers
----------
This plugin is on GitHub at https://github.com/peterjc/flake8-black
Developers may install the plugin from the git repository with optional build
dependencies::
$ pip install -e .[develop]
To make a new release once tested locally and online::
$ git tag vX.Y.Z
$ python -m build
$ git push origin master --tags
$ twine upload dist/flake8?black-X.Y.Z*
The PyPI upload should trigger an automated pull request updating the
`flake8-black conda-forge recipe
<https://github.com/conda-forge/flake8-black-feedstock/blob/master/recipe/meta.yaml>`_.
================================================
FILE: flake8_black.py
================================================
"""Check Python code passes black style validation via flake8.
This is a plugin for the tool flake8 tool for checking Python
source code using the tool black.
"""
import sys
from os import path
from pathlib import Path
if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib
import black
from flake8 import utils as stdin_utils
from flake8 import LOG
__version__ = "0.4.0"
black_prefix = "BLK"
try:
black.decode_bytes(b"")
except TypeError:
# TypeError: decode_bytes() missing required argument 'mode' (pos 2)
decode_bytes_wrapper = black.decode_bytes
else:
# Probably running older than black 25.9.0
def decode_bytes_wrapper(src, mode):
"""Proxy wrapper for backward compatibility."""
return black.decode_bytes(src)
def find_diff_start(old_src, new_src):
"""Find line number and column number where text first differs."""
old_lines = old_src.split("\n")
new_lines = new_src.split("\n")
for line in range(min(len(old_lines), len(new_lines))):
old = old_lines[line]
new = new_lines[line]
if old == new:
continue
for col in range(min(len(old), len(new))):
if old[col] != new[col]:
return line, col
# Difference at the end of the line...
return line, min(len(old), len(new))
# Difference at the end of the file...
return min(len(old_lines), len(new_lines)), 0
class BadBlackConfig(ValueError):
"""Bad black TOML configuration file."""
pass
def load_black_mode(toml_filename=None):
"""Load black configuration TOML file (or return defaults) as black.Mode object."""
if not toml_filename:
return black.FileMode(
target_versions=set(),
line_length=black.DEFAULT_LINE_LENGTH, # Expect to be 88
string_normalization=True,
magic_trailing_comma=True,
preview=False,
)
LOG.info("flake8-black: loading black settings from %s", toml_filename)
try:
with toml_filename.open(mode="rb") as toml_file:
pyproject_toml = tomllib.load(toml_file)
except ValueError:
LOG.info("flake8-black: invalid TOML file %s", toml_filename)
raise BadBlackConfig(path.relpath(toml_filename))
config = pyproject_toml.get("tool", {}).get("black", {})
black_config = {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
# Extract the fields we care about,
# cast to int explicitly otherwise line length could be a string
return black.Mode(
target_versions={
black.TargetVersion[val.upper()]
for val in black_config.get("target_version", [])
},
line_length=int(black_config.get("line_length", black.DEFAULT_LINE_LENGTH)),
string_normalization=not black_config.get("skip_string_normalization", False),
magic_trailing_comma=not black_config.get("skip_magic_trailing_comma", False),
preview=bool(black_config.get("preview", False)),
)
black_config = {None: load_black_mode()} # None key's value is default config
class BlackStyleChecker:
"""Checker of Python code using black."""
name = "black"
version = __version__
override_config = None
STDIN_NAMES = {"stdin", "-", "(none)", None}
def __init__(self, tree, filename="(none)"):
"""Initialise."""
self.tree = tree
self.filename = filename
@property
def _file_mode(self):
"""Return black.FileMode object, using local pyproject.toml as needed."""
if self.override_config:
return self.override_config
# Unless using override, we look for pyproject.toml
project_root = black.find_project_root(
("." if self.filename in self.STDIN_NAMES else self.filename,)
)
if isinstance(project_root, tuple):
# black stable 22.1.0 update find_project_root return value
# from Path to Tuple[Path, str]
project_root = project_root[0]
path = project_root / "pyproject.toml"
if path in black_config:
# Already loaded
LOG.debug("flake8-black: %s using pre-loaded %s", self.filename, path)
return black_config[path]
elif path.is_file():
# Use this pyproject.toml for this python file,
# (unless configured with global override config)
# This should be thread safe - does not matter even if
# two workers load and cache this file at the same time
black_config[path] = load_black_mode(path)
LOG.debug("flake8-black: %s using newly loaded %s", self.filename, path)
return black_config[path]
else:
# No project specific file, use default
LOG.debug("flake8-black: %s using defaults", self.filename)
return black_config[None]
@classmethod
def add_options(cls, parser):
"""Add black-config options."""
parser.add_option(
"--black-config",
metavar="TOML_FILENAME",
default=None,
action="store",
# type="string", <- breaks using None as a sentinel
# normalize_paths=True, <- broken and breaks None as a sentinel
# https://gitlab.com/pycqa/flake8/issues/562
# https://gitlab.com/pycqa/flake8/merge_requests/337
parse_from_config=True,
help="Path to black TOML configuration file (overrides the "
"default 'pyproject.toml' detection; use empty string '' to mean "
"ignore all 'pyproject.toml' files).",
)
@classmethod
def parse_options(cls, optmanager, options, extra_args):
"""Parse black-config options."""
# We have one and only one flake8 plugin configuration
if options.black_config is None:
LOG.info("flake8-black: No black configuration set")
cls.override_config = None
return
elif not options.black_config:
LOG.info("flake8-black: Explicitly using no black configuration file")
cls.override_config = black_config[None] # explicitly use defaults
return
# Validate the path setting - handling relative paths ourselves,
# see https://gitlab.com/pycqa/flake8/issues/562
black_config_path = Path(options.black_config)
if options.config:
# Assume black config path was via flake8 config file
base_path = Path(path.dirname(path.abspath(options.config)))
black_config_path = base_path / black_config_path
if not black_config_path.is_file():
# Want flake8 to abort, see:
# https://gitlab.com/pycqa/flake8/issues/559
raise ValueError(
"Plugin flake8-black could not find specified black config file: "
"--black-config %s" % black_config_path
)
# Now load the TOML file, and the black section within it
# This configuration is to override any local pyproject.toml
try:
cls.override_config = black_config[black_config_path] = load_black_mode(
black_config_path
)
except BadBlackConfig:
# Could raise BLK997, but view this as an abort condition
raise ValueError(
"Plugin flake8-black could not parse specified black config file: "
"--black-config %s" % black_config_path
)
def run(self):
"""Use black to check code style."""
msg = None
line = 0
col = 0
try:
if self.filename in self.STDIN_NAMES:
self.filename = "stdin"
raw_source = stdin_utils.stdin_get_value().encode("utf-8")
else:
with open(self.filename, "rb") as buf:
raw_source = buf.read()
except Exception as e:
raw_source = ""
msg = "900 Failed to load file: %s" % e
if not raw_source and not msg:
# Empty file (good)
return
elif raw_source:
# Call black...
try:
file_mode = self._file_mode
file_mode.is_pyi = self.filename and self.filename.endswith(".pyi")
source, _, _ = decode_bytes_wrapper(raw_source, file_mode)
new_code = black.format_file_contents(
source, mode=file_mode, fast=False
)
except black.NothingChanged:
return
except black.InvalidInput:
msg = "901 Invalid input."
except (BadBlackConfig, tomllib.TOMLDecodeError):
# Seems in black 25.9.0 the TOMLDecodeError is triggered while
# finding project root, not trivial to get the path
msg = "997 Invalid TOML file"
except Exception as err:
msg = "999 Unexpected exception: %r" % err
else:
assert (
new_code != source
), "Black made changes without raising NothingChanged"
line, col = find_diff_start(source, new_code)
line += 1 # Strange as col seems to be zero based?
msg = "100 Black would make changes."
# If we don't know the line or column numbers, leaving as zero.
yield line, col, black_prefix + msg, type(self)
================================================
FILE: pyproject.toml
================================================
[build-system]
requires = ['pip>=21.3', 'setuptools>=61', 'wheel']
build-backend = 'setuptools.build_meta'
[project]
name = 'flake8-black'
description = 'flake8 plugin to call black as a code style validator'
keywords = ['black', 'formatting', 'style', 'flake8']
license = {text = 'MIT'}
readme = 'README.rst'
authors = [
{name = 'Peter J. A. Cock'}
]
maintainers = [
{name = 'Peter J. A. Cock', email = 'p.j.a.cock@googlemail.com'}
]
classifiers = [
'Intended Audience :: Developers',
'Framework :: Flake8',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Software Development :: Quality Assurance',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only'
]
requires-python = '>=3.9'
dependencies = [
'flake8>=3',
'black>=22.1.0',
'tomli ; python_version < "3.11"',
]
dynamic = ['version']
[project.entry-points]
'flake8.extension' = {BLK = 'flake8_black:BlackStyleChecker'}
[project.optional-dependencies]
develop = ['build', 'twine']
[project.urls]
Homepage = 'https://github.com/peterjc/flake8-black'
'Source Code' = 'https://github.com/peterjc/flake8-black/'
'Bug Tracker' = 'https://github.com/peterjc/flake8-black/issues'
Documentation = 'https://github.com/peterjc/flake8-black/blob/master/README.rst'
[tool.setuptools]
py-modules = ['flake8_black']
zip-safe = true
[tool.setuptools.dynamic]
version = {attr = 'flake8_black.__version__'}
================================================
FILE: requirements.txt
================================================
# This is a plugin for flake8, so we require that.
# Our prefix is not single letter, so we need v3:
flake8 >= 3.0.0
# We need black
black >= 22.1.0
tomli ; python_version < "3.11"
================================================
FILE: tests/conflicting_configurations/.flake8
================================================
[flake8]
# Plugin flake8-black will pass this value to black
max-line-length = 120
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
# flake8/pycodechecker give false positives on black code
E203,
================================================
FILE: tests/conflicting_configurations/goodbye.py
================================================
"""Print 'Au revoir' to the terminal.
This is a simple test script.
"""
print("Au revoir")
================================================
FILE: tests/conflicting_configurations/hello.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line
and a PEP263 encoding line.
"""
print("Hello world")
================================================
FILE: tests/conflicting_configurations/pyproject.toml
================================================
[tool.black]
line-length = 90
================================================
FILE: tests/non_conflicting_configurations/.flake8
================================================
[flake8]
# Plugin flake8-black will pass this value to black
max-line-length = 120
extend-ignore =
# See https://github.com/PyCQA/pycodestyle/issues/373
# flake8/pycodechecker give false positives on black code
E203,
================================================
FILE: tests/non_conflicting_configurations/hello.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line
and a PEP263 encoding line.
"""
print("Hello world")
================================================
FILE: tests/non_conflicting_configurations/pyproject.toml
================================================
[tool.black]
line-length = 120
================================================
FILE: tests/run_tests.sh
================================================
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
# Assumes in the tests/ directory
echo "Checking our configuration option appears in help"
flake8 -h 2>&1 | grep "black-config"
set +o pipefail
echo "Checking we report an error when can't find specified config file"
flake8 --black-config does_not_exist.toml 2>&1 | grep -i "could not find"
echo "Checking failure with mal-formed TOML file"
flake8 --select BLK test_cases/ --black-config with_bad_toml/pyproject.toml 2>&1 | grep -i "could not parse"
set -o pipefail
echo "Checking we report no errors on these test cases"
# Must explicitly include *.pyi or flake8 ignores them
flake8 --select BLK test_cases/*.py*
# Adding --black-config '' meaning ignore any pyproject.toml should have no effect:
flake8 --select BLK test_cases/*.py --black-config ''
flake8 --select BLK --max-line-length 50 test_cases/*.py
flake8 --select BLK --max-line-length 90 test_cases/*.py
flake8 --select BLK with_pyproject_toml/*.py
flake8 --select BLK with_pyproject_toml/*.py --black-config with_pyproject_toml/pyproject.toml
flake8 --select BLK --max-line-length 88 with_pyproject_toml/
flake8 --select BLK without_pyproject_toml/*.py --black-config with_pyproject_toml/pyproject.toml
# Adding --black-config '' should have no effect:
#flake8 --select BLK --max-line-length 88 with_pyproject_toml/ --black-config ''
flake8 --select BLK non_conflicting_configurations/*.py
flake8 --select BLK conflicting_configurations/*.py
# Here using --black-config '' meaning ignore any (bad) pyproject.toml files:
flake8 --select BLK with_bad_toml/hello_world.py --black-config ''
echo "Checking we report expected black changes"
diff test_changes/hello_world.txt <(flake8 --select BLK test_changes/hello_world.py)
diff test_changes/hello_world_EOF.txt <(flake8 --select BLK test_changes/hello_world_EOF.py)
diff test_changes/hello_world_EOF.txt <(flake8 --select BLK test_changes/hello_world_EOF.py --black-config '')
diff <(
if [ "${WIN:-1}" = 0 ]; then
sed 's_/_\\_2' with_bad_toml/hello_world.txt
else
cat with_bad_toml/hello_world.txt
fi
) <(flake8 --select BLK with_bad_toml/hello_world.py)
diff with_pyproject_toml/ignoring_toml.txt <(flake8 with_pyproject_toml/ --select BLK --black-config '')
# no changes by default,
flake8 --select BLK test_changes/commas.py tests/black_preview.py
# will make changes if we ignore the magic trailing comma:
diff test_changes/commas.txt <(flake8 --select BLK test_changes/commas.py --black-config with_pyproject_toml/pyproject.toml)
# will make changes if we enable future functionality preview mode:
diff test_changes/black_preview.txt <(flake8 --select BLK test_changes/black_preview.py --black-config with_pyproject_toml/pyproject.toml)
echo "Tests passed."
================================================
FILE: tests/test_cases/hello_world.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line
and a PEP263 encoding line.
"""
print("Hello world")
================================================
FILE: tests/test_cases/mixed_tab_spaces.py
================================================
"""Invalid under Python 3, example with mixed indentation."""
if True:
print("This line was indented with four spaces!")
if True:
print("This line was indented with eight spaces.")
if True:
print("This line was indented with a tab!")
================================================
FILE: tests/test_cases/no_closing_bracket.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal (with syntax error).
This is a simple test script using a hashbang line and a PEP263 encoding line. There is
a deliberate syntax error (missing closing bracket).
Black will fail to parse this file:
$ black --check no_closing_bracket.py ; echo "Return code $?"
error: cannot format no_closing_bracket.py: ('EOF in multi-line statement', (31, 0))
All done! ð ð ð
1 file would fail to reformat.
Return code 123
It seems in this case the plugin never gets the chance to report:
$ flake8 --select BLK no_closing_bracket.py ; echo "Return code $?"
Return code 0
This doesn't really matter, as it would be redundant with the flake8 syntax errors:
$ flake8 no_closing_bracket.py ; echo "Return code $?"
no_closing_bracket.py:30:19: E999 SyntaxError: unexpected EOF while parsing
Return code 1
"""
print("Hello world"
================================================
FILE: tests/test_cases/stub.pyi
================================================
def my_function(): ...
class Wibble: ...
================================================
FILE: tests/test_changes/black_preview.py
================================================
"""Example showing future black string reformatting."""
a_very_long_variable = 17.3
short_value = 1234567890
def and_a_very_long_function_call():
"""Deep thought."""
return 42
my_dict = {
"a key in my dict": a_very_long_variable
* and_a_very_long_function_call()
/ 100000.0,
"another key": (short_value),
}
================================================
FILE: tests/test_changes/black_preview.txt
================================================
test_changes/black_preview.py:13:25: BLK100 Black would make changes.
================================================
FILE: tests/test_changes/commas.py
================================================
"""Example of black and magic commas."""
vegetables = {
"carrot",
"parsnip",
"potato",
"swede",
"leak",
"aubergine",
"tomato",
"peas",
"beans",
}
# This set would easily fit on one line, but a trailing comma
# after the final entry tells black (by default) to leave this
# with one entry per line:
yucky = {
"aubergine",
"squid",
"snails",
}
print("I dislike these vegetables: %s." % ", ".join(vegetables.intersection(yucky)))
================================================
FILE: tests/test_changes/commas.txt
================================================
test_changes/commas.py:18:10: BLK100 Black would make changes.
================================================
FILE: tests/test_changes/hello_world.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line and a PEP263 encoding line.
In the original format, there excess spaces in the print call, and unwanted
blank lines - which black will remove.
"""
print ( "Hello world" )
================================================
FILE: tests/test_changes/hello_world.txt
================================================
test_changes/hello_world.py:12:6: BLK100 Black would make changes.
================================================
FILE: tests/test_changes/hello_world_EOF.py
================================================
"""Print 'Hello world' to the terminal.
This is a simple test script which in the formal form has a missing final
line break - which black will add.
The point of this is the edit position will be at the very end of the file,
which is a corner case.
"""
print("Hello world")
================================================
FILE: tests/test_changes/hello_world_EOF.txt
================================================
test_changes/hello_world_EOF.py:11:1: BLK100 Black would make changes.
================================================
FILE: tests/with_bad_toml/hello_world.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line
and a PEP263 encoding line.
"""
print("Hello world")
================================================
FILE: tests/with_bad_toml/hello_world.txt
================================================
with_bad_toml/hello_world.py:0:1: BLK997 Invalid TOML file
================================================
FILE: tests/with_bad_toml/pyproject.toml
================================================
[tool.black]
skip-string-normalization = true
# This line is (a) in the wrong file, and (b) invalid syntax
black-config=
================================================
FILE: tests/with_pyproject_toml/ignoring_toml.txt
================================================
with_pyproject_toml/ordinary_quotes.py:10:7: BLK100 Black would make changes.
================================================
FILE: tests/with_pyproject_toml/ordinary_quotes.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line
and a PEP263 encoding line.
We use ordinary quotes in this test.
"""
print('Hello world')
================================================
FILE: tests/with_pyproject_toml/pyproject.toml
================================================
[tool.black]
# This is probably better as an integer,
# but reasonable to cope with it as str:
line-length = "88"
skip-string-normalization = true
skip-magic-trailing-comma = true
preview = true
================================================
FILE: tests/without_pyproject_toml/ordinary_quotes.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Print 'Hello world' to the terminal.
This is a simple test script using a hashbang line
and a PEP263 encoding line.
We use ordinary quotes in this test.
"""
print('Hello world')
gitextract_foj3g7v5/
├── .flake8
├── .github/
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE.rst
├── MANIFEST.in
├── README.rst
├── flake8_black.py
├── pyproject.toml
├── requirements.txt
└── tests/
├── conflicting_configurations/
│ ├── .flake8
│ ├── goodbye.py
│ ├── hello.py
│ └── pyproject.toml
├── non_conflicting_configurations/
│ ├── .flake8
│ ├── hello.py
│ └── pyproject.toml
├── run_tests.sh
├── test_cases/
│ ├── hello_world.py
│ ├── mixed_tab_spaces.py
│ ├── no_closing_bracket.py
│ └── stub.pyi
├── test_changes/
│ ├── black_preview.py
│ ├── black_preview.txt
│ ├── commas.py
│ ├── commas.txt
│ ├── hello_world.py
│ ├── hello_world.txt
│ ├── hello_world_EOF.py
│ └── hello_world_EOF.txt
├── with_bad_toml/
│ ├── hello_world.py
│ ├── hello_world.txt
│ └── pyproject.toml
├── with_pyproject_toml/
│ ├── ignoring_toml.txt
│ ├── ordinary_quotes.py
│ └── pyproject.toml
└── without_pyproject_toml/
└── ordinary_quotes.py
SYMBOL INDEX (13 symbols across 3 files)
FILE: flake8_black.py
function decode_bytes_wrapper (line 33) | def decode_bytes_wrapper(src, mode):
function find_diff_start (line 38) | def find_diff_start(old_src, new_src):
class BadBlackConfig (line 57) | class BadBlackConfig(ValueError):
function load_black_mode (line 63) | def load_black_mode(toml_filename=None):
class BlackStyleChecker (line 101) | class BlackStyleChecker:
method __init__ (line 110) | def __init__(self, tree, filename="(none)"):
method _file_mode (line 116) | def _file_mode(self):
method add_options (line 149) | def add_options(cls, parser):
method parse_options (line 167) | def parse_options(cls, optmanager, options, extra_args):
method run (line 207) | def run(self):
FILE: tests/test_cases/stub.pyi
function my_function (line 1) | def my_function(): ...
class Wibble (line 3) | class Wibble: ...
FILE: tests/test_changes/black_preview.py
function and_a_very_long_function_call (line 7) | def and_a_very_long_function_call():
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (40K chars).
[
{
"path": ".flake8",
"chars": 1098,
"preview": "[flake8]\n\n# Recommend matching the black line length (default 88),\n# rather than using the flake8 default of 79:\nmax-lin"
},
{
"path": ".github/workflows/test.yml",
"chars": 1240,
"preview": "name: test\n\non: [push, pull_request]\n\njobs:\n run-tests:\n runs-on: ${{ matrix.os }}\n defaults:\n run:\n "
},
{
"path": ".gitignore",
"chars": 432,
"preview": "#Ignore the build directory (and its sub-directories):\nbuild\n\n#Ignore the distribution directory\ndist\n\n#Ignore another P"
},
{
"path": ".pre-commit-config.yaml",
"chars": 1974,
"preview": "# pre-commit run --all-files\nrepos:\n- repo: https://github.com/pre-commit/pre-commit-hooks\n rev: v6.0.0\n hooks:\n"
},
{
"path": "LICENSE.rst",
"chars": 1084,
"preview": "Copyright 2019, Peter Cock, The James Hutton Institute, UK.\n\nPermission is hereby granted, free of charge, to any person"
},
{
"path": "MANIFEST.in",
"chars": 111,
"preview": "include README.rst\ninclude LICENSE.rst\ninclude requirements.txt\nrecursive-include tests *.py *.txt *.sh *.toml\n"
},
{
"path": "README.rst",
"chars": 11117,
"preview": "flake8-black\n============\n\n.. image:: https://img.shields.io/pypi/v/flake8-black.svg\n :alt: Released on the Python Pac"
},
{
"path": "flake8_black.py",
"chars": 9523,
"preview": "\"\"\"Check Python code passes black style validation via flake8.\n\nThis is a plugin for the tool flake8 tool for checking P"
},
{
"path": "pyproject.toml",
"chars": 1545,
"preview": "[build-system]\nrequires = ['pip>=21.3', 'setuptools>=61', 'wheel']\nbuild-backend = 'setuptools.build_meta'\n\n[project]\nna"
},
{
"path": "requirements.txt",
"chars": 182,
"preview": "# This is a plugin for flake8, so we require that.\n# Our prefix is not single letter, so we need v3:\nflake8 >= 3.0.0\n\n# "
},
{
"path": "tests/conflicting_configurations/.flake8",
"chars": 231,
"preview": "[flake8]\n\n# Plugin flake8-black will pass this value to black\nmax-line-length = 120\n\nextend-ignore =\n # See https://g"
},
{
"path": "tests/conflicting_configurations/goodbye.py",
"chars": 93,
"preview": "\"\"\"Print 'Au revoir' to the terminal.\n\nThis is a simple test script.\n\"\"\"\n\nprint(\"Au revoir\")\n"
},
{
"path": "tests/conflicting_configurations/hello.py",
"chars": 192,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
},
{
"path": "tests/conflicting_configurations/pyproject.toml",
"chars": 30,
"preview": "[tool.black]\nline-length = 90\n"
},
{
"path": "tests/non_conflicting_configurations/.flake8",
"chars": 231,
"preview": "[flake8]\n\n# Plugin flake8-black will pass this value to black\nmax-line-length = 120\n\nextend-ignore =\n # See https://g"
},
{
"path": "tests/non_conflicting_configurations/hello.py",
"chars": 192,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
},
{
"path": "tests/non_conflicting_configurations/pyproject.toml",
"chars": 31,
"preview": "[tool.black]\nline-length = 120\n"
},
{
"path": "tests/run_tests.sh",
"chars": 2740,
"preview": "#!/bin/bash\nset -euo pipefail\nIFS=$'\\n\\t'\n\n# Assumes in the tests/ directory\n\necho \"Checking our configuration option ap"
},
{
"path": "tests/test_cases/hello_world.py",
"chars": 192,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
},
{
"path": "tests/test_cases/mixed_tab_spaces.py",
"chars": 256,
"preview": "\"\"\"Invalid under Python 3, example with mixed indentation.\"\"\"\n\nif True:\n print(\"This line was indented with four spac"
},
{
"path": "tests/test_cases/no_closing_bracket.py",
"chars": 943,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal (with syntax error).\n\nThis is a sim"
},
{
"path": "tests/test_cases/stub.pyi",
"chars": 42,
"preview": "def my_function(): ...\n\nclass Wibble: ...\n"
},
{
"path": "tests/test_changes/black_preview.py",
"chars": 336,
"preview": "\"\"\"Example showing future black string reformatting.\"\"\"\n\na_very_long_variable = 17.3\nshort_value = 1234567890\n\n\ndef and_"
},
{
"path": "tests/test_changes/black_preview.txt",
"chars": 70,
"preview": "test_changes/black_preview.py:13:25: BLK100 Black would make changes.\n"
},
{
"path": "tests/test_changes/commas.py",
"chars": 478,
"preview": "\"\"\"Example of black and magic commas.\"\"\"\n\nvegetables = {\n \"carrot\",\n \"parsnip\",\n \"potato\",\n \"swede\",\n \"le"
},
{
"path": "tests/test_changes/commas.txt",
"chars": 63,
"preview": "test_changes/commas.py:18:10: BLK100 Black would make changes.\n"
},
{
"path": "tests/test_changes/hello_world.py",
"chars": 313,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
},
{
"path": "tests/test_changes/hello_world.txt",
"chars": 67,
"preview": "test_changes/hello_world.py:12:6: BLK100 Black would make changes.\n"
},
{
"path": "tests/test_changes/hello_world_EOF.py",
"chars": 276,
"preview": "\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script which in the formal form has a missing final\nline "
},
{
"path": "tests/test_changes/hello_world_EOF.txt",
"chars": 71,
"preview": "test_changes/hello_world_EOF.py:11:1: BLK100 Black would make changes.\n"
},
{
"path": "tests/with_bad_toml/hello_world.py",
"chars": 192,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
},
{
"path": "tests/with_bad_toml/hello_world.txt",
"chars": 59,
"preview": "with_bad_toml/hello_world.py:0:1: BLK997 Invalid TOML file\n"
},
{
"path": "tests/with_bad_toml/pyproject.toml",
"chars": 121,
"preview": "[tool.black]\nskip-string-normalization = true\n# This line is (a) in the wrong file, and (b) invalid syntax\nblack-config="
},
{
"path": "tests/with_pyproject_toml/ignoring_toml.txt",
"chars": 78,
"preview": "with_pyproject_toml/ordinary_quotes.py:10:7: BLK100 Black would make changes.\n"
},
{
"path": "tests/with_pyproject_toml/ordinary_quotes.py",
"chars": 229,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
},
{
"path": "tests/with_pyproject_toml/pyproject.toml",
"chars": 195,
"preview": "[tool.black]\n# This is probably better as an integer,\n# but reasonable to cope with it as str:\nline-length = \"88\"\nskip-s"
},
{
"path": "tests/without_pyproject_toml/ordinary_quotes.py",
"chars": 229,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\"\"\"Print 'Hello world' to the terminal.\n\nThis is a simple test script usin"
}
]
About this extraction
This page contains the full source code of the peterjc/flake8-black GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (35.4 KB), approximately 10.2k tokens, and a symbol index with 13 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.