Skip to content

Commit 368b915

Browse files
jakkdlpre-commit-ci[bot]Zac-HD
authored
add basic sphinx & readthedocs infra (#223)
* add basic sphinx & readthedocs setup * copy over most of existing documentation, with some changes. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Zac Hatfield-Dodds <[email protected]>
1 parent 584294c commit 368b915

10 files changed

+468
-0
lines changed

.readthedocs.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
# .readthedocs.yaml
3+
# Read the Docs configuration file
4+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
5+
6+
# Required
7+
version: 2
8+
9+
# Set the OS, Python version and other tools you might need
10+
build:
11+
os: ubuntu-lts-latest
12+
tools:
13+
python: latest
14+
# You can also specify other tool versions:
15+
# nodejs: "19"
16+
# rust: "1.64"
17+
# golang: "1.19"
18+
19+
# Build documentation in the "docs/" directory with Sphinx
20+
sphinx:
21+
configuration: docs/conf.py
22+
23+
# Optionally build your docs in additional formats such as PDF and ePub
24+
# formats:
25+
# - pdf
26+
# - epub
27+
28+
# Optional but recommended, declare the Python requirements required
29+
# to build your documentation
30+
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
31+
python:
32+
install:
33+
- requirements: docs/requirements.txt

docs/Makefile

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line, and also
5+
# from the environment for the first two.
6+
SPHINXOPTS ?=
7+
SPHINXBUILD ?= sphinx-build
8+
SOURCEDIR = .
9+
BUILDDIR = _build
10+
11+
# Put it first so that "make" without argument is like "make help".
12+
help:
13+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14+
15+
.PHONY: help Makefile
16+
17+
# Catch-all target: route all unknown targets to Sphinx using the new
18+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19+
%: Makefile
20+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

docs/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"""Documentation for flake8-async.
2+
3+
Ruff raised INP001 "implicit namespace package" without this file.
4+
"""

docs/conf.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Configuration file for the Sphinx documentation builder.
2+
3+
For the full list of built-in configuration values, see the documentation:
4+
https://www.sphinx-doc.org/en/master/usage/configuration.html
5+
"""
6+
7+
import sys
8+
from pathlib import Path
9+
10+
sys.path.insert(0, str(Path("..").resolve()))
11+
import flake8_async
12+
13+
# -- Project information -----------------------------------------------------
14+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
15+
16+
project = "flake8-async"
17+
# A001: shadowing python builtin
18+
copyright = "2024, Zac Hatfield-Dodds, John Litborn, and Contributors" # noqa: A001
19+
author = "Zac Hatfield-Dodds, John Litborn, and Contributors"
20+
21+
22+
version = flake8_async.__version__
23+
release = version
24+
25+
# -- General configuration ---------------------------------------------------
26+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
27+
28+
extensions: list[str] = []
29+
30+
templates_path = ["_templates"]
31+
exclude_patterns: list[str] = ["_build", "Thumbs.db", ".DS_Store"]
32+
33+
# Warn about all references to unknown targets
34+
nitpicky = True
35+
36+
37+
# -- Options for HTML output -------------------------------------------------
38+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
39+
40+
html_theme = "alabaster"
41+
# We don't currently use the _static directory, and git doesn't allow empty directories,
42+
# so leaving it commented out for now to silence a warning.
43+
# `html_static_path = ["_static"]`

docs/index.rst

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.. flake8-async documentation master file, created by
2+
sphinx-quickstart on Wed Mar 20 13:37:26 2024.
3+
You can adapt this file completely to your liking, but it should at least
4+
contain the root `toctree` directive.
5+
6+
############
7+
flake8-async
8+
############
9+
10+
11+
A highly opinionated flake8 plugin for problems related to `Trio <https://github.com/python-trio/trio>`_, `AnyIO <https://github.com/agronholm/anyio>`_, or `asyncio <https://docs.python.org/3/library/asyncio.html>`_.
12+
13+
14+
This can include anything from outright bugs, to pointless/dead code,
15+
to likely performance issues, to minor points of idiom that might signal
16+
a misunderstanding.
17+
18+
19+
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.
20+
Pairs well with flake8-bugbear.
21+
22+
23+
Some rules are incorporated into `ruff <https://docs.astral.sh/ruff/rules/#flake8-async-async>`_.
24+
25+
26+
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.
27+
28+
29+
*********
30+
Contents:
31+
*********
32+
.. toctree::
33+
:maxdepth: 2
34+
35+
usage
36+
rules
37+
38+
39+
******************
40+
Indices and tables
41+
******************
42+
43+
* :ref:`genindex`
44+
* :ref:`modindex`
45+
* :ref:`search`
46+
* :doc:`usage`
47+
* :doc:`rules`

docs/make.bat

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
@ECHO OFF
2+
3+
pushd %~dp0
4+
5+
REM Command file for Sphinx documentation
6+
7+
if "%SPHINXBUILD%" == "" (
8+
set SPHINXBUILD=sphinx-build
9+
)
10+
set SOURCEDIR=source
11+
set BUILDDIR=build
12+
13+
%SPHINXBUILD% >NUL 2>NUL
14+
if errorlevel 9009 (
15+
echo.
16+
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17+
echo.installed, then set the SPHINXBUILD environment variable to point
18+
echo.to the full path of the 'sphinx-build' executable. Alternatively you
19+
echo.may add the Sphinx directory to PATH.
20+
echo.
21+
echo.If you don't have Sphinx installed, grab it from
22+
echo.https://www.sphinx-doc.org/
23+
exit /b 1
24+
)
25+
26+
if "%1" == "" goto help
27+
28+
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29+
goto end
30+
31+
:help
32+
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33+
34+
:end
35+
popd

docs/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
libcst

docs/rules.rst

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
****************
2+
List of rules
3+
****************
4+
5+
General rules
6+
=============
7+
8+
- **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.
9+
- **ASYNC101**: ``yield`` inside a trio/anyio nursery or cancel scope is only safe when implementing a context manager - otherwise, it breaks exception handling.
10+
- **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.
11+
- **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.
12+
- **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.
13+
- **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.
14+
- **ASYNC106**: ``trio``/``anyio``/``asyncio`` must be imported with ``import trio``/``import anyio``/``import asyncio`` for the linter to work.
15+
- **ASYNC109**: Async function definition with a ``timeout`` parameter - use ``[trio/anyio].[fail/move_on]_[after/at]`` instead.
16+
- **ASYNC110**: ``while <condition>: await [trio/anyio].sleep()`` should be replaced by a ``[trio/anyio].Event``.
17+
- **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.
18+
- **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.
19+
- **ASYNC113**: Using ``nursery.start_soon`` in ``__aenter__`` doesn't wait for the task to begin. Consider replacing with ``nursery.start``.
20+
- **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.
21+
- **ASYNC115**: Replace ``[trio/anyio].sleep(0)`` with the more suggestive ``[trio/anyio].lowlevel.checkpoint()``.
22+
- **ASYNC116**: ``[trio/anyio].sleep()`` with >24 hour interval should usually be ``[trio/anyio].sleep_forever()``.
23+
- **ASYNC118**: Don't assign the value of ``anyio.get_cancelled_exc_class()`` to a variable, since that breaks linter checks and multi-backend programs.
24+
25+
Blocking sync calls in async functions
26+
======================================
27+
28+
Note: 22X, 23X and 24X has not had asyncio-specific suggestions written.
29+
30+
31+
- **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.
32+
- **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.
33+
- **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.
34+
- **ASYNC212**: Blocking sync HTTP call on httpx object, use httpx.AsyncClient.
35+
- **ASYNC220**: Sync process call in async function, use ``await nursery.start([trio/anyio].run_process, ...)``. ``asyncio`` users can use `asyncio.create_subprocess_[exec/shell] <https://docs.python.org/3/library/asyncio-subprocess.html>`_.
36+
- **ASYNC221**: Sync process call in async function, use ``await [trio/anyio].run_process(...)``. ``asyncio`` users can use `asyncio.create_subprocess_[exec/shell] <https://docs.python.org/3/library/asyncio-subprocess.html>`_.
37+
- **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 <https://docs.python.org/3/library/asyncio-subprocess.html>`_.
38+
- **ASYNC230**: Sync IO call in async function, use ``[trio/anyio].open_file(...)``. ``asyncio`` users need to use a library such as `aiofiles <https://pypi.org/project/aiofiles/>`_, or switch to `anyio <https://github.com/agronholm/anyio>`_.
39+
- **ASYNC231**: Sync IO call in async function, use ``[trio/anyio].wrap_file(...)``. ``asyncio`` users need to use a library such as `aiofiles <https://pypi.org/project/aiofiles/>`_, or switch to `anyio <https://github.com/agronholm/anyio>`_.
40+
- **ASYNC232**: Blocking sync call on file object, wrap the file object in ``[trio/anyio].wrap_file()`` to get an async file object.
41+
- **ASYNC240**: Avoid using ``os.path`` in async functions, prefer using ``[trio/anyio].Path`` objects. ``asyncio`` users should consider `aiopath <https://pypi.org/project/aiopath>`_ or `anyio <https://github.com/agronholm/anyio>`_.
42+
- **ASYNC250**: Builtin ``input()`` should not be called from async function. Wrap in ``[trio/anyio].to_thread.run_sync()`` or ``asyncio.loop.run_in_executor()``.
43+
- **ASYNC251**: ``time.sleep(...)`` should not be called from async function. Use ``[trio/anyio/asyncio].sleep(...)``.
44+
45+
Optional rules disabled by default
46+
==================================
47+
48+
- **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.
49+
- **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.
50+
- **ASYNC911**: Exit, ``yield`` or ``return`` from async iterable with no guaranteed checkpoint since possible function entry (yield or function definition)
51+
Checkpoints are ``await``, ``async for``, and ``async with`` (on one of enter/exit).
52+
53+
Removed rules
54+
================
55+
56+
- **TRIOxxx**: All error codes are now renamed ASYNCxxx
57+
- **TRIO107**: Renamed to TRIO910
58+
- **TRIO108**: Renamed to TRIO911
59+
- **TRIO117**: "Don't raise or catch ``trio.[NonBase]MultiError``, prefer ``[exceptiongroup.]BaseExceptionGroup``." ``MultiError`` was removed in trio==0.24.0.

0 commit comments

Comments
 (0)