mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +00:00
[ty] Add hint if async context manager is used in non-async with statement (#18299)
# Summary Adds a subdiagnostic hint in the following scenario where a synchronous `with` is used with an async context manager: ```py class Manager: async def __aenter__(self): ... async def __aexit__(self, *args): ... # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`" # note: Objects of type `Manager` *can* be used as async context managers # note: Consider using `async with` here with Manager(): ... ``` closes https://github.com/astral-sh/ty/issues/508 ## Test Plan New MD snapshot tests --------- Co-authored-by: David Peter <mail@david-peter.de>
This commit is contained in:
parent
62ef96f51e
commit
1d20cf9570
3 changed files with 147 additions and 1 deletions
|
@ -0,0 +1,85 @@
|
|||
---
|
||||
source: crates/ty_test/src/lib.rs
|
||||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: sync.md - With statements - Accidental use of non-async `with`
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/with/sync.md
|
||||
---
|
||||
|
||||
# Python source files
|
||||
|
||||
## mdtest_snippet.py
|
||||
|
||||
```
|
||||
1 | class Manager:
|
||||
2 | async def __aenter__(self): ...
|
||||
3 | async def __aexit__(self, *args): ...
|
||||
4 |
|
||||
5 | # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`"
|
||||
6 | with Manager():
|
||||
7 | ...
|
||||
8 | class Manager:
|
||||
9 | async def __aenter__(self): ...
|
||||
10 | async def __aexit__(self, typ: str, exc, traceback): ...
|
||||
11 |
|
||||
12 | # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`"
|
||||
13 | with Manager():
|
||||
14 | ...
|
||||
15 | class Manager:
|
||||
16 | async def __aenter__(self, wrong_extra_arg): ...
|
||||
17 | async def __aexit__(self, typ, exc, traceback, wrong_extra_arg): ...
|
||||
18 |
|
||||
19 | # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`"
|
||||
20 | with Manager():
|
||||
21 | ...
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[invalid-context-manager]: Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`
|
||||
--> src/mdtest_snippet.py:6:6
|
||||
|
|
||||
5 | # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and...
|
||||
6 | with Manager():
|
||||
| ^^^^^^^^^
|
||||
7 | ...
|
||||
8 | class Manager:
|
||||
|
|
||||
info: Objects of type `Manager` can be used as async context managers
|
||||
info: Consider using `async with` here
|
||||
info: rule `invalid-context-manager` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-context-manager]: Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`
|
||||
--> src/mdtest_snippet.py:13:6
|
||||
|
|
||||
12 | # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` an...
|
||||
13 | with Manager():
|
||||
| ^^^^^^^^^
|
||||
14 | ...
|
||||
15 | class Manager:
|
||||
|
|
||||
info: Objects of type `Manager` can be used as async context managers
|
||||
info: Consider using `async with` here
|
||||
info: rule `invalid-context-manager` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
error[invalid-context-manager]: Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`
|
||||
--> src/mdtest_snippet.py:20:6
|
||||
|
|
||||
19 | # error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` an...
|
||||
20 | with Manager():
|
||||
| ^^^^^^^^^
|
||||
21 | ...
|
||||
|
|
||||
info: Objects of type `Manager` can be used as async context managers
|
||||
info: Consider using `async with` here
|
||||
info: rule `invalid-context-manager` is enabled by default
|
||||
|
||||
```
|
|
@ -149,3 +149,45 @@ context_expr = Manager()
|
|||
with context_expr as f:
|
||||
reveal_type(f) # revealed: str
|
||||
```
|
||||
|
||||
## Accidental use of non-async `with`
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
If a synchronous `with` statement is used on a type with `__aenter__` and `__aexit__`, we show a
|
||||
diagnostic hint that the user might have intended to use `asnyc with` instead.
|
||||
|
||||
```py
|
||||
class Manager:
|
||||
async def __aenter__(self): ...
|
||||
async def __aexit__(self, *args): ...
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`"
|
||||
with Manager():
|
||||
...
|
||||
```
|
||||
|
||||
The sub-diagnostic is also provided if the signatures of `__aenter__` and `__aexit__` do not match
|
||||
the expected signatures for a context manager:
|
||||
|
||||
```py
|
||||
class Manager:
|
||||
async def __aenter__(self): ...
|
||||
async def __aexit__(self, typ: str, exc, traceback): ...
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`"
|
||||
with Manager():
|
||||
...
|
||||
```
|
||||
|
||||
Similarly, we also show the hint if the functions have the wrong number of arguments:
|
||||
|
||||
```py
|
||||
class Manager:
|
||||
async def __aenter__(self, wrong_extra_arg): ...
|
||||
async def __aexit__(self, typ, exc, traceback, wrong_extra_arg): ...
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because it does not implement `__enter__` and `__exit__`"
|
||||
with Manager():
|
||||
...
|
||||
```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue