Skip to content

Commit

Permalink
standardize to [a/b] (python-trio#212)
Browse files Browse the repository at this point in the history
Change all instances of [a|b} to [a/b] in documentation, etc.
  • Loading branch information
jakkdl authored Mar 3, 2024
1 parent 5c6879a commit fe751bc
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 23 deletions.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pip install flake8-async
```

## List of warnings
- **ASYNC100**: A `with [trio|anyio].fail_after(...):` or `with [trio|anyio].move_on_after(...):`
- **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.
- **ASYNC101**: `yield` inside a trio/anyio nursery or cancel scope is only safe when implementing a context manager - otherwise, it breaks exception handling.
Expand All @@ -33,13 +33,13 @@ pip install flake8-async
- **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 <condition>: await [trio/anyio].sleep()` should be replaced by a `[trio|anyio].Event`.
- **ASYNC110**: `while <condition>: 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()`.
- **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
Expand All @@ -48,13 +48,13 @@ Note: 22X, 23X and 24X has not had asyncio-specific suggestions written.
- **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, ...)`.
- **ASYNC221**: Sync process call in async function, use `await [trio|anyio].run_process(...)`.
- **ASYNC222**: Sync `os.*` call in async function, wrap in `await [trio|anyio].to_thread.run_sync()`.
- **ASYNC230**: Sync IO call in async function, use `[trio|anyio].open_file(...)`.
- **ASYNC231**: Sync IO call in async function, use `[trio|anyio].wrap_file(...)`.
- **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.
- **ASYNC220**: Sync process call in async function, use `await nursery.start([trio/anyio].run_process, ...)`.
- **ASYNC221**: Sync process call in async function, use `await [trio/anyio].run_process(...)`.
- **ASYNC222**: Sync `os.*` call in async function, wrap in `await [trio/anyio].to_thread.run_sync()`.
- **ASYNC230**: Sync IO call in async function, use `[trio/anyio].open_file(...)`.
- **ASYNC231**: Sync IO call in async function, use `[trio/anyio].wrap_file(...)`.
- **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.

### 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.
Expand Down Expand Up @@ -134,7 +134,7 @@ Comma-separated list of error-codes to enable autofixing for if implemented. Req
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].
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](https://docs.python.org/3/library/fnmatch.html). Defaults to disabling for `asynccontextmanager`.
Expand Down
11 changes: 6 additions & 5 deletions flake8_async/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,9 @@ def add_options(option_manager: OptionManager | ArgumentParser):
required=False,
default=False,
help=(
"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]."
"Change the default library for suggestions to be anyio instead of trio."
" If asyncio/trio is imported it will assume that is also available and"
" print suggestions with [asyncio/anyio/trio]."
),
)
add_argument(
Expand All @@ -306,9 +306,10 @@ def add_options(option_manager: OptionManager | ArgumentParser):
required=False,
default=False,
help=(
"Change the default library to be asyncio instead of trio."
"Change the default library for suggestions to be asyncio instead of"
" trio."
" If anyio/trio is imported it will assume that is also available and"
" print suggestions with [asyncio|anyio/trio]."
" print suggestions with [asyncio/anyio/trio]."
),
)

Expand Down
2 changes: 1 addition & 1 deletion flake8_async/visitors/flake8asyncvisitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def library(self) -> tuple[str, ...]:
def library_str(self) -> str:
if len(self.library) == 1:
return self.library[0]
return "[" + "|".join(self.library) + "]"
return "[" + "/".join(self.library) + "]"

def add_library(self, name: str) -> None:
if name not in self.__state.library:
Expand Down
4 changes: 2 additions & 2 deletions flake8_async/visitors/visitor103_104.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# TODO: ugly
for a, b in (("anyio", "trio"), ("anyio", "asyncio"), ("asyncio", "trio")):
_suggestion_dict[(a, b)] = (
"[" + "|".join((_suggestion_dict[(a,)], _suggestion_dict[(b,)])) + "]"
"[" + "/".join((_suggestion_dict[(a,)], _suggestion_dict[(b,)])) + "]"
)
_suggestion_dict[
(
Expand Down Expand Up @@ -110,7 +110,7 @@ def visit_ExceptHandler(self, node: ast.ExceptHandler):

# Don't save the state of cancelled_caught, that's handled in Try and would
# reset it between each except
# Don't need to reset the values of unraised_[break|continue] since that's handled
# Don't need to reset the values of unraised_[break/continue] since that's handled
# by visit_For, but need to save the state of them to not mess up loops we're
# nested inside
self.save_state(
Expand Down
2 changes: 1 addition & 1 deletion tests/eval_files/anyio_trio.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@


async def foo():
subprocess.Popen() # ASYNC220: 4, 'subprocess.Popen', "[anyio|trio]"
subprocess.Popen() # ASYNC220: 4, 'subprocess.Popen', "[anyio/trio]"
2 changes: 1 addition & 1 deletion tests/eval_files/trio_anyio.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@


async def foo():
subprocess.Popen() # ASYNC220: 4, 'subprocess.Popen', "[trio|anyio]"
subprocess.Popen() # ASYNC220: 4, 'subprocess.Popen', "[trio/anyio]"
2 changes: 1 addition & 1 deletion tests/test_config_and_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def test_anyio_from_config(tmp_path: Path, capsys: pytest.CaptureFixture[str]):

err_msg = Visitor22X.error_codes["ASYNC220"].format(
"subprocess.Popen",
"[anyio|trio]",
"[anyio/trio]",
)
err_file = Path(__file__).parent / "eval_files" / "anyio_trio.py"

Expand Down

0 comments on commit fe751bc

Please sign in to comment.