diff --git a/README.md b/README.md index 50508ae..d0e1691 100644 --- a/README.md +++ b/README.md @@ -18,3 +18,6 @@ Pairs well with flake8-bugbear. Some checks are incorporated into [ruff](https://github.com/astral-sh/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. + +## Rules +https://flake8-async.readthedocs.io/en/latest/rules.html diff --git a/docs/glossary.rst b/docs/glossary.rst new file mode 100644 index 0000000..7dde9b7 --- /dev/null +++ b/docs/glossary.rst @@ -0,0 +1,131 @@ +******** +Glossary +******** + +.. _cancel_scope: + +cancel scope +------------ +A cancel scope is a context manager which can request the library cancels +whatever task is executing in the body of the ``with`` (or ``async with``) +block. A cancel scope is the key component of a :ref:`timeout context `, +and used in :ref:`TaskGroups / Nurseries ` to cancel any remaining child tasks if one raises an +exception. + +* Trio has an explicit :class:`trio.CancelScope` type, and `general documentation + `__ + about cancellation and timeouts. + +* AnyIO similarly has :class:`anyio.CancelScope` and `documentation + `__ of cancellation handling. + +* asyncio does not have an explicit cancel-scope type, but incorporates similar semantics + in :func:`asyncio.timeout` and :class:`asyncio.TaskGroup` and has `some documentation + `__. + + +.. _timeout_context: + +timeout context +--------------- +A context manager that enforces a timeout on a block of code, by cancelling it +after a specified duration or at a preset time. The timeout can also be +rescheduled after creation. They are internally implemented with a :ref:`cancel scope `, +which in anyio & trio can be directly initialized with a deadline. + +* Trio has :func:`trio.move_on_after`, :func:`trio.move_on_at`, + :func:`trio.fail_after`, :func:`trio.fail_at`, and :class:`trio.CancelScope` + (`docs `__) + +* AnyIO has :func:`anyio.move_on_after`, :func:`anyio.fail_after`, and :class:`anyio.CancelScope` + (`docs `__) + +* asyncio has :func:`asyncio.timeout` and :func:`asyncio.timeout_at` + (`docs `__) + + +.. _taskgroup_nursery: + +TaskGroup / Nursery +------------------- + +A collection of child Tasks that can run concurrently. Internally contains a +:ref:`cancel scope ` for canceling any remaining child tasks if +one raises an exception. + +* Trio has :class:`trio.Nursery`, created with :func:`trio.open_nursery` + (`docs `__) + +* AnyIO has :class:`anyio.abc.TaskGroup`, created with :func:`anyio.create_task_group` + (`docs `__) + +* asyncio has :class:`asyncio.TaskGroup` since python 3.11 + (`docs `__) + + +.. _cancellation: +.. _cancelled: + +Cancelled / CancelledError +-------------------------- + +Handling cancellation is very sensitive, and you generally never want to catch a +cancellation exception without letting it propagate to the library. + +General documentation on cancellation in the different async libraries: + +* `Trio `__ +* `AnyIO `__ +* `asyncio `__ + +Exception classes: + +* :class:`trio.Cancelled` +* :func:`anyio.get_cancelled_exc_class` +* :class:`asyncio.CancelledError` + +.. _checkpoint: + +Checkpoint +---------- +Checkpoints are points where the async backend checks for cancellation and +can switch which task is running, in an ``await``, ``async for``, or ``async with`` +expression. Regular checkpoints can be important for both performance and correctness. + +Trio has extensive and detailed documentation on the concept of +:external+trio:ref:`checkpoints `, and guarantees that all async +functions defined by Trio will either checkpoint or raise an exception when +``await``-ed. ``async for`` on Trio iterables will checkpoint before each +iteration, and when exhausting the iterator, and ``async with`` will checkpoint +on at least one of enter/exit. + +asyncio does not place any guarantees on if or when asyncio functions will +checkpoint. This means that enabling and adhering to :ref:`ASYNC91x ` +will still not guarantee checkpoints. + +For anyio it will depend on the current backend. + +When using Trio (or an AnyIO library that people might use on Trio), it can be +very helpful to ensure that your own code adheres to the same guarantees as +Trio. For this we supply the :ref:`ASYNC91x ` rules. To make it +possible to reason the rules will also assume that all other async functions +also adhere to those rules. This means you must be careful if you're using +3rd-party async libraries. + +To insert a checkpoint with no other side effects, you can use +:func:`trio.lowlevel.checkpoint`/:func:`anyio.lowlevel.checkpoint`/:func:`asyncio.sleep(0) +` + +.. _channel_stream_queue: + +Channel / Stream / Queue +------------------------ +Interfaces used for communicating between tasks, processes, the network, etc. + +.. anyio streams is a :doc: and not a :label:, so we can't link with intersphinx :( + +.. _anyio_streams: https://anyio.readthedocs.io/en/stable/streams.html#streams + +* Trio has :ref:`channels ` for python objects and :ref:`streams ` for bytes. +* AnyIO has ``byte`` and ``object`` `streams `_ +* asyncio has :ref:`queues ` for python objects and :ref:`streams ` for bytes. diff --git a/docs/index.rst b/docs/index.rst index af37fab..1cf69e4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,7 @@ flake8-async ############ -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, @@ -17,10 +17,10 @@ a misunderstanding. 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. +Pairs well with `flake8-bugbear `__. -Some rules 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. @@ -33,6 +33,7 @@ Contents: usage rules + glossary changelog contributing @@ -46,5 +47,6 @@ Indices and tables * :ref:`search` * :doc:`usage` * :doc:`rules` +* :doc:`glossary` * :doc:`changelog` * :doc:`contributing` diff --git a/docs/rules.rst b/docs/rules.rst index 0964146..9e0e68b 100644 --- a/docs/rules.rst +++ b/docs/rules.rst @@ -1,86 +1,159 @@ -**************** -List of rules -**************** +***** +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 :class:`trio.Nursery`/:class:`anyio.abc.TaskGroup`/:py:class:`asyncio.TaskGroup`, or in a timeout/cancel scope is only safe when implementing a context manager - otherwise, it breaks exception handling. See `this thread `_ for discussion of a future PEP. This has substantial overlap with :ref:`ASYNC119 `, which will warn on almost all instances of ASYNC101, but ASYNC101 is about a conceptually different problem that will not get resolved by `PEP 533 `_. -- **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`` :class:`BaseException`/:class:`trio.Cancelled`/:func:`anyio.get_cancelled_exc_class`/:class:`asyncio.CancelledError`, or a bare ``except:`` with a code path that doesn't re-raise. If you don't want to re-raise :class:`BaseException`, add a separate handler for :class:`trio.Cancelled`/:func:`anyio.get_cancelled_exc_class`/:class:`asyncio.CancelledError` before. -- **ASYNC104**: :class:`trio.Cancelled`/:func:`anyio.get_cancelled_exc_class`/:class:`asyncio.CancelledError`/:class:`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. +_`ASYNC100` : cancel-scope-no-checkpoint + A :ref:`timeout_context` does not contain any :ref:`checkpoints `. + This makes it pointless, as the timeout can only be triggered by a checkpoint. + This check also treats ``yield`` as a checkpoint, since checkpoints can happen in the caller we yield to. + See :ref:`ASYNC912 ` which will in addition guarantee checkpoints on every code path. + +ASYNC101 : yield-in-cancel-scope + ``yield`` inside a :ref:`taskgroup_nursery` or :ref:`timeout_context` is only safe when implementing a context manager - otherwise, it breaks exception handling. + See `this thread `_ for discussion of a future PEP. + This has substantial overlap with :ref:`ASYNC119 `, which will warn on almost all instances of ASYNC101, but ASYNC101 is about a conceptually different problem that will not get resolved by `PEP 533 `_. + +ASYNC102 : await-in-finally-or-cancelled + ``await`` inside ``finally`` or :ref:`cancelled-catching ` ``except:`` must have shielded :ref:`cancel scope ` with timeout. + This is currently not able to detect asyncio shields. + +ASYNC103 : no-reraise-cancelled + :ref:`cancelled`-catching exception that does not reraise the exception. + If you don't want to re-raise :class:`BaseException`, add a separate handler for :ref:`Cancelled` before. + +ASYNC104 : cancelled-not-raised + :ref:`Cancelled`-catching exception does not raise the exception. + Triggered on ``return`` or raising a different exception. + +ASYNC105 : missing-await + async trio function called without using ``await``. + This is only supported with trio functions, but you can get similar functionality with a type-checker. + +ASYNC106 : bad-async-library-import + trio/anyio/asyncio must be imported with ``import xxx`` for the linter to work. - .. _async113: +ASYNC109 : async-function-with-timeout + Async function definition with a ``timeout`` parameter. + In structured concurrency the caller should instead use :ref:`timeout context managers `. -- **ASYNC113**: Using :meth:`trio.Nursery.start_soon` in ``__aenter__`` doesn't wait for the task to begin. Consider replacing with ``nursery.start``. +ASYNC110 : async-busy-wait + ``while ...: await [trio/anyio].sleep()`` should be replaced by a :class:`trio.Event`/:class:`anyio.Event`. - .. _async114: +ASYNC111 : variable-from-cm-in-start-soon + Variable, from context manager opened inside :ref:`taskgroup_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. -- **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 :func:`anyio.get_cancelled_exc_class` to a variable, since that breaks linter checks and multi-backend programs. +ASYNC112 : useless-nursery + :ref:`taskgroup_nursery` body with only a call to ``.start[_soon]`` and not passing itself as a parameter can be replaced with a regular function call. - .. _async119: +_`ASYNC113` : start-soon-in-aenter + Using :meth:`~trio.Nursery.start_soon`/:meth:`~anyio.abc.TaskGroup.start_soon` in ``__aenter__`` doesn't wait for the task to begin. + Consider replacing with :meth:`~trio.Nursery.start`/:meth:`~anyio.abc.TaskGroup.start`. + +_`ASYNC114` : startable-not-in-config + Startable function (i.e. has a ``task_status`` keyword parameter) not in :ref:`--startable-in-context-manager <--startable-in-context-manager>` parameter list, please add it so ASYNC113 can catch errors when using it. + +ASYNC115 : async-zero-sleep + Replace :func:`trio.sleep(0) `/:func:`anyio.sleep(0) ` with the more suggestive :func:`trio.lowlevel.checkpoint`/:func:`anyio.lowlevel.checkpoint`. + +ASYNC116 : long-sleep-not-forever + :func:`trio.sleep`/:func:`anyio.sleep` with >24 hour interval should usually be :func:`trio.sleep_forever`/:func:`anyio.sleep_forever`. + +ASYNC118 : cancelled-class-saved + Don't assign the value of :func:`anyio.get_cancelled_exc_class()` to a variable, since that breaks linter checks and multi-backend programs. + +_`ASYNC119` : yield-in-cm-in-async-gen + ``yield`` in context manager in async generator is unsafe, the cleanup may be delayed until ``await`` is no longer allowed. + We strongly encourage you to read `PEP 533 `_ and use `async with aclosing(...) `_, or better yet avoid async generators entirely (see `ASYNC900`_ ) in favor of context managers which return an iterable :ref:`channel/stream/queue `. -- **ASYNC119**: ``yield`` in context manager in async generator is unsafe, the cleanup may be delayed until ``await`` is no longer allowed. We strongly encourage you to read `PEP 533 `_ and use `async with aclosing(...) `_, or better yet avoid async generators entirely (see :ref:`ASYNC900 ` ) in favor of context managers which return an iterable `channel (trio) `_, `stream (anyio) `_, or `queue (asyncio) `_. - .. TODO: use intersphinx(?) instead of having to specify full URL Blocking sync calls in async functions ====================================== -Note: 22X, 23X and 24X has not had asyncio-specific suggestions written. +.. _httpx.Client: https://www.python-httpx.org/api/#client +.. _httpx.AsyncClient: https://www.python-httpx.org/api/#asyncclient +.. _urllib3: https://github.com/urllib3/urllib3 +.. _aiofiles: https://pypi.org/project/aiofiles/ +.. _anyio: https://github.com/agronholm/anyio -.. _async200: +_`ASYNC200` : blocking-configured-call + User-configured error for blocking sync calls in async functions. + Does nothing by default, see :ref:`async200-blocking-calls` for how to configure it. -- **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(...)``. +ASYNC210 : blocking-http-call + Sync HTTP call in async function, use `httpx.AsyncClient`_. + This and the other :ref:`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` : blocking-http-call-pool + 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. -Optional rules disabled by default -================================== +ASYNC212 : blocking-http-call-httpx + Blocking sync HTTP call on httpx object, use `httpx.AsyncClient`_. + +ASYNC220 : blocking-create-subprocess + Sync call to :class:`subprocess.Popen` (or equivalent) in async function, use :func:`trio.run_process`/:func:`anyio.run_process`/:ref:`asyncio.create_subprocess_[exec/shell] ` in a :ref:`taskgroup_nursery`. + +ASYNC221 : blocking-run-process + Sync call to :func:`subprocess.run` (or equivalent) in async function, use :func:`trio.run_process`/:func:`anyio.run_process`/:ref:`asyncio.create_subprocess_[exec/shell] `. + +ASYNC222 : blocking-process-wait + Sync call to :func:`os.wait` (or equivalent) in async function, wrap in :func:`trio.to_thread.run_sync`/:func:`anyio.to_thread.run_sync`/:meth:`asyncio.loop.run_in_executor`. + +ASYNC230 : blocking-open-call + Sync call to :func:`open` in async function, use :func:`trio.open_file`/:func:`anyio.open_file`. ``asyncio`` users need to use a library such as `aiofiles`_, or switch to `anyio`_. + +ASYNC231 : blocking-fdopen-call + Sync call to :func:`os.fdopen` in async function, use :func:`trio.wrap_file`/:func:`anyio.wrap_file`. ``asyncio`` users need to use a library such as `aiofiles`_, or switch to `anyio`_. -.. _async900: +ASYNC232 : blocking-file-call + Blocking sync call on file object, wrap the file object in :func:`trio.wrap_file`/:func:`anyio.wrap_file` to get an async file object. -- **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. +ASYNC240 : blocking-path-usage + Avoid using :mod:`os.path` in async functions, prefer using :class:`trio.Path`/:class:`anyio.Path` objects. ``asyncio`` users should consider `aiopath `__ or `anyio`_. + +ASYNC250 : blocking-input + Builtin :func:`input` should not be called from async function. + Wrap in :func:`trio.to_thread.run_sync`/:func:`anyio.to_thread.run_sync` or :meth:`asyncio.loop.run_in_executor`. + +ASYNC251 : blocking-sleep + :func:`time.sleep` should not be called from async function. + Use :func:`trio.sleep`/:func:`anyio.sleep`/:func:`asyncio.sleep`. + + +Optional rules disabled by default +================================== - .. _async910: +_`ASYNC900` : unsafe-async-generator + Async generator without :func:`@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 `#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. +_`ASYNC910` : async-function-no-checkpoint + Exit or ``return`` from async function with no guaranteed :ref:`checkpoint` or exception since function definition. + You might want to enable this on a trio/anyio codebase to make it easier to reason about checkpoints, and make the logic of ASYNC911 correct. - .. _async911: +_`ASYNC911` : async-generator-no-checkpoint + Exit, ``yield`` or ``return`` from async iterable with no guaranteed :ref:`checkpoint` since possible function entry (``yield`` or function definition). -- **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). -- **ASYNC912**: A timeout/cancelscope has checkpoints, but they're not guaranteed to run. Similar to ASYNC100, but it does not warn on trivial cases where there is no checkpoint at all. It instead shares logic with ASYNC910 and ASYNC911 for parsing conditionals and branches. +_`ASYNC912` : cancel-scope-no-guaranteed-checkpoint + A timeout/cancelscope has :ref:`checkpoints `, but they're not guaranteed to run. + Similar to `ASYNC100`_, but it does not warn on trivial cases where there is no checkpoint at all. + It instead shares logic with `ASYNC910`_ and `ASYNC911`_ for parsing conditionals and branches. .. _autofix-support: Autofix support =============== The following rules support :ref:`autofixing `. -- ASYNC100 -- ASYNC910 -- ASYNC911 +- :ref:`ASYNC100 ` +- :ref:`ASYNC910 ` +- :ref:`ASYNC911 ` Removed rules ================ diff --git a/docs/usage.rst b/docs/usage.rst index c351c48..a38afd5 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -54,7 +54,7 @@ Afterwards, run install and run as standalone ============================= -If inside a git repository, running without arguments will run it against all ``*.py`` files in the repository tree. +If inside a git repository, running without arguments will run it against all ``*.py`` files in the repository. .. code-block:: sh @@ -103,6 +103,8 @@ Note that when running ``flake8-async`` as a standalone it's not currently possi Selecting rules =============== +.. _valueerror_ignore: + ``ValueError`` when trying to ``ignore`` error codes in config file ------------------------------------------------------------------- @@ -135,7 +137,7 @@ Example ``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. +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. :ref:`It will also bypass errors introduced in flake8>=6 `. This is parsed after :ref:`enable`, so if a rule is both "enabled" and "disabled" it will be disabled. Defaults to "ASYNC9". @@ -167,7 +169,8 @@ Example ``error-on-autofix`` ---------------------- -Whether to also print an error message for autofixed errors. Defaults to ``False`` +Whether to also print an error message for autofixed errors. +Defaults to ``False`` Example ^^^^^^^ @@ -183,7 +186,10 @@ Modifying rule behaviour ``anyio`` ----------- -Change the default library to be anyio instead of trio. This is mostly used for the sake of printing suggestions in error messages, but may affect some logic. If additional libraries are imported other than the default then rules will assume multiple are available simultaneously. It is currently not possible to set multiple default libraries, other than `anyio`+`asyncio`. +Change the default library to be anyio instead of trio. +This is mostly used for the sake of printing suggestions in error messages, but may affect some logic. +If additional libraries are imported other than the default then rules will assume multiple are available simultaneously. +It is currently not possible to set multiple default libraries, other than `anyio`+`asyncio`. Example ^^^^^^^ @@ -207,7 +213,9 @@ Example ``no-checkpoint-warning-decorators`` ------------------------------------ -Comma-separated list of decorators to disable checkpointing checks for, turning off :ref:`ASYNC910 ` and :ref:`ASYNC911 ` warnings for functions decorated with any decorator matching any in the list. Matching is done with `fnmatch `_. Defaults to disabling for ``asynccontextmanager``. +Comma-separated list of decorators to disable checkpointing checks for, turning off :ref:`ASYNC910 ` and :ref:`ASYNC911 ` warnings for functions decorated with any decorator matching against an entry 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. @@ -222,12 +230,14 @@ Example ign*, *.ignore, +.. _--startable-in-context-manager: + ``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()``. +Comma-separated list of methods which should be used with :meth:`trio.Nursery.start`/:meth:`anyio.abc.TaskGroup.start` when opening a context manager, +in addition to the default :func:`trio.run_process`, :func:`trio.serve_tcp`, :func:`trio.serve_ssl_over_tcp`, and :func:`trio.serve_listeners`. +Names must be valid identifiers as per :meth:`str.isidentifier`. Used by :ref:`ASYNC113 `, and :ref:`ASYNC114 ` will warn when encountering methods not in the list. Example @@ -242,9 +252,11 @@ Example .. _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 :ref:`ASYNC200 ` 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. +Comma-separated list of pairs of values separated by ``->`` (optional whitespace stripped), where the first is a pattern for a call that should raise :ref:`ASYNC200 ` 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.