flake8-async 24.3.2__tar.gz → 24.3.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flake8-async-24.3.2 → flake8-async-24.3.4}/CHANGELOG.md +6 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/PKG-INFO +10 -3
- {flake8-async-24.3.2 → flake8-async-24.3.4}/README.md +3 -2
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/__init__.py +1 -1
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/__init__.py +1 -1
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor2xx.py +15 -3
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitors.py +13 -1
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/PKG-INFO +10 -3
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/SOURCES.txt +2 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async110.py +5 -0
- flake8-async-24.3.4/tests/eval_files/async251.py +13 -0
- flake8-async-24.3.4/tests/eval_files/async251_multi_library.py +9 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_flake8_async.py +11 -7
- {flake8-async-24.3.2 → flake8-async-24.3.4}/CONTRIBUTING.md +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/LICENSE +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/MANIFEST.in +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/__main__.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/base.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/runner.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/flake8asyncvisitor.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/helpers.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor100.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor101.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor102.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor103_104.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor105.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor111.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor118.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor91x.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async/visitors/visitor_utility.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/dependency_links.txt +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/entry_points.txt +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/not-zip-safe +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/requires.txt +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/flake8_async.egg-info/top_level.txt +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/pyproject.toml +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/setup.cfg +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/setup.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/__init__.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/async100.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/async100_simple_autofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/async910.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/async911.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/async91x_autofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/noqa.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/autofix_files/noqa_testing.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/conftest.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/anyio_trio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async100.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async100_asyncio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async100_noautofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async100_simple_autofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async101.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async102.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async102_anyio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async102_asyncio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async102_trio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async103.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async103_all_imported.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async103_both_imported.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async103_no_104.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async103_trio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async104.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async104_anyio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async104_trio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async105.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async105_anyio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async106.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async109.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async111.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async112.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async113.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async113_anyio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async113_trio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async114.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async115.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async116.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async118.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async200.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async210.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async211.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async212.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async22x.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async22x_asyncio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async232.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async232_asyncio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async23x.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async23x_asyncio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async240.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async250.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async250_multi_library.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async900.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async910.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async911.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async91x_autofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/async91x_noautofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/no_library.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/noqa.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/noqa_no_autofix.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/noqa_testing.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/eval_files/trio_anyio.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_all_visitors_imported.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_changelog_and_version.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_config_and_args.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_decorator.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_exception_on_invalid_code.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_formatting.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/test_messages_documented.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tests/trio_options.py +0 -0
- {flake8-async-24.3.2 → flake8-async-24.3.4}/tox.ini +0 -0
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
*[CalVer, YY.month.patch](https://calver.org/)*
|
|
3
3
|
|
|
4
|
+
## 24.3.4
|
|
5
|
+
- ASYNC110 (don't loop sleep) now also warns if looping `[trio/anyio].lowlevel.checkpoint()`
|
|
6
|
+
|
|
7
|
+
## 24.3.3
|
|
8
|
+
- Add ASYNC251: `time.sleep()` in async method.
|
|
9
|
+
|
|
4
10
|
## 24.3.2
|
|
5
11
|
- Add ASYNC250: blocking sync call `input()` in async method.
|
|
6
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flake8-async
|
|
3
|
-
Version: 24.3.
|
|
3
|
+
Version: 24.3.4
|
|
4
4
|
Summary: A highly opinionated flake8 plugin for Trio-related problems.
|
|
5
5
|
Home-page: https://github.com/python-trio/flake8-async
|
|
6
6
|
Author: Zac Hatfield-Dodds, John Litborn, and Contributors
|
|
@@ -80,7 +80,8 @@ Note: 22X, 23X and 24X has not had asyncio-specific suggestions written.
|
|
|
80
80
|
- **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).
|
|
81
81
|
- **ASYNC232**: Blocking sync call on file object, wrap the file object in `[trio/anyio].wrap_file()` to get an async file object.
|
|
82
82
|
- **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).
|
|
83
|
-
- **ASYNC250**: Builtin `input()` should not be called from async function.
|
|
83
|
+
- **ASYNC250**: Builtin `input()` should not be called from async function. Wrap in `[trio/anyio].to_thread.run_sync()` or `asyncio.loop.run_in_executor()`.
|
|
84
|
+
- **ASYNC251**: `time.sleep(...)` should not be called from async function. Use `[trio/anyio/asyncio].sleep(...)`.
|
|
84
85
|
|
|
85
86
|
### Warnings disabled by default
|
|
86
87
|
- **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.
|
|
@@ -108,7 +109,7 @@ adding the following to your `.pre-commit-config.yaml`:
|
|
|
108
109
|
minimum_pre_commit_version: '2.9.0'
|
|
109
110
|
repos:
|
|
110
111
|
- repo: https://github.com/python-trio/flake8-async
|
|
111
|
-
rev: 24.3.
|
|
112
|
+
rev: 24.3.4
|
|
112
113
|
hooks:
|
|
113
114
|
- id: flake8-async
|
|
114
115
|
# args: [--enable=ASYNC, --disable=ASYNC9, --autofix=ASYNC]
|
|
@@ -220,6 +221,12 @@ async def my_function():
|
|
|
220
221
|
# Changelog
|
|
221
222
|
*[CalVer, YY.month.patch](https://calver.org/)*
|
|
222
223
|
|
|
224
|
+
## 24.3.4
|
|
225
|
+
- ASYNC110 (don't loop sleep) now also warns if looping `[trio/anyio].lowlevel.checkpoint()`
|
|
226
|
+
|
|
227
|
+
## 24.3.3
|
|
228
|
+
- Add ASYNC251: `time.sleep()` in async method.
|
|
229
|
+
|
|
223
230
|
## 24.3.2
|
|
224
231
|
- Add ASYNC250: blocking sync call `input()` in async method.
|
|
225
232
|
|
|
@@ -55,7 +55,8 @@ Note: 22X, 23X and 24X has not had asyncio-specific suggestions written.
|
|
|
55
55
|
- **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).
|
|
56
56
|
- **ASYNC232**: Blocking sync call on file object, wrap the file object in `[trio/anyio].wrap_file()` to get an async file object.
|
|
57
57
|
- **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).
|
|
58
|
-
- **ASYNC250**: Builtin `input()` should not be called from async function.
|
|
58
|
+
- **ASYNC250**: Builtin `input()` should not be called from async function. Wrap in `[trio/anyio].to_thread.run_sync()` or `asyncio.loop.run_in_executor()`.
|
|
59
|
+
- **ASYNC251**: `time.sleep(...)` should not be called from async function. Use `[trio/anyio/asyncio].sleep(...)`.
|
|
59
60
|
|
|
60
61
|
### Warnings disabled by default
|
|
61
62
|
- **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.
|
|
@@ -83,7 +84,7 @@ adding the following to your `.pre-commit-config.yaml`:
|
|
|
83
84
|
minimum_pre_commit_version: '2.9.0'
|
|
84
85
|
repos:
|
|
85
86
|
- repo: https://github.com/python-trio/flake8-async
|
|
86
|
-
rev: 24.3.
|
|
87
|
+
rev: 24.3.4
|
|
87
88
|
hooks:
|
|
88
89
|
- id: flake8-async
|
|
89
90
|
# args: [--enable=ASYNC, --disable=ASYNC9, --autofix=ASYNC]
|
|
@@ -25,7 +25,7 @@ default_disabled_error_codes: list[str] = []
|
|
|
25
25
|
utility_visitors: set[type[Flake8AsyncVisitor]] = set()
|
|
26
26
|
utility_visitors_cst: set[type[Flake8AsyncVisitor_cst]] = set()
|
|
27
27
|
|
|
28
|
-
# Import all visitors so their decorators run, filling the above containers
|
|
28
|
+
# Import all files with visitors so their decorators run, filling the above containers
|
|
29
29
|
# This has to be done at the end to avoid circular imports
|
|
30
30
|
from . import (
|
|
31
31
|
visitor2xx,
|
|
@@ -398,13 +398,25 @@ wrappers: Mapping[str, str] = {
|
|
|
398
398
|
class Visitor25X(Visitor200):
|
|
399
399
|
error_codes: Mapping[str, str] = {
|
|
400
400
|
"ASYNC250": ("Blocking sync call `input()` in async function. Wrap in `{}`."),
|
|
401
|
+
"ASYNC251": (
|
|
402
|
+
"Blocking sync call `time.sleep(...)` in async function."
|
|
403
|
+
" Use `await {}.sleep(...)`."
|
|
404
|
+
),
|
|
401
405
|
}
|
|
402
406
|
|
|
403
407
|
def visit_Call(self, node: ast.Call):
|
|
404
408
|
if not self.async_function:
|
|
405
409
|
return
|
|
406
|
-
|
|
410
|
+
func_name = ast.unparse(node.func)
|
|
411
|
+
if func_name == "input":
|
|
412
|
+
error_code = "ASYNC250"
|
|
407
413
|
if len(self.library) == 1:
|
|
408
|
-
|
|
414
|
+
msg_param = wrappers[self.library_str]
|
|
409
415
|
else:
|
|
410
|
-
|
|
416
|
+
msg_param = "/".join(wrappers[lib] for lib in self.library)
|
|
417
|
+
elif func_name == "time.sleep":
|
|
418
|
+
error_code = "ASYNC251"
|
|
419
|
+
msg_param = self.library_str
|
|
420
|
+
else:
|
|
421
|
+
return
|
|
422
|
+
self.error(node, msg_param, error_code=error_code)
|
|
@@ -65,7 +65,19 @@ class Visitor110(Flake8AsyncVisitor):
|
|
|
65
65
|
len(node.body) == 1
|
|
66
66
|
and isinstance(node.body[0], ast.Expr)
|
|
67
67
|
and isinstance(node.body[0].value, ast.Await)
|
|
68
|
-
and
|
|
68
|
+
and (
|
|
69
|
+
get_matching_call(node.body[0].value.value, "sleep", "sleep_until")
|
|
70
|
+
or (
|
|
71
|
+
# get_matching_call doesn't (currently) support checking for trio.x.y
|
|
72
|
+
isinstance(call := node.body[0].value.value, ast.Call)
|
|
73
|
+
and isinstance(call.func, ast.Attribute)
|
|
74
|
+
and call.func.attr == "checkpoint"
|
|
75
|
+
and isinstance(call.func.value, ast.Attribute)
|
|
76
|
+
and call.func.value.attr == "lowlevel"
|
|
77
|
+
and isinstance(call.func.value.value, ast.Name)
|
|
78
|
+
and call.func.value.value.id in ("trio", "anyio")
|
|
79
|
+
)
|
|
80
|
+
)
|
|
69
81
|
):
|
|
70
82
|
self.error(node, self.library_str)
|
|
71
83
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: flake8-async
|
|
3
|
-
Version: 24.3.
|
|
3
|
+
Version: 24.3.4
|
|
4
4
|
Summary: A highly opinionated flake8 plugin for Trio-related problems.
|
|
5
5
|
Home-page: https://github.com/python-trio/flake8-async
|
|
6
6
|
Author: Zac Hatfield-Dodds, John Litborn, and Contributors
|
|
@@ -80,7 +80,8 @@ Note: 22X, 23X and 24X has not had asyncio-specific suggestions written.
|
|
|
80
80
|
- **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).
|
|
81
81
|
- **ASYNC232**: Blocking sync call on file object, wrap the file object in `[trio/anyio].wrap_file()` to get an async file object.
|
|
82
82
|
- **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).
|
|
83
|
-
- **ASYNC250**: Builtin `input()` should not be called from async function.
|
|
83
|
+
- **ASYNC250**: Builtin `input()` should not be called from async function. Wrap in `[trio/anyio].to_thread.run_sync()` or `asyncio.loop.run_in_executor()`.
|
|
84
|
+
- **ASYNC251**: `time.sleep(...)` should not be called from async function. Use `[trio/anyio/asyncio].sleep(...)`.
|
|
84
85
|
|
|
85
86
|
### Warnings disabled by default
|
|
86
87
|
- **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.
|
|
@@ -108,7 +109,7 @@ adding the following to your `.pre-commit-config.yaml`:
|
|
|
108
109
|
minimum_pre_commit_version: '2.9.0'
|
|
109
110
|
repos:
|
|
110
111
|
- repo: https://github.com/python-trio/flake8-async
|
|
111
|
-
rev: 24.3.
|
|
112
|
+
rev: 24.3.4
|
|
112
113
|
hooks:
|
|
113
114
|
- id: flake8-async
|
|
114
115
|
# args: [--enable=ASYNC, --disable=ASYNC9, --autofix=ASYNC]
|
|
@@ -220,6 +221,12 @@ async def my_function():
|
|
|
220
221
|
# Changelog
|
|
221
222
|
*[CalVer, YY.month.patch](https://calver.org/)*
|
|
222
223
|
|
|
224
|
+
## 24.3.4
|
|
225
|
+
- ASYNC110 (don't loop sleep) now also warns if looping `[trio/anyio].lowlevel.checkpoint()`
|
|
226
|
+
|
|
227
|
+
## 24.3.3
|
|
228
|
+
- Add ASYNC251: `time.sleep()` in async method.
|
|
229
|
+
|
|
223
230
|
## 24.3.2
|
|
224
231
|
- Add ASYNC250: blocking sync call `input()` in async method.
|
|
225
232
|
|
|
@@ -94,6 +94,8 @@ tests/eval_files/async23x_asyncio.py
|
|
|
94
94
|
tests/eval_files/async240.py
|
|
95
95
|
tests/eval_files/async250.py
|
|
96
96
|
tests/eval_files/async250_multi_library.py
|
|
97
|
+
tests/eval_files/async251.py
|
|
98
|
+
tests/eval_files/async251_multi_library.py
|
|
97
99
|
tests/eval_files/async900.py
|
|
98
100
|
tests/eval_files/async910.py
|
|
99
101
|
tests/eval_files/async911.py
|
|
@@ -69,3 +69,8 @@ async def foo():
|
|
|
69
69
|
|
|
70
70
|
while await trio.sleep():
|
|
71
71
|
...
|
|
72
|
+
|
|
73
|
+
# also error when looping .lowlevel.checkpoint, which is equivalent to .sleep(0)
|
|
74
|
+
# see https://github.com/python-trio/flake8-async/issues/201
|
|
75
|
+
while ...: # ASYNC110: 4, "trio"
|
|
76
|
+
await trio.lowlevel.checkpoint()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NOAUTOFIX
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from time import sleep
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
async def foo():
|
|
8
|
+
time.sleep(5) # ASYNC251: 4, "trio"
|
|
9
|
+
time.sleep(5) if 5 else time.sleep(5) # ASYNC251: 4, "trio" # ASYNC251: 28, "trio"
|
|
10
|
+
|
|
11
|
+
# Not handled due to difficulty tracking imports and not wanting to trigger
|
|
12
|
+
# false positives. But could definitely be handled by ruff et al.
|
|
13
|
+
sleep(5)
|
|
@@ -458,20 +458,24 @@ class SyncTransformer(ast.NodeTransformer):
|
|
|
458
458
|
def visit_Await(self, node: ast.Await):
|
|
459
459
|
return self.generic_visit(node.value)
|
|
460
460
|
|
|
461
|
-
def replace_async(
|
|
461
|
+
def replace_async(
|
|
462
|
+
self, node: ast.AST, target: type[ast.AST], *args: object
|
|
463
|
+
) -> ast.AST:
|
|
462
464
|
node = self.generic_visit(node)
|
|
463
|
-
|
|
465
|
+
# py313 gives DeprecationWarning if missing posargs, so we pass them even if we
|
|
466
|
+
# overwrite __dict__ directly afterwards
|
|
467
|
+
newnode = target(*args)
|
|
464
468
|
newnode.__dict__ = node.__dict__
|
|
465
469
|
return newnode
|
|
466
470
|
|
|
467
|
-
def visit_AsyncFunctionDef(self, node: ast.
|
|
468
|
-
return self.replace_async(node, ast.FunctionDef)
|
|
471
|
+
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef):
|
|
472
|
+
return self.replace_async(node, ast.FunctionDef, node.name, node.args)
|
|
469
473
|
|
|
470
|
-
def visit_AsyncWith(self, node: ast.
|
|
474
|
+
def visit_AsyncWith(self, node: ast.AsyncWith):
|
|
471
475
|
return self.replace_async(node, ast.With)
|
|
472
476
|
|
|
473
|
-
def visit_AsyncFor(self, node: ast.
|
|
474
|
-
return self.replace_async(node, ast.For)
|
|
477
|
+
def visit_AsyncFor(self, node: ast.AsyncFor):
|
|
478
|
+
return self.replace_async(node, ast.For, node.target, node.iter)
|
|
475
479
|
|
|
476
480
|
|
|
477
481
|
@pytest.mark.parametrize(("test", "path"), test_files)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|