From 06db5a454eba061ebc0475a63c41cff6fcbbba7f Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 20 Mar 2024 14:48:29 +0100 Subject: [PATCH 01/11] add basic sphinx & readthedocs stuff --- .readthedocs.yaml | 33 +++++++++++++++++++++++++++++++++ docs/Makefile | 20 ++++++++++++++++++++ docs/make.bat | 35 +++++++++++++++++++++++++++++++++++ docs/source/conf.py | 37 +++++++++++++++++++++++++++++++++++++ docs/source/index.rst | 20 ++++++++++++++++++++ 5 files changed, 145 insertions(+) create mode 100644 .readthedocs.yaml create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/conf.py create mode 100644 docs/source/index.rst diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..7f972414 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,33 @@ +--- +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the OS, Python version and other tools you might need +build: + os: ubuntu-lts-latest + tools: + python: latest + # You can also specify other tool versions: + # nodejs: "19" + # rust: "1.64" + # golang: "1.19" + +# Build documentation in the "docs/" directory with Sphinx +sphinx: + configuration: docs/conf.py + +# Optionally build your docs in additional formats such as PDF and ePub +# formats: +# - pdf +# - epub + +# Optional but recommended, declare the Python requirements required +# to build your documentation +# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..dc1312ab --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..5fb5fe49 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,37 @@ +"""Configuration file for the Sphinx documentation builder. + +For the full list of built-in configuration values, see the documentation: +https://www.sphinx-doc.org/en/master/usage/configuration.html +""" + +import flake8_async + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "flake8-async" +# A001: shadowing python builtin +copyright = "2024, Zac Hatfield-Dodds, John Litborn, and Contributors" # noqa: A001 +author = "Zac Hatfield-Dodds, John Litborn, and Contributors" + + +version = flake8_async.__version__ +release = version + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions: list[str] = [] + +templates_path = ["_templates"] +exclude_patterns: list[str] = [] + +# Warn about all references to unknown targets +nitpicky = True + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "alabaster" +html_static_path = ["_static"] diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 00000000..14d26b46 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,20 @@ +.. flake8-async documentation master file, created by + sphinx-quickstart on Wed Mar 20 13:37:26 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to flake8-async's documentation! +======================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` From 2ebfb1f557ba88010f77ea364de8fc1cb7cefa91 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 20 Mar 2024 14:56:01 +0100 Subject: [PATCH 02/11] test triggering RTD ci From 07283a531639f615dc649c12183d1aa5dfd3a5dc Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 20 Mar 2024 15:02:41 +0100 Subject: [PATCH 03/11] add __init__, point to correct conf location --- .readthedocs.yaml | 2 +- docs/source/__init__.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 docs/source/__init__.py diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7f972414..a9132bee 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -18,7 +18,7 @@ build: # Build documentation in the "docs/" directory with Sphinx sphinx: - configuration: docs/conf.py + configuration: docs/source/conf.py # Optionally build your docs in additional formats such as PDF and ePub # formats: diff --git a/docs/source/__init__.py b/docs/source/__init__.py new file mode 100644 index 00000000..6e0a7009 --- /dev/null +++ b/docs/source/__init__.py @@ -0,0 +1,4 @@ +"""Documentation for flake8-async. + +Ruff raised INP001 "implicit namespace package" without this file. +""" From e8216e5b2cda6b56b6192ea83be1b8cfcb345b51 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 20 Mar 2024 15:16:31 +0100 Subject: [PATCH 04/11] skip separating source dir, add path to flake8_async in sys.path --- docs/Makefile | 4 ++-- docs/{source => }/__init__.py | 0 docs/{source => }/conf.py | 6 +++++- docs/{source => }/index.rst | 0 4 files changed, 7 insertions(+), 3 deletions(-) rename docs/{source => }/__init__.py (100%) rename docs/{source => }/conf.py (88%) rename docs/{source => }/index.rst (100%) diff --git a/docs/Makefile b/docs/Makefile index d0c3cbf1..d4bb2cbb 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -5,8 +5,8 @@ # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build +SOURCEDIR = . +BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: diff --git a/docs/source/__init__.py b/docs/__init__.py similarity index 100% rename from docs/source/__init__.py rename to docs/__init__.py diff --git a/docs/source/conf.py b/docs/conf.py similarity index 88% rename from docs/source/conf.py rename to docs/conf.py index 5fb5fe49..e8d17beb 100644 --- a/docs/source/conf.py +++ b/docs/conf.py @@ -4,6 +4,10 @@ https://www.sphinx-doc.org/en/master/usage/configuration.html """ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path("..").resolve())) import flake8_async # -- Project information ----------------------------------------------------- @@ -24,7 +28,7 @@ extensions: list[str] = [] templates_path = ["_templates"] -exclude_patterns: list[str] = [] +exclude_patterns: list[str] = ["_build", "Thumbs.db", ".DS_Store"] # Warn about all references to unknown targets nitpicky = True diff --git a/docs/source/index.rst b/docs/index.rst similarity index 100% rename from docs/source/index.rst rename to docs/index.rst From edeafaa3f527e7dd74fddb8c5bde6c01bdfea58c Mon Sep 17 00:00:00 2001 From: jakkdl Date: Wed, 20 Mar 2024 15:17:39 +0100 Subject: [PATCH 05/11] update readthedocs.yaml --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a9132bee..7f972414 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -18,7 +18,7 @@ build: # Build documentation in the "docs/" directory with Sphinx sphinx: - configuration: docs/source/conf.py + configuration: docs/conf.py # Optionally build your docs in additional formats such as PDF and ePub # formats: From ef55fe1bbced0d1d97bc7b58e735e7660ecce09f Mon Sep 17 00:00:00 2001 From: jakkdl Date: Fri, 12 Apr 2024 13:23:02 +0200 Subject: [PATCH 06/11] add docs/requirements.txt, add tox target for making docs, silence a warning --- .readthedocs.yaml | 6 +++--- docs/conf.py | 4 +++- docs/requirements.txt | 1 + tox.ini | 12 ++++++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 docs/requirements.txt diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7f972414..f46cd713 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -28,6 +28,6 @@ sphinx: # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt +python: + install: + - requirements: docs/requirements.txt diff --git a/docs/conf.py b/docs/conf.py index e8d17beb..830d78b4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,4 +38,6 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "alabaster" -html_static_path = ["_static"] +# We don't currently use the _static directory, and git doesn't allow empty directories, +# so leaving it commented out for now to silence a warning. +# `html_static_path = ["_static"]` diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..d3a945f2 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +libcst diff --git a/tox.ini b/tox.ini index b7e9febc..761ce975 100644 --- a/tox.ini +++ b/tox.ini @@ -20,6 +20,18 @@ deps = commands = pytest {posargs:-n auto} +[testenv:docs] +description = Generate docs locally +deps = + sphinx + readthedocs-sphinx-ext + -r docs/requirements.txt +allowlist_externals = make +changedir = docs +skip_install = True +commands = + make html + # Settings for other tools [pytest] addopts = From dbde890be7b661eef093112d5062a81a1943ae74 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:25:04 +0000 Subject: [PATCH 07/11] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .readthedocs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f46cd713..07156efb 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -29,5 +29,5 @@ sphinx: # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: - install: - - requirements: docs/requirements.txt + install: + - requirements: docs/requirements.txt From 0b7c3f7ae967dc8225ca7d8058a9aac2dfcb002e Mon Sep 17 00:00:00 2001 From: jakkdl Date: Fri, 12 Apr 2024 16:38:22 +0200 Subject: [PATCH 08/11] slowly getting there.... credits to Claude for converting the markdown to rst --- docs/index.rst | 204 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 14d26b46..39bbf3af 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,18 +3,220 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to flake8-async's documentation! +flake8-async ======================================== .. toctree:: :maxdepth: 2 :caption: Contents: + rules Indices and tables ================== +* :doc:`rules` * :ref:`genindex` * :ref:`modindex` * :ref:`search` + + +A highly opinionated flake8 plugin for problems related to `Trio `_, `AnyIO `_, or `asyncio `_. +This can include anything from outright bugs, to pointless/dead code, +to likely performance issues, to minor points of idiom that might signal +a misunderstanding. +It may well be too noisy for anyone with different opinions, that's OK. +Pairs well with flake8-bugbear. +Some checks are incorporated into `ruff `_. +This plugin was previously known as flake8-trio, and there was a separate small plugin known as flake8-async for asyncio. But this plugin was a superset of the checks in flake8-async, and support for anyio was added, so it's now named flake8-async to more properly convey its usage. At the same time all error codes were renamed from TRIOxxx to ASYNCxxx, as was previously used by the old flake8-async. + +Installation +------------ + +.. code-block:: console + + pip install flake8-async + +Usage +-------- + +install and run through flake8 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: sh + + pip install flake8 flake8-async + flake8 . + +install and run with pre-commit +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you use `pre-commit `_, you can use it with flake8-async by +adding the following to your ``.pre-commit-config.yaml``: + +.. code-block:: yaml + + minimum_pre_commit_version: '2.9.0' + repos: + - repo: https://github.com/python-trio/flake8-async + rev: 23.2.5 + hooks: + - id: flake8-async + # args: [--enable=ASYNC, --disable=ASYNC9, --autofix=ASYNC] + +This is often considerably faster for large projects, because ``pre-commit`` +can avoid running ``flake8-async`` on unchanged files. +Afterwards, run + +.. code-block:: sh + + pip install pre-commit flake8-async + pre-commit run . + +install and run as standalone +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If inside a git repository, running without arguments will run it against all ``*.py`` files in the repository. + +.. code-block:: sh + + pip install flake8-async + flake8-async + +with autofixes +"""""""""""""" + +.. code-block:: sh + + flake8-async --autofix=ASYNC + +specifying source files +""""""""""""""""""""""" + +.. code-block:: sh + + flake8-async my_python_file.py + +zsh-only +'''''''' + +.. code-block:: zsh + + flake8-async **/*.py + + +Run through ruff +^^^^^^^^^^^^^^^^ +`Ruff ` is a linter and formatter that reimplements a lot of rules from various flake8 plugins. They currently only support a small subset of the rules though, see https://github.com/astral-sh/ruff/issues/8451 for current status and https://docs.astral.sh/ruff/rules/#flake8-async-async for documentation. + +Configuration +------------- + +`You can configure flake8 with command-line options `_, +but we prefer using a config file. The file needs to start with a section marker ``[flake8]`` and the following options are then parsed using flake8's config parser, and can be used just like any other flake8 options. +Note that it's not currently possible to use a configuration file when running ``flake8-async`` standalone. + +``ValueError`` when trying to ``ignore`` error codes in config file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Error codes with more than three letters are not possible to ``ignore`` in +config files since flake8>=6, as flake8 tries to validate correct +configuration with a regex. We have decided not to conform to this, as it +would be a breaking change for end-users requiring them to update ``noqa``\ s +and configurations, we think the ``ASYNC`` code is much more readable than +e.g. ``ASYxxx``, and ruff does not enforce such a limit. The easiest option +for users hitting this error is to instead use the ``--disable`` option as +documented `below <#--disable>`__. See further discussion and other +workarounds in https://github.com/python-trio/flake8-async/issues/230. + + +``--enable`` +^^^^^^^^^^^^ + +Comma-separated list of error codes to enable, similar to flake8 --select but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors. + +``--disable`` +^^^^^^^^^^^^^ + +Comma-separated list of error codes to disable, similar to flake8 --ignore but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors. + +``--autofix`` +^^^^^^^^^^^^^ + +Comma-separated list of error-codes to enable autofixing for if implemented. Requires running as a standalone program. Pass ``--autofix=ASYNC`` to enable all autofixes. + + +``--error-on-autofix`` +^^^^^^^^^^^^^^^^^^^^^^ + +Whether to also print an error message for autofixed errors. + +``--anyio`` +^^^^^^^^^^^ + +Change the default library to be anyio instead of trio. If trio is imported it will assume both are available and print suggestions with [anyio/trio]. + +``no-checkpoint-warning-decorators`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Comma-separated list of decorators to disable checkpointing checks for, turning off ASYNC910 and ASYNC911 warnings for functions decorated with any decorator matching any in the list. Matching is done with `fnmatch `_. Defaults to disabling for ``asynccontextmanager``. + +Decorators-to-match must be identifiers or dotted names only (not PEP-614 expressions), and will match against the name only - e.g. ``foo.bar`` matches ``foo.bar``, ``foo.bar()``, and ``foo.bar(args, here)``, etc. + +For example: + +:: + + no-checkpoint-warning-decorators = + mydecorator, + mydecoratorpackage.checkpointing_decorators.*, + ign*, + *.ignore, + +``startable-in-context-manager`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Comma-separated list of methods which should be used with ``.start()`` when opening a context manager, +in addition to the default ``trio.run_process``, ``trio.serve_tcp``, ``trio.serve_ssl_over_tcp``, and +``trio.serve_listeners``. Names must be valid identifiers as per ``str.isidentifier()``. For example: + +:: + + startable-in-context-manager = + myfun, + myfun2, + +.. async200-blocking-calls: + +``async200-blocking-calls`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Comma-separated list of pairs of values separated by ``->`` (optional whitespace stripped), where the first is a pattern for a call that should raise an error if found inside an async function, and the second is what should be suggested to use instead. It uses fnmatch as per `no-checkpoint-warning-decorators`_ for matching. The part after ``->`` is not used by the checker other than when printing the error, so you could add extra info there if you want. + +The format of the error message is ``User-configured blocking sync call {0} in async function, consider replacing with {1}.``, where ``{0}`` is the pattern the call matches and ``{1}`` is the suggested replacement. + +Example: + +:: + + async200-blocking-calls = + my_blocking_call -> async.alternative, + module.block_call -> other_function_to_use, + common_error_call -> alternative(). But sometimes you should use other_function(). Ask joe if you're unsure which one, + dangerous_module.* -> corresponding function in safe_module, + *.dangerous_call -> .safe_call() + +Specified patterns must not have parentheses, and will only match when the pattern is the name of a call, so given the above configuration + +:: + + async def my_function(): + my_blocking_call() # this would raise an error + x = my_blocking_call(a, b, c) # as would this + y = my_blocking_call # but not this + y() # or this + [my_blocking_call][0]() # nor this + def my_blocking_call(): # it's also safe to use the name in other contexts + ... + arbitrary_other_function(my_blocking_call=None) From 1a4d5efa7d9f76b2da59894c307435c5acbc00ce Mon Sep 17 00:00:00 2001 From: jakkdl Date: Mon, 15 Apr 2024 11:23:09 +0200 Subject: [PATCH 09/11] break out rules.rst and usage.rst, various small updates --- docs/index.rst | 219 +++++-------------------------------------------- docs/rules.rst | 55 +++++++++++++ docs/usage.rst | 207 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 284 insertions(+), 197 deletions(-) create mode 100644 docs/rules.rst create mode 100644 docs/usage.rst diff --git a/docs/index.rst b/docs/index.rst index 39bbf3af..ddebd9ca 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,220 +3,45 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +############ flake8-async -======================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - rules +############ -Indices and tables -================== - -* :doc:`rules` -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +A highly opinionated flake8 plugin for problems related to `Trio `_, `AnyIO `_, or `asyncio `_. -A highly opinionated flake8 plugin for problems related to `Trio `_, `AnyIO `_, or `asyncio `_. This can include anything from outright bugs, to pointless/dead code, to likely performance issues, to minor points of idiom that might signal a misunderstanding. -It may well be too noisy for anyone with different opinions, that's OK. -Pairs well with flake8-bugbear. -Some checks are incorporated into `ruff `_. -This plugin was previously known as flake8-trio, and there was a separate small plugin known as flake8-async for asyncio. But this plugin was a superset of the checks in flake8-async, and support for anyio was added, so it's now named flake8-async to more properly convey its usage. At the same time all error codes were renamed from TRIOxxx to ASYNCxxx, as was previously used by the old flake8-async. - -Installation ------------- - -.. code-block:: console - - pip install flake8-async - -Usage --------- - -install and run through flake8 -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: sh - - pip install flake8 flake8-async - flake8 . - -install and run with pre-commit -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you use `pre-commit `_, you can use it with flake8-async by -adding the following to your ``.pre-commit-config.yaml``: - -.. code-block:: yaml - - minimum_pre_commit_version: '2.9.0' - repos: - - repo: https://github.com/python-trio/flake8-async - rev: 23.2.5 - hooks: - - id: flake8-async - # args: [--enable=ASYNC, --disable=ASYNC9, --autofix=ASYNC] - -This is often considerably faster for large projects, because ``pre-commit`` -can avoid running ``flake8-async`` on unchanged files. -Afterwards, run - -.. code-block:: sh - - pip install pre-commit flake8-async - pre-commit run . - -install and run as standalone -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If inside a git repository, running without arguments will run it against all ``*.py`` files in the repository. - -.. code-block:: sh - - pip install flake8-async - flake8-async - -with autofixes -"""""""""""""" - -.. code-block:: sh - - flake8-async --autofix=ASYNC - -specifying source files -""""""""""""""""""""""" - -.. code-block:: sh - - flake8-async my_python_file.py -zsh-only -'''''''' -.. code-block:: zsh - - flake8-async **/*.py - - -Run through ruff -^^^^^^^^^^^^^^^^ -`Ruff ` is a linter and formatter that reimplements a lot of rules from various flake8 plugins. They currently only support a small subset of the rules though, see https://github.com/astral-sh/ruff/issues/8451 for current status and https://docs.astral.sh/ruff/rules/#flake8-async-async for documentation. - -Configuration -------------- - -`You can configure flake8 with command-line options `_, -but we prefer using a config file. The file needs to start with a section marker ``[flake8]`` and the following options are then parsed using flake8's config parser, and can be used just like any other flake8 options. -Note that it's not currently possible to use a configuration file when running ``flake8-async`` standalone. - -``ValueError`` when trying to ``ignore`` error codes in config file -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Error codes with more than three letters are not possible to ``ignore`` in -config files since flake8>=6, as flake8 tries to validate correct -configuration with a regex. We have decided not to conform to this, as it -would be a breaking change for end-users requiring them to update ``noqa``\ s -and configurations, we think the ``ASYNC`` code is much more readable than -e.g. ``ASYxxx``, and ruff does not enforce such a limit. The easiest option -for users hitting this error is to instead use the ``--disable`` option as -documented `below <#--disable>`__. See further discussion and other -workarounds in https://github.com/python-trio/flake8-async/issues/230. - - -``--enable`` -^^^^^^^^^^^^ - -Comma-separated list of error codes to enable, similar to flake8 --select but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors. - -``--disable`` -^^^^^^^^^^^^^ - -Comma-separated list of error codes to disable, similar to flake8 --ignore but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors. - -``--autofix`` -^^^^^^^^^^^^^ - -Comma-separated list of error-codes to enable autofixing for if implemented. Requires running as a standalone program. Pass ``--autofix=ASYNC`` to enable all autofixes. - - -``--error-on-autofix`` -^^^^^^^^^^^^^^^^^^^^^^ - -Whether to also print an error message for autofixed errors. - -``--anyio`` -^^^^^^^^^^^ - -Change the default library to be anyio instead of trio. If trio is imported it will assume both are available and print suggestions with [anyio/trio]. - -``no-checkpoint-warning-decorators`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Comma-separated list of decorators to disable checkpointing checks for, turning off ASYNC910 and ASYNC911 warnings for functions decorated with any decorator matching any in the list. Matching is done with `fnmatch `_. Defaults to disabling for ``asynccontextmanager``. - -Decorators-to-match must be identifiers or dotted names only (not PEP-614 expressions), and will match against the name only - e.g. ``foo.bar`` matches ``foo.bar``, ``foo.bar()``, and ``foo.bar(args, here)``, etc. - -For example: - -:: - - no-checkpoint-warning-decorators = - mydecorator, - mydecoratorpackage.checkpointing_decorators.*, - ign*, - *.ignore, - -``startable-in-context-manager`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Comma-separated list of methods which should be used with ``.start()`` when opening a context manager, -in addition to the default ``trio.run_process``, ``trio.serve_tcp``, ``trio.serve_ssl_over_tcp``, and -``trio.serve_listeners``. Names must be valid identifiers as per ``str.isidentifier()``. For example: - -:: - - startable-in-context-manager = - myfun, - myfun2, +The plugin may well be too noisy or pedantic depending on your requirements or opinions, in which case you should consider :ref:`--disable` for those rules. +Pairs well with flake8-bugbear. -.. async200-blocking-calls: -``async200-blocking-calls`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Some checks are incorporated into `ruff `_. -Comma-separated list of pairs of values separated by ``->`` (optional whitespace stripped), where the first is a pattern for a call that should raise an error if found inside an async function, and the second is what should be suggested to use instead. It uses fnmatch as per `no-checkpoint-warning-decorators`_ for matching. The part after ``->`` is not used by the checker other than when printing the error, so you could add extra info there if you want. -The format of the error message is ``User-configured blocking sync call {0} in async function, consider replacing with {1}.``, where ``{0}`` is the pattern the call matches and ``{1}`` is the suggested replacement. +This plugin was previously known as flake8-trio, and there was a separate small plugin known as flake8-async for asyncio. But this plugin was a superset of the checks in flake8-async, and support for anyio was added, so it's now named flake8-async to more properly convey its usage. At the same time all error codes were renamed from TRIOxxx to ASYNCxxx, as was previously used by the old flake8-async. -Example: -:: +********* +Contents: +********* +.. toctree:: + :maxdepth: 2 - async200-blocking-calls = - my_blocking_call -> async.alternative, - module.block_call -> other_function_to_use, - common_error_call -> alternative(). But sometimes you should use other_function(). Ask joe if you're unsure which one, - dangerous_module.* -> corresponding function in safe_module, - *.dangerous_call -> .safe_call() + usage + rules -Specified patterns must not have parentheses, and will only match when the pattern is the name of a call, so given the above configuration -:: +****************** +Indices and tables +****************** - async def my_function(): - my_blocking_call() # this would raise an error - x = my_blocking_call(a, b, c) # as would this - y = my_blocking_call # but not this - y() # or this - [my_blocking_call][0]() # nor this - def my_blocking_call(): # it's also safe to use the name in other contexts - ... - arbitrary_other_function(my_blocking_call=None) +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` +* :doc:`usage` +* :doc:`rules` diff --git a/docs/rules.rst b/docs/rules.rst new file mode 100644 index 00000000..3b6f378d --- /dev/null +++ b/docs/rules.rst @@ -0,0 +1,55 @@ +List of warnings +------------------ + +- **ASYNC100**: A ``with [trio/anyio].fail_after(...):`` or ``with [trio/anyio].move_on_after(...):`` context does not contain any ``await`` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint. This check also allows ``yield`` statements, since checkpoints can happen in the caller we yield to. +- **ASYNC101**: ``yield`` inside a trio/anyio nursery or cancel scope is only safe when implementing a context manager - otherwise, it breaks exception handling. +- **ASYNC102**: It's unsafe to await inside ``finally:`` or ``except BaseException/trio.Cancelled/anyio.get_cancelled_exc_class()/asyncio.exceptions.CancelledError`` unless you use a shielded cancel scope with a timeout. This is currently not able to detect asyncio shields. +- **ASYNC103**: ``except BaseException/trio.Cancelled/anyio.get_cancelled_exc_class()/asyncio.exceptions.CancelledError``, or a bare ``except:`` with a code path that doesn't re-raise. If you don't want to re-raise ``BaseException``, add a separate handler for ``trio.Cancelled``/``anyio.get_cancelled_exc_class()``/``asyncio.exceptions.CancelledError`` before. +- **ASYNC104**: ``trio.Cancelled``/``anyio.get_cancelled_exc_class()``/``asyncio.exceptions.CancelledError``/``BaseException`` must be re-raised. The same as ASYNC103, except specifically triggered on ``return`` or a different exception being raised. +- **ASYNC105**: Calling a trio async function without immediately ``await``\ ing it. This is only supported with trio functions, but you can get similar functionality with a type-checker. +- **ASYNC106**: ``trio``/``anyio``/``asyncio`` must be imported with ``import trio``/``import anyio``/``import asyncio`` for the linter to work. +- **ASYNC109**: Async function definition with a ``timeout`` parameter - use ``[trio/anyio].[fail/move_on]_[after/at]`` instead. +- **ASYNC110**: ``while : await [trio/anyio].sleep()`` should be replaced by a ``[trio/anyio].Event``. +- **ASYNC111**: Variable, from context manager opened inside nursery, passed to ``start[_soon]`` might be invalidly accessed while in use, due to context manager closing before the nursery. This is usually a bug, and nurseries should generally be the inner-most context manager. +- **ASYNC112**: Nursery body with only a call to ``nursery.start[_soon]`` and not passing itself as a parameter can be replaced with a regular function call. +- **ASYNC113**: Using ``nursery.start_soon`` in ``__aenter__`` doesn't wait for the task to begin. Consider replacing with ``nursery.start``. +- **ASYNC114**: Startable function (i.e. has a ``task_status`` keyword parameter) not in ``--startable-in-context-manager`` parameter list, please add it so ASYNC113 can catch errors when using it. +- **ASYNC115**: Replace ``[trio/anyio].sleep(0)`` with the more suggestive ``[trio/anyio].lowlevel.checkpoint()``. +- **ASYNC116**: ``[trio/anyio].sleep()`` with >24 hour interval should usually be ``[trio/anyio].sleep_forever()``. +- **ASYNC118**: Don't assign the value of ``anyio.get_cancelled_exc_class()`` to a variable, since that breaks linter checks and multi-backend programs. + +Warnings for blocking sync calls in async functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Note: 22X, 23X and 24X has not had asyncio-specific suggestions written. + + +- **ASYNC200**: User-configured error for blocking sync calls in async functions. Does nothing by default, see :ref:`async200-blocking-calls` for how to configure it. +- **ASYNC210**: Sync HTTP call in async function, use ``httpx.AsyncClient``. This and the other ASYNC21x checks look for usage of ``urllib3`` and ``httpx.Client``, and recommend using ``httpx.AsyncClient`` as that's the largest http client supporting anyio/trio. +- **ASYNC211**: Likely sync HTTP call in async function, use ``httpx.AsyncClient``. Looks for ``urllib3`` method calls on pool objects, but only matching on the method signature and not the object. +- **ASYNC212**: Blocking sync HTTP call on httpx object, use httpx.AsyncClient. +- **ASYNC220**: Sync process call in async function, use ``await nursery.start([trio/anyio].run_process, ...)``. ``asyncio`` users can use `asyncio.create_subprocess_[exec/shell] `_. +- **ASYNC221**: Sync process call in async function, use ``await [trio/anyio].run_process(...)``. ``asyncio`` users can use `asyncio.create_subprocess_[exec/shell] `_. +- **ASYNC222**: Sync ``os.*`` call in async function, wrap in ``await [trio/anyio].to_thread.run_sync()``. ``asyncio`` users can use `asyncio.loop.run_in_executor `_. +- **ASYNC230**: Sync IO call in async function, use ``[trio/anyio].open_file(...)``. ``asyncio`` users need to use a library such as `aiofiles `_, or switch to `anyio `_. +- **ASYNC231**: Sync IO call in async function, use ``[trio/anyio].wrap_file(...)``. ``asyncio`` users need to use a library such as `aiofiles `_, or switch to `anyio `_. +- **ASYNC232**: Blocking sync call on file object, wrap the file object in ``[trio/anyio].wrap_file()`` to get an async file object. +- **ASYNC240**: Avoid using ``os.path`` in async functions, prefer using ``[trio/anyio].Path`` objects. ``asyncio`` users should consider `aiopath `_ or `anyio `_. +- **ASYNC250**: Builtin ``input()`` should not be called from async function. Wrap in ``[trio/anyio].to_thread.run_sync()`` or ``asyncio.loop.run_in_executor()``. +- **ASYNC251**: ``time.sleep(...)`` should not be called from async function. Use ``[trio/anyio/asyncio].sleep(...)``. + +Warnings disabled by default +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- **ASYNC900**: Async generator without ``@asynccontextmanager`` not allowed. You might want to enable this on a codebase since async generators are inherently unsafe and cleanup logic might not be performed. See https://github.com/python-trio/flake8-async/issues/211 and https://discuss.python.org/t/using-exceptiongroup-at-anthropic-experience-report/20888/6 for discussion. +- **ASYNC910**: Exit or ``return`` from async function with no guaranteed checkpoint or exception since function definition. You might want to enable this on a codebase to make it easier to reason about checkpoints, and make the logic of ASYNC911 correct. +- **ASYNC911**: Exit, ``yield`` or ``return`` from async iterable with no guaranteed checkpoint since possible function entry (yield or function definition) + Checkpoints are ``await``, ``async for``, and ``async with`` (on one of enter/exit). + +Removed warnings +~~~~~~~~~~~~~~~~ + +- **TRIOxxx**: All error codes are now renamed ASYNCxxx +- **TRIO107**: Renamed to TRIO910 +- **TRIO108**: Renamed to TRIO911 +- **TRIO117**: Don't raise diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 00000000..2cadfbac --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,207 @@ +************ +Installation +************ + +.. code-block:: console + + pip install flake8-async + +***** +Usage +***** + +install and run through flake8 +============================== + +.. code-block:: sh + + pip install flake8 flake8-async + flake8 . + +install and run with pre-commit +=============================== + +If you use `pre-commit `_, you can use it with flake8-async by +adding the following to your ``.pre-commit-config.yaml``: + +.. code-block:: yaml + + minimum_pre_commit_version: '2.9.0' + repos: + - repo: https://github.com/python-trio/flake8-async + rev: 23.2.5 + hooks: + - id: flake8-async + # args: [--enable=ASYNC, --disable=ASYNC9, --autofix=ASYNC] + +This is often considerably faster for large projects, because ``pre-commit`` +can avoid running ``flake8-async`` on unchanged files. +Afterwards, run + +.. code-block:: sh + + pip install pre-commit flake8-async + pre-commit run . + +install and run as standalone +============================= + +If inside a git repository, running without arguments will run it against all ``*.py`` files in the repository. + +.. code-block:: sh + + pip install flake8-async + flake8-async + +with autofixes +-------------- + +.. code-block:: sh + + flake8-async --autofix=ASYNC + +specifying source files +----------------------- + +.. code-block:: sh + + flake8-async my_python_file.py + +zsh-only +^^^^^^^^ + +.. code-block:: zsh + + flake8-async **/*.py + + +Run through ruff +================ +`Ruff ` is a linter and formatter that reimplements a lot of rules from various flake8 plugins. They currently only support a small subset of the rules though, see https://github.com/astral-sh/ruff/issues/8451 for current status and https://docs.astral.sh/ruff/rules/#flake8-async-async for documentation. + +************* +Configuration +************* + +`You can configure flake8 with command-line options `_, +but we prefer using a config file. The file needs to start with a section marker ``[flake8]`` and the following options are then parsed using flake8's config parser, and can be used just like any other flake8 options. +Note that it's not currently possible to use a configuration file when running ``flake8-async`` standalone. + +Selecting rules +=============== + +``ValueError`` when trying to ``ignore`` error codes in config file +------------------------------------------------------------------- + +Error codes with more than three letters are not possible to ``ignore`` in +config files since flake8>=6, as flake8 tries to validate correct +configuration with a regex. We have decided not to conform to this, as it +would be a breaking change for end-users requiring them to update ``noqa``\ s +and configurations, we think the ``ASYNC`` code is much more readable than +e.g. ``ASYxxx``, and ruff does not enforce such a limit. The easiest option +for users hitting this error is to instead use the ``--disable`` option as +documented `below <#--disable>`__. See further discussion and other +workarounds in https://github.com/python-trio/flake8-async/issues/230. + + +``--enable`` +------------ + +Comma-separated list of error codes to enable, similar to flake8 --select but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors. + +.. _--disable: + +``--disable`` +------------- + +Comma-separated list of error codes to disable, similar to flake8 ``--ignore`` but is additionally more performant as it will disable non-enabled visitors from running instead of just silencing their errors. It will also bypass errors introduced in flake8>=6, see above. + +``--autofix`` +------------- + +Comma-separated list of error-codes to enable autofixing for if implemented. Requires running as a standalone program. Pass ``--autofix=ASYNC`` to enable all autofixes. + + +``--error-on-autofix`` +---------------------- + +Whether to also print an error message for autofixed errors. + +Modifying rule behaviour +======================== + +.. _--anyio: + +``--anyio`` +----------- + +Change the default library to be anyio instead of trio. If trio is imported it will assume both are available and print suggestions with [anyio/trio]. + +``--asyncio`` +------------- +Set default library to be ``asyncio``. See :ref:`--anyio` + + +``no-checkpoint-warning-decorators`` +------------------------------------ + +Comma-separated list of decorators to disable checkpointing checks for, turning off ASYNC910 and ASYNC911 warnings for functions decorated with any decorator matching any in the list. Matching is done with `fnmatch `_. Defaults to disabling for ``asynccontextmanager``. + +Decorators-to-match must be identifiers or dotted names only (not PEP-614 expressions), and will match against the name only - e.g. ``foo.bar`` matches ``foo.bar``, ``foo.bar()``, and ``foo.bar(args, here)``, etc. + +For example: + +:: + + no-checkpoint-warning-decorators = + mydecorator, + mydecoratorpackage.checkpointing_decorators.*, + ign*, + *.ignore, + +``startable-in-context-manager`` +-------------------------------- + +Comma-separated list of methods which should be used with ``.start()`` when opening a context manager, +in addition to the default ``trio.run_process``, ``trio.serve_tcp``, ``trio.serve_ssl_over_tcp``, and +``trio.serve_listeners``. Names must be valid identifiers as per ``str.isidentifier()``. For example: + +:: + + startable-in-context-manager = + myfun, + myfun2, + +.. async200-blocking-calls: + +``async200-blocking-calls`` +--------------------------- + +Comma-separated list of pairs of values separated by ``->`` (optional whitespace stripped), where the first is a pattern for a call that should raise an error if found inside an async function, and the second is what should be suggested to use instead. It uses fnmatch as per `no-checkpoint-warning-decorators`_ for matching. The part after ``->`` is not used by the checker other than when printing the error, so you could add extra info there if you want. + +The format of the error message is ``User-configured blocking sync call {0} in async function, consider replacing with {1}.``, where ``{0}`` is the pattern the call matches and ``{1}`` is the suggested replacement. + +Example: + +:: + + async200-blocking-calls = + my_blocking_call -> async.alternative, + module.block_call -> other_function_to_use, + common_error_call -> alternative(). But sometimes you should use other_function(). Ask joe if you're unsure which one, + dangerous_module.* -> corresponding function in safe_module, + *.dangerous_call -> .safe_call() + +Specified patterns must not have parentheses, and will only match when the pattern is the name of a call, so given the above configuration + +:: + + async def my_function(): + my_blocking_call() # this would raise an error + x = my_blocking_call(a, b, c) # as would this + y = my_blocking_call # but not this + y() # or this + [my_blocking_call][0]() # nor this + def my_blocking_call(): # it's also safe to use the name in other contexts + ... + arbitrary_other_function(my_blocking_call=None) From 1ca1d96243af4d30548aeb73f40b6405d1e5beb2 Mon Sep 17 00:00:00 2001 From: John Litborn <11260241+jakkdl@users.noreply.github.com> Date: Tue, 16 Apr 2024 13:32:16 +0200 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Zac Hatfield-Dodds --- docs/index.rst | 2 +- docs/usage.rst | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index ddebd9ca..05d3270c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,7 +23,7 @@ Pairs well with flake8-bugbear. Some checks are incorporated into `ruff `_. -This plugin was previously known as flake8-trio, and there was a separate small plugin known as flake8-async for asyncio. But this plugin was a superset of the checks in flake8-async, and support for anyio was added, so it's now named flake8-async to more properly convey its usage. At the same time all error codes were renamed from TRIOxxx to ASYNCxxx, as was previously used by the old flake8-async. +We previously maintained separate flake8-async and flake8-trio plugins, but merged both into this plugin under the more general "flake8-async" name after flake8-trio grew support for anyio and asyncio and became a superset of the former flake8-async. All flake8-trio error codes were renamed from TRIOxxx to ASYNCxxx and the flake8-trio package is now deprecated. ********* diff --git a/docs/usage.rst b/docs/usage.rst index 2cadfbac..a7def4da 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -77,7 +77,9 @@ zsh-only Run through ruff ================ -`Ruff ` is a linter and formatter that reimplements a lot of rules from various flake8 plugins. They currently only support a small subset of the rules though, see https://github.com/astral-sh/ruff/issues/8451 for current status and https://docs.astral.sh/ruff/rules/#flake8-async-async for documentation. +`Ruff `_ is a linter and formatter that reimplements a lot of rules from various flake8 plugins. + +They currently only support a small subset of the rules though, see https://github.com/astral-sh/ruff/issues/8451 for current status and https://docs.astral.sh/ruff/rules/#flake8-async-async for documentation. ************* Configuration From efe6556bf51c5356b7b3622d91a607e800f7bf03 Mon Sep 17 00:00:00 2001 From: jakkdl Date: Tue, 16 Apr 2024 14:54:43 +0200 Subject: [PATCH 11/11] update docs after review --- docs/index.rst | 2 +- docs/rules.rst | 22 +++++++++++++--------- docs/usage.rst | 13 +++++++++---- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 05d3270c..d41e7ff2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -20,7 +20,7 @@ The plugin may well be too noisy or pedantic depending on your requirements or o Pairs well with flake8-bugbear. -Some checks are incorporated into `ruff `_. +Some rules are incorporated into `ruff `_. We previously maintained separate flake8-async and flake8-trio plugins, but merged both into this plugin under the more general "flake8-async" name after flake8-trio grew support for anyio and asyncio and became a superset of the former flake8-async. All flake8-trio error codes were renamed from TRIOxxx to ASYNCxxx and the flake8-trio package is now deprecated. diff --git a/docs/rules.rst b/docs/rules.rst index 3b6f378d..007a5485 100644 --- a/docs/rules.rst +++ b/docs/rules.rst @@ -1,5 +1,9 @@ -List of warnings ------------------- +**************** +List of rules +**************** + +General rules +============= - **ASYNC100**: A ``with [trio/anyio].fail_after(...):`` or ``with [trio/anyio].move_on_after(...):`` context does not contain any ``await`` statements. This makes it pointless, as the timeout can only be triggered by a checkpoint. This check also allows ``yield`` statements, since checkpoints can happen in the caller we yield to. - **ASYNC101**: ``yield`` inside a trio/anyio nursery or cancel scope is only safe when implementing a context manager - otherwise, it breaks exception handling. @@ -18,8 +22,8 @@ List of warnings - **ASYNC116**: ``[trio/anyio].sleep()`` with >24 hour interval should usually be ``[trio/anyio].sleep_forever()``. - **ASYNC118**: Don't assign the value of ``anyio.get_cancelled_exc_class()`` to a variable, since that breaks linter checks and multi-backend programs. -Warnings for blocking sync calls in async functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Blocking sync calls in async functions +====================================== Note: 22X, 23X and 24X has not had asyncio-specific suggestions written. @@ -38,18 +42,18 @@ Note: 22X, 23X and 24X has not had asyncio-specific suggestions written. - **ASYNC250**: Builtin ``input()`` should not be called from async function. Wrap in ``[trio/anyio].to_thread.run_sync()`` or ``asyncio.loop.run_in_executor()``. - **ASYNC251**: ``time.sleep(...)`` should not be called from async function. Use ``[trio/anyio/asyncio].sleep(...)``. -Warnings disabled by default -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Optional rules disabled by default +================================== - **ASYNC900**: Async generator without ``@asynccontextmanager`` not allowed. You might want to enable this on a codebase since async generators are inherently unsafe and cleanup logic might not be performed. See https://github.com/python-trio/flake8-async/issues/211 and https://discuss.python.org/t/using-exceptiongroup-at-anthropic-experience-report/20888/6 for discussion. - **ASYNC910**: Exit or ``return`` from async function with no guaranteed checkpoint or exception since function definition. You might want to enable this on a codebase to make it easier to reason about checkpoints, and make the logic of ASYNC911 correct. - **ASYNC911**: Exit, ``yield`` or ``return`` from async iterable with no guaranteed checkpoint since possible function entry (yield or function definition) Checkpoints are ``await``, ``async for``, and ``async with`` (on one of enter/exit). -Removed warnings -~~~~~~~~~~~~~~~~ +Removed rules +================ - **TRIOxxx**: All error codes are now renamed ASYNCxxx - **TRIO107**: Renamed to TRIO910 - **TRIO108**: Renamed to TRIO911 -- **TRIO117**: Don't raise +- **TRIO117**: "Don't raise or catch ``trio.[NonBase]MultiError``, prefer ``[exceptiongroup.]BaseExceptionGroup``." ``MultiError`` was removed in trio==0.24.0. diff --git a/docs/usage.rst b/docs/usage.rst index a7def4da..78aba3bc 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -18,6 +18,8 @@ install and run through flake8 pip install flake8 flake8-async flake8 . +.. _install-run-pre-commit: + install and run with pre-commit =============================== @@ -85,9 +87,12 @@ They currently only support a small subset of the rules though, see https://gith Configuration ************* -`You can configure flake8 with command-line options `_, -but we prefer using a config file. The file needs to start with a section marker ``[flake8]`` and the following options are then parsed using flake8's config parser, and can be used just like any other flake8 options. -Note that it's not currently possible to use a configuration file when running ``flake8-async`` standalone. +`You can configure flake8 with command-line options `_, +but we prefer using a config file. See general documentation for `configuring flake8 `_ which also handles options registered by plugins such as ``flake8-async``. + +If you want to use a ``pyproject.toml`` file for configuring flake8 we recommend `pyproject-flake8 ` or similar. + +Note that when running ``flake8-async`` as a standalone it's not currently possible to use a configuration file. Consider using some wrapper that lets you specify command-line flags in a file. For example, :ref:`install-run-pre-commit`, `tox `, `hatch scripts `, MakeFiles, etc. Selecting rules =============== @@ -174,7 +179,7 @@ in addition to the default ``trio.run_process``, ``trio.serve_tcp``, ``trio.serv myfun, myfun2, -.. async200-blocking-calls: +.. _async200-blocking-calls: ``async200-blocking-calls`` ---------------------------