diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bbb18337..ad60be1d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: - id: black args: [--line-length=79] - repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 + rev: 7.0.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy diff --git a/docs/source/conf.py b/docs/source/conf.py index a2b4af3e..48f8a524 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -34,7 +34,7 @@ "sphinx.ext.todo", "sphinx.ext.coverage", "sphinx.ext.viewcode", - "sphinx-prompt", + "sphinx_prompt", ] # Add any paths that contain templates here, relative to this directory. @@ -296,7 +296,11 @@ # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)} +intersphinx_mapping = { + "python": ("https://docs.python.org/3/", None), + "packaging": ("https://packaging.python.org/en/latest/", None), + "setuptools": ("https://setuptools.pypa.io/en/latest/", None), +} extlinks = { "issue": ("https://github.com/pycqa/flake8/issues/%s", "#%s"), diff --git a/docs/source/plugin-development/index.rst b/docs/source/plugin-development/index.rst index c89e5f0e..90889429 100644 --- a/docs/source/plugin-development/index.rst +++ b/docs/source/plugin-development/index.rst @@ -30,7 +30,8 @@ To get started writing a |Flake8| :term:`plugin` you first need: Once you've gathered these things, you can get started. -All plugins for |Flake8| must be registered via `entry points`_. In this +All plugins for |Flake8| must be registered via +:external+packaging:doc:`entry points`. In this section we cover: - How to register your plugin so |Flake8| can find it @@ -54,6 +55,8 @@ Here's a tutorial which goes over building an ast checking plugin from scratch: +Detailed Plugin Development Documentation +========================================= .. toctree:: :caption: Plugin Developer Documentation @@ -62,7 +65,3 @@ Here's a tutorial which goes over building an ast checking plugin from scratch: registering-plugins plugin-parameters formatters - - -.. _entry points: - https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points diff --git a/docs/source/plugin-development/registering-plugins.rst b/docs/source/plugin-development/registering-plugins.rst index ca740088..964ff99f 100644 --- a/docs/source/plugin-development/registering-plugins.rst +++ b/docs/source/plugin-development/registering-plugins.rst @@ -12,16 +12,17 @@ To register any kind of plugin with |Flake8|, you need: #. A name for your plugin that will (ideally) be unique. -#. A somewhat recent version of setuptools (newer than 0.7.0 but preferably as - recent as you can attain). - -|Flake8| relies on functionality provided by setuptools called -`Entry Points`_. These allow any package to register a plugin with |Flake8| -via that package's ``setup.py`` file. +|Flake8| relies on functionality provided by build tools called +:external+packaging:doc:`entry points`. These +allow any package to register a plugin with |Flake8| via that package's +metadata. Let's presume that we already have our plugin written and it's in a module -called ``flake8_example``. We might have a ``setup.py`` that looks something -like: +called ``flake8_example``. We will also assume ``setuptools`` is used as a +:external+packaging:term:`Build Backend`, but be aware that most backends +support entry points. + +We might have a ``setup.py`` that looks something like: .. code-block:: python @@ -150,5 +151,7 @@ If your plugin is intended to be opt-in, it can set the attribute :ref:`enable-extensions` with your plugin's entry point. -.. _Entry Points: - https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points +.. seealso:: + + The :external+setuptools:doc:`setuptools user guide ` + about entry points. diff --git a/docs/source/release-notes/7.1.0.rst b/docs/source/release-notes/7.1.0.rst new file mode 100644 index 00000000..2229baab --- /dev/null +++ b/docs/source/release-notes/7.1.0.rst @@ -0,0 +1,13 @@ +7.1.0 -- 2024-06-15 +------------------- + +You can view the `7.1.0 milestone`_ on GitHub for more details. + +New Dependency Information +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- pycodestyle has been updated to >= 2.12.0, < 2.13.0 (See also :pull:`1939`). + +.. all links +.. _7.1.0 milestone: + https://github.com/PyCQA/flake8/milestone/50 diff --git a/docs/source/release-notes/7.1.1.rst b/docs/source/release-notes/7.1.1.rst new file mode 100644 index 00000000..62f2d11c --- /dev/null +++ b/docs/source/release-notes/7.1.1.rst @@ -0,0 +1,15 @@ +7.1.1 -- 2024-08-04 +------------------- + +You can view the `7.1.1 milestone`_ on GitHub for more details. + +Bugs Fixed +~~~~~~~~~~ + +- Properly preserve escaped `{` and `}` in fstrings in logical lines in 3.12+. + (See also :issue:`1948`, :pull:`1949`). + + +.. all links +.. _7.1.1 milestone: + https://github.com/PyCQA/flake8/milestone/51 diff --git a/docs/source/release-notes/index.rst b/docs/source/release-notes/index.rst index 58c6845e..9bf8646d 100644 --- a/docs/source/release-notes/index.rst +++ b/docs/source/release-notes/index.rst @@ -10,6 +10,8 @@ with the newest releases first. .. toctree:: 7.0.0 + 7.1.0 + 7.1.1 6.x Release Series ================== diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt index 93f773e4..765fb130 100644 --- a/docs/source/requirements.txt +++ b/docs/source/requirements.txt @@ -1,4 +1,4 @@ sphinx>=2.1.0,!=3.1.0 sphinx-rtd-theme>=1.2.2 -sphinx-prompt>=1.5.0 +sphinx-prompt>=1.8.0 docutils!=0.18 diff --git a/docs/source/user/options.rst b/docs/source/user/options.rst index d7677481..bd80c877 100644 --- a/docs/source/user/options.rst +++ b/docs/source/user/options.rst @@ -46,6 +46,8 @@ Index of Options - :option:`flake8 --exclude` +- :option:`flake8 --extend-exclude` + - :option:`flake8 --filename` - :option:`flake8 --stdin-display-name` diff --git a/setup.cfg b/setup.cfg index 2254902d..28e6f933 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,7 +29,7 @@ classifiers = packages = find: install_requires = mccabe>=0.7.0,<0.8.0 - pycodestyle>=2.11.0,<2.12.0 + pycodestyle>=2.12.0,<2.13.0 pyflakes>=3.2.0,<3.3.0 python_requires = >=3.8.1 package_dir = diff --git a/src/flake8/__init__.py b/src/flake8/__init__.py index ea7a56de..101eafe7 100644 --- a/src/flake8/__init__.py +++ b/src/flake8/__init__.py @@ -17,7 +17,7 @@ LOG = logging.getLogger(__name__) LOG.addHandler(logging.NullHandler()) -__version__ = "7.0.0" +__version__ = "7.1.1" __version_info__ = tuple(int(i) for i in __version__.split(".") if i.isdigit()) _VERBOSITY_TO_LOG_LEVEL = { diff --git a/src/flake8/processor.py b/src/flake8/processor.py index 21a25e0f..e44547b3 100644 --- a/src/flake8/processor.py +++ b/src/flake8/processor.py @@ -203,7 +203,13 @@ def build_logical_line_tokens(self) -> _Logical: # noqa: C901 if token_type == tokenize.STRING: text = mutate_string(text) elif token_type == FSTRING_MIDDLE: # pragma: >=3.12 cover - text = "x" * len(text) + # A curly brace in an FSTRING_MIDDLE token must be an escaped + # curly brace. Both 'text' and 'end' will account for the + # escaped version of the token (i.e. a single brace) rather + # than the raw double brace version, so we must counteract this + brace_offset = text.count("{") + text.count("}") + text = "x" * (len(text) + brace_offset) + end = (end[0], end[1] + brace_offset) if previous_row: (start_row, start_column) = start if previous_row != start_row: diff --git a/tests/integration/test_plugins.py b/tests/integration/test_plugins.py index d4c22b0b..90ca555a 100644 --- a/tests/integration/test_plugins.py +++ b/tests/integration/test_plugins.py @@ -1,6 +1,8 @@ """Integration tests for plugin loading.""" from __future__ import annotations +import sys + import pytest from flake8.main.cli import main @@ -261,3 +263,36 @@ def test_logical_line_plugin(tmpdir, capsys): """ out, err = capsys.readouterr() assert out == expected + + +def test_escaping_of_fstrings_in_string_redacter(tmpdir, capsys): + cfg_s = f"""\ +[flake8] +extend-ignore = F +[flake8:local-plugins] +extension = + T = {yields_logical_line.__module__}:{yields_logical_line.__name__} +""" + + cfg = tmpdir.join("tox.ini") + cfg.write(cfg_s) + + src = """\ +f'{{"{hello}": "{world}"}}' +""" + t_py = tmpdir.join("t.py") + t_py.write_binary(src.encode()) + + with tmpdir.as_cwd(): + assert main(("t.py", "--config", str(cfg))) == 1 + + if sys.version_info >= (3, 12): # pragma: >=3.12 cover + expected = """\ +t.py:1:1: T001 "f'xxx{hello}xxxx{world}xxx'" +""" + else: # pragma: <3.12 cover + expected = """\ +t.py:1:1: T001 "f'xxxxxxxxxxxxxxxxxxxxxxxx'" +""" + out, err = capsys.readouterr() + assert out == expected