mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:37 +00:00
[ty] Rename "possibly unbound" diagnostics to "possibly missing" (#20492)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
This commit is contained in:
parent
4ed8c65d29
commit
bf38e69870
41 changed files with 213 additions and 194 deletions
|
@ -914,7 +914,7 @@ def _(flag: bool):
|
|||
reveal_type(C3.attr2) # revealed: Literal["metaclass value", "class value"]
|
||||
```
|
||||
|
||||
If the *metaclass* attribute is only partially defined, we emit a `possibly-unbound-attribute`
|
||||
If the *metaclass* attribute is only partially defined, we emit a `possibly-missing-attribute`
|
||||
diagnostic:
|
||||
|
||||
```py
|
||||
|
@ -924,12 +924,12 @@ def _(flag: bool):
|
|||
attr1: str = "metaclass value"
|
||||
|
||||
class C4(metaclass=Meta4): ...
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(C4.attr1) # revealed: str
|
||||
```
|
||||
|
||||
Finally, if both the metaclass attribute and the class-level attribute are only partially defined,
|
||||
we union them and emit a `possibly-unbound-attribute` diagnostic:
|
||||
we union them and emit a `possibly-missing-attribute` diagnostic:
|
||||
|
||||
```py
|
||||
def _(flag1: bool, flag2: bool):
|
||||
|
@ -941,7 +941,7 @@ def _(flag1: bool, flag2: bool):
|
|||
if flag2:
|
||||
attr1 = "class value"
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(C5.attr1) # revealed: Unknown | Literal["metaclass value", "class value"]
|
||||
```
|
||||
|
||||
|
@ -1180,13 +1180,13 @@ def _(flag1: bool, flag2: bool):
|
|||
|
||||
C = C1 if flag1 else C2 if flag2 else C3
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>` may be missing"
|
||||
reveal_type(C.x) # revealed: Unknown | Literal[1, 3]
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[100]` is not assignable to attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>`"
|
||||
C.x = 100
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `x` on type `C1 | C2 | C3` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `x` on type `C1 | C2 | C3` may be missing"
|
||||
reveal_type(C().x) # revealed: Unknown | Literal[1, 3]
|
||||
|
||||
# error: [invalid-assignment] "Object of type `Literal[100]` is not assignable to attribute `x` on type `C1 | C2 | C3`"
|
||||
|
@ -1212,18 +1212,18 @@ def _(flag: bool, flag1: bool, flag2: bool):
|
|||
|
||||
C = C1 if flag1 else C2 if flag2 else C3
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `x` on type `<class 'C1'> | <class 'C2'> | <class 'C3'>` may be missing"
|
||||
reveal_type(C.x) # revealed: Unknown | Literal[1, 2, 3]
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
C.x = 100
|
||||
|
||||
# Note: we might want to consider ignoring possibly-unbound diagnostics for instance attributes eventually,
|
||||
# Note: we might want to consider ignoring possibly-missing diagnostics for instance attributes eventually,
|
||||
# see the "Possibly unbound/undeclared instance attribute" section below.
|
||||
# error: [possibly-unbound-attribute] "Attribute `x` on type `C1 | C2 | C3` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `x` on type `C1 | C2 | C3` may be missing"
|
||||
reveal_type(C().x) # revealed: Unknown | Literal[1, 2, 3]
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
C().x = 100
|
||||
```
|
||||
|
||||
|
@ -1287,16 +1287,16 @@ def _(flag: bool):
|
|||
if flag:
|
||||
x = 2
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(Bar.x) # revealed: Unknown | Literal[2, 1]
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
Bar.x = 3
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(Bar().x) # revealed: Unknown | Literal[2, 1]
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
Bar().x = 3
|
||||
```
|
||||
|
||||
|
@ -1304,7 +1304,7 @@ def _(flag: bool):
|
|||
|
||||
We currently treat implicit instance attributes to be bound, even if they are only conditionally
|
||||
defined within a method. If the class-level definition or the whole method is only conditionally
|
||||
available, we emit a `possibly-unbound-attribute` diagnostic.
|
||||
available, we emit a `possibly-missing-attribute` diagnostic.
|
||||
|
||||
#### Possibly unbound and undeclared
|
||||
|
||||
|
@ -1484,17 +1484,17 @@ def _(flag: bool):
|
|||
class B1: ...
|
||||
|
||||
def inner1(a_and_b: Intersection[A1, B1]):
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a_and_b.x) # revealed: P
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
a_and_b.x = R()
|
||||
# Same for class objects
|
||||
def inner1_class(a_and_b: Intersection[type[A1], type[B1]]):
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a_and_b.x) # revealed: P
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
a_and_b.x = R()
|
||||
|
||||
class A2:
|
||||
|
@ -1509,7 +1509,7 @@ def _(flag: bool):
|
|||
|
||||
# TODO: this should not be an error, we need better intersection
|
||||
# handling in `validate_attribute_assignment` for this
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
a_and_b.x = R()
|
||||
# Same for class objects
|
||||
def inner2_class(a_and_b: Intersection[type[A2], type[B1]]):
|
||||
|
@ -1524,17 +1524,17 @@ def _(flag: bool):
|
|||
x: Q = Q()
|
||||
|
||||
def inner3(a_and_b: Intersection[A3, B3]):
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a_and_b.x) # revealed: P & Q
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
a_and_b.x = R()
|
||||
# Same for class objects
|
||||
def inner3_class(a_and_b: Intersection[type[A3], type[B3]]):
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a_and_b.x) # revealed: P & Q
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
a_and_b.x = R()
|
||||
|
||||
class A4: ...
|
||||
|
@ -1649,7 +1649,7 @@ If an attribute is defined on the class, it takes precedence over the `__getattr
|
|||
reveal_type(c.class_attr) # revealed: int
|
||||
```
|
||||
|
||||
If the class attribute is possibly unbound, we union the type of the attribute with the fallback
|
||||
If the class attribute is possibly missing, we union the type of the attribute with the fallback
|
||||
type of the `__getattr__` method:
|
||||
|
||||
```py
|
||||
|
|
|
@ -26,7 +26,7 @@ In particular, we should raise errors in the "possibly-undeclared-and-unbound" a
|
|||
| **Diagnostic** | declared | possibly-undeclared | undeclared |
|
||||
| ---------------- | -------- | ------------------------- | ------------------- |
|
||||
| bound | | | |
|
||||
| possibly-unbound | | `possibly-unbound-import` | ? |
|
||||
| possibly-unbound | | `possibly-missing-import` | ? |
|
||||
| unbound | | ? | `unresolved-import` |
|
||||
|
||||
## Declared
|
||||
|
@ -158,7 +158,7 @@ a = None
|
|||
|
||||
If a symbol is possibly undeclared and possibly unbound, we also use the union of the declared and
|
||||
inferred types. This case is interesting because the "possibly declared" definition might not be the
|
||||
same as the "possibly bound" definition (symbol `b`). Note that we raise a `possibly-unbound-import`
|
||||
same as the "possibly bound" definition (symbol `b`). Note that we raise a `possibly-missing-import`
|
||||
error for both `a` and `b`:
|
||||
|
||||
`mod.py`:
|
||||
|
@ -177,8 +177,8 @@ else:
|
|||
```
|
||||
|
||||
```py
|
||||
# error: [possibly-unbound-import]
|
||||
# error: [possibly-unbound-import]
|
||||
# error: [possibly-missing-import] "Member `a` of module `mod` may be missing"
|
||||
# error: [possibly-missing-import] "Member `b` of module `mod` may be missing"
|
||||
from mod import a, b
|
||||
|
||||
reveal_type(a) # revealed: Literal[1] | Any
|
||||
|
@ -332,8 +332,8 @@ if flag():
|
|||
```
|
||||
|
||||
```py
|
||||
# error: [possibly-unbound-import]
|
||||
# error: [possibly-unbound-import]
|
||||
# error: [possibly-missing-import]
|
||||
# error: [possibly-missing-import]
|
||||
from mod import MyInt, C
|
||||
|
||||
reveal_type(MyInt) # revealed: <class 'int'>
|
||||
|
|
|
@ -19,7 +19,7 @@ b = Unit()(3.0) # error: "Object of type `Unit` is not callable"
|
|||
reveal_type(b) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Possibly unbound `__call__` method
|
||||
## Possibly missing `__call__` method
|
||||
|
||||
```py
|
||||
def _(flag: bool):
|
||||
|
@ -29,7 +29,7 @@ def _(flag: bool):
|
|||
return 1
|
||||
|
||||
a = PossiblyNotCallable()
|
||||
result = a() # error: "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
result = a() # error: "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
reveal_type(result) # revealed: int
|
||||
```
|
||||
|
||||
|
@ -105,7 +105,7 @@ reveal_type(c()) # revealed: int
|
|||
|
||||
## Union over callables
|
||||
|
||||
### Possibly unbound `__call__`
|
||||
### Possibly missing `__call__`
|
||||
|
||||
```py
|
||||
def outer(cond1: bool):
|
||||
|
@ -122,6 +122,6 @@ def outer(cond1: bool):
|
|||
else:
|
||||
a = Other()
|
||||
|
||||
# error: [call-non-callable] "Object of type `Test` is not callable (possibly unbound `__call__` method)"
|
||||
# error: [call-non-callable] "Object of type `Test` is not callable (possibly missing `__call__` method)"
|
||||
a()
|
||||
```
|
||||
|
|
|
@ -158,15 +158,15 @@ def _(flag: bool) -> None:
|
|||
def __new__(cls):
|
||||
return object.__new__(cls)
|
||||
|
||||
# error: [possibly-unbound-implicit-call]
|
||||
# error: [possibly-missing-implicit-call]
|
||||
reveal_type(Foo()) # revealed: Foo
|
||||
|
||||
# error: [possibly-unbound-implicit-call]
|
||||
# error: [possibly-missing-implicit-call]
|
||||
# error: [too-many-positional-arguments]
|
||||
reveal_type(Foo(1)) # revealed: Foo
|
||||
```
|
||||
|
||||
#### Possibly unbound `__call__` on `__new__` callable
|
||||
#### Possibly missing `__call__` on `__new__` callable
|
||||
|
||||
```py
|
||||
def _(flag: bool) -> None:
|
||||
|
@ -178,11 +178,11 @@ def _(flag: bool) -> None:
|
|||
class Foo:
|
||||
__new__ = Callable()
|
||||
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly unbound `__call__` method)"
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly missing `__call__` method)"
|
||||
reveal_type(Foo(1)) # revealed: Foo
|
||||
# TODO should be - error: [missing-argument] "No argument provided for required parameter `x` of bound method `__call__`"
|
||||
# but we currently infer the signature of `__call__` as unknown, so it accepts any arguments
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly unbound `__call__` method)"
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly missing `__call__` method)"
|
||||
reveal_type(Foo()) # revealed: Foo
|
||||
```
|
||||
|
||||
|
@ -294,11 +294,11 @@ def _(flag: bool) -> None:
|
|||
class Foo:
|
||||
__init__ = Callable()
|
||||
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly unbound `__call__` method)"
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly missing `__call__` method)"
|
||||
reveal_type(Foo(1)) # revealed: Foo
|
||||
# TODO should be - error: [missing-argument] "No argument provided for required parameter `x` of bound method `__call__`"
|
||||
# but we currently infer the signature of `__call__` as unknown, so it accepts any arguments
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly unbound `__call__` method)"
|
||||
# error: [call-non-callable] "Object of type `Callable` is not callable (possibly missing `__call__` method)"
|
||||
reveal_type(Foo()) # revealed: Foo
|
||||
```
|
||||
|
||||
|
|
|
@ -114,7 +114,11 @@ def _(flag: bool):
|
|||
|
||||
this_fails = ThisFails()
|
||||
|
||||
# error: [possibly-unbound-implicit-call]
|
||||
# TODO: this would be a friendlier diagnostic if we propagated the error up the stack
|
||||
# and transformed it into a `[not-subscriptable]` error with a subdiagnostic explaining
|
||||
# that the cause of the error was a possibly missing `__getitem__` method
|
||||
#
|
||||
# error: [possibly-missing-implicit-call] "Method `__getitem__` of type `ThisFails` may be missing"
|
||||
reveal_type(this_fails[0]) # revealed: Unknown | str
|
||||
```
|
||||
|
||||
|
@ -270,6 +274,11 @@ def _(flag: bool):
|
|||
return str(key)
|
||||
|
||||
c = C()
|
||||
# error: [possibly-unbound-implicit-call]
|
||||
|
||||
# TODO: this would be a friendlier diagnostic if we propagated the error up the stack
|
||||
# and transformed it into a `[not-subscriptable]` error with a subdiagnostic explaining
|
||||
# that the cause of the error was a possibly missing `__getitem__` method
|
||||
#
|
||||
# error: [possibly-missing-implicit-call] "Method `__getitem__` of type `C` may be missing"
|
||||
reveal_type(c[0]) # revealed: str
|
||||
```
|
||||
|
|
|
@ -325,7 +325,7 @@ class D(metaclass=Meta):
|
|||
reveal_type(D.f(1)) # revealed: Literal["a"]
|
||||
```
|
||||
|
||||
If the class method is possibly unbound, we union the return types:
|
||||
If the class method is possibly missing, we union the return types:
|
||||
|
||||
```py
|
||||
def flag() -> bool:
|
||||
|
|
|
@ -219,7 +219,7 @@ def f(x: C | D):
|
|||
s = super(A, x)
|
||||
reveal_type(s) # revealed: <super: <class 'A'>, C> | <super: <class 'A'>, D>
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `b` on type `<super: <class 'A'>, C> | <super: <class 'A'>, D>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `b` on type `<super: <class 'A'>, C> | <super: <class 'A'>, D>` may be missing"
|
||||
s.b
|
||||
|
||||
def f(flag: bool):
|
||||
|
@ -259,7 +259,7 @@ def f(flag: bool):
|
|||
reveal_type(s.x) # revealed: Unknown | Literal[1, 2]
|
||||
reveal_type(s.y) # revealed: int | str
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `a` on type `<super: <class 'B'>, B> | <super: <class 'D'>, D>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `a` on type `<super: <class 'B'>, B> | <super: <class 'D'>, D>` may be missing"
|
||||
reveal_type(s.a) # revealed: str
|
||||
```
|
||||
|
||||
|
|
|
@ -351,7 +351,7 @@ reveal_type(C4.meta_attribute) # revealed: Literal["value on metaclass"]
|
|||
reveal_type(C4.meta_non_data_descriptor) # revealed: Literal["non-data"]
|
||||
```
|
||||
|
||||
When a metaclass data descriptor is possibly unbound, we union the result type of its `__get__`
|
||||
When a metaclass data descriptor is possibly missing, we union the result type of its `__get__`
|
||||
method with an underlying class level attribute, if present:
|
||||
|
||||
```py
|
||||
|
@ -365,7 +365,7 @@ def _(flag: bool):
|
|||
meta_data_descriptor1: Literal["value on class"] = "value on class"
|
||||
|
||||
reveal_type(C5.meta_data_descriptor1) # revealed: Literal["data", "value on class"]
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(C5.meta_data_descriptor2) # revealed: Literal["data"]
|
||||
|
||||
# TODO: We currently emit two diagnostics here, corresponding to the two states of `flag`. The diagnostics are not
|
||||
|
@ -375,11 +375,11 @@ def _(flag: bool):
|
|||
# error: [invalid-assignment] "Object of type `None` is not assignable to attribute `meta_data_descriptor1` of type `Literal["value on class"]`"
|
||||
C5.meta_data_descriptor1 = None
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
C5.meta_data_descriptor2 = 1
|
||||
```
|
||||
|
||||
When a class-level attribute is possibly unbound, we union its (descriptor protocol) type with the
|
||||
When a class-level attribute is possibly missing, we union its (descriptor protocol) type with the
|
||||
metaclass attribute (unless it's a data descriptor, which always takes precedence):
|
||||
|
||||
```py
|
||||
|
@ -401,7 +401,7 @@ def _(flag: bool):
|
|||
reveal_type(C6.attribute1) # revealed: Literal["data"]
|
||||
reveal_type(C6.attribute2) # revealed: Literal["non-data", "value on class"]
|
||||
reveal_type(C6.attribute3) # revealed: Literal["value on metaclass", "value on class"]
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(C6.attribute4) # revealed: Literal["value on class"]
|
||||
```
|
||||
|
||||
|
@ -756,16 +756,16 @@ def _(flag: bool):
|
|||
non_data: NonDataDescriptor = NonDataDescriptor()
|
||||
data: DataDescriptor = DataDescriptor()
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `non_data` on type `<class 'PossiblyUnbound'>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `non_data` on type `<class 'PossiblyUnbound'>` may be missing"
|
||||
reveal_type(PossiblyUnbound.non_data) # revealed: int
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `non_data` on type `PossiblyUnbound` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `non_data` on type `PossiblyUnbound` may be missing"
|
||||
reveal_type(PossiblyUnbound().non_data) # revealed: int
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `data` on type `<class 'PossiblyUnbound'>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `data` on type `<class 'PossiblyUnbound'>` may be missing"
|
||||
reveal_type(PossiblyUnbound.data) # revealed: int
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `data` on type `PossiblyUnbound` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `data` on type `PossiblyUnbound` may be missing"
|
||||
reveal_type(PossiblyUnbound().data) # revealed: int
|
||||
```
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ instance = C()
|
|||
instance.non_existent = 1 # error: [unresolved-attribute]
|
||||
```
|
||||
|
||||
## Possibly-unbound attributes
|
||||
## Possibly-missing attributes
|
||||
|
||||
When trying to set an attribute that is not defined in all branches, we emit errors:
|
||||
|
||||
|
@ -79,10 +79,10 @@ def _(flag: bool) -> None:
|
|||
if flag:
|
||||
attr: int = 0
|
||||
|
||||
C.attr = 1 # error: [possibly-unbound-attribute]
|
||||
C.attr = 1 # error: [possibly-missing-attribute]
|
||||
|
||||
instance = C()
|
||||
instance.attr = 1 # error: [possibly-unbound-attribute]
|
||||
instance.attr = 1 # error: [possibly-missing-attribute]
|
||||
```
|
||||
|
||||
## Data descriptors
|
||||
|
|
|
@ -23,7 +23,7 @@ async def main() -> None:
|
|||
await MissingAwait() # error: [invalid-await]
|
||||
```
|
||||
|
||||
## Custom type with possibly unbound `__await__`
|
||||
## Custom type with possibly missing `__await__`
|
||||
|
||||
This diagnostic also points to the method definition if available.
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ def _(n: int):
|
|||
# error: [invalid-argument-type] "Argument to function `f5` is incorrect: Expected `str`, found `Literal[3]`"
|
||||
# error: [no-matching-overload] "No overload of function `f6` matches arguments"
|
||||
# error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
# error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
# error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
x = f(3)
|
||||
```
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ def _(flag: bool):
|
|||
|
||||
reveal_type(A.union_declared) # revealed: int | str
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `possibly_unbound` on type `<class 'A'>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `possibly_unbound` on type `<class 'A'>` may be missing"
|
||||
reveal_type(A.possibly_unbound) # revealed: str
|
||||
|
||||
# error: [unresolved-attribute] "Type `<class 'A'>` has no attribute `non_existent`"
|
||||
|
|
|
@ -22,7 +22,7 @@ reveal_type(y)
|
|||
```
|
||||
|
||||
```py
|
||||
# error: [possibly-unbound-import] "Member `y` of module `maybe_unbound` is possibly unbound"
|
||||
# error: [possibly-missing-import] "Member `y` of module `maybe_unbound` may be missing"
|
||||
from maybe_unbound import x, y
|
||||
|
||||
reveal_type(x) # revealed: Unknown | Literal[3]
|
||||
|
@ -53,7 +53,7 @@ reveal_type(y)
|
|||
Importing an annotated name prefers the declared type over the inferred type:
|
||||
|
||||
```py
|
||||
# error: [possibly-unbound-import] "Member `y` of module `maybe_unbound_annotated` is possibly unbound"
|
||||
# error: [possibly-missing-import] "Member `y` of module `maybe_unbound_annotated` may be missing"
|
||||
from maybe_unbound_annotated import x, y
|
||||
|
||||
reveal_type(x) # revealed: Unknown | Literal[3]
|
||||
|
|
|
@ -306,7 +306,7 @@ The following scenarios are when a re-export happens conditionally in a stub fil
|
|||
### Global import
|
||||
|
||||
```py
|
||||
# error: "Member `Foo` of module `a` is possibly unbound"
|
||||
# error: "Member `Foo` of module `a` may be missing"
|
||||
from a import Foo
|
||||
|
||||
reveal_type(Foo) # revealed: str
|
||||
|
@ -337,7 +337,7 @@ Here, both the branches of the condition are import statements where one of them
|
|||
the other does not.
|
||||
|
||||
```py
|
||||
# error: "Member `Foo` of module `a` is possibly unbound"
|
||||
# error: "Member `Foo` of module `a` may be missing"
|
||||
from a import Foo
|
||||
|
||||
reveal_type(Foo) # revealed: <class 'Foo'>
|
||||
|
@ -365,7 +365,7 @@ class Foo: ...
|
|||
### Re-export in one branch
|
||||
|
||||
```py
|
||||
# error: "Member `Foo` of module `a` is possibly unbound"
|
||||
# error: "Member `Foo` of module `a` may be missing"
|
||||
from a import Foo
|
||||
|
||||
reveal_type(Foo) # revealed: <class 'Foo'>
|
||||
|
|
|
@ -88,7 +88,7 @@ async def foo():
|
|||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
### Possibly unbound `__anext__` method
|
||||
### Possibly missing `__anext__` method
|
||||
|
||||
```py
|
||||
from typing_extensions import reveal_type
|
||||
|
@ -108,7 +108,7 @@ async def foo(flag: bool):
|
|||
reveal_type(x) # revealed: int
|
||||
```
|
||||
|
||||
### Possibly unbound `__aiter__` method
|
||||
### Possibly missing `__aiter__` method
|
||||
|
||||
```py
|
||||
from typing_extensions import reveal_type
|
||||
|
|
|
@ -363,7 +363,7 @@ for x in Bad():
|
|||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
## `__iter__` returns an object with a possibly unbound `__next__` method
|
||||
## `__iter__` returns an object with a possibly missing `__next__` method
|
||||
|
||||
```py
|
||||
def _(flag: bool):
|
||||
|
@ -412,7 +412,7 @@ for y in Iterable2():
|
|||
reveal_type(y) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Possibly unbound `__iter__` and bad `__getitem__` method
|
||||
## Possibly missing `__iter__` and bad `__getitem__` method
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
|
@ -438,12 +438,12 @@ def _(flag: bool):
|
|||
reveal_type(x) # revealed: int | bytes
|
||||
```
|
||||
|
||||
## Possibly unbound `__iter__` and not-callable `__getitem__`
|
||||
## Possibly missing `__iter__` and not-callable `__getitem__`
|
||||
|
||||
This snippet tests that we infer the element type correctly in the following edge case:
|
||||
|
||||
- `__iter__` is a method with the correct parameter spec that returns a valid iterator; BUT
|
||||
- `__iter__` is possibly unbound; AND
|
||||
- `__iter__` is possibly missing; AND
|
||||
- `__getitem__` is set to a non-callable type
|
||||
|
||||
It's important that we emit a diagnostic here, but it's also important that we still use the return
|
||||
|
@ -466,7 +466,7 @@ def _(flag: bool):
|
|||
reveal_type(x) # revealed: int
|
||||
```
|
||||
|
||||
## Possibly unbound `__iter__` and possibly unbound `__getitem__`
|
||||
## Possibly missing `__iter__` and possibly missing `__getitem__`
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
|
@ -560,7 +560,7 @@ for x in Iterable():
|
|||
reveal_type(x) # revealed: int
|
||||
```
|
||||
|
||||
## Possibly unbound `__iter__` but definitely bound `__getitem__`
|
||||
## Possibly missing `__iter__` but definitely bound `__getitem__`
|
||||
|
||||
Here, we should not emit a diagnostic: if `__iter__` is unbound, we should fallback to
|
||||
`__getitem__`:
|
||||
|
@ -694,7 +694,7 @@ def _(flag: bool):
|
|||
reveal_type(y) # revealed: str | int
|
||||
```
|
||||
|
||||
## Possibly unbound `__iter__` and possibly invalid `__getitem__`
|
||||
## Possibly missing `__iter__` and possibly invalid `__getitem__`
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
|
|
|
@ -135,9 +135,9 @@ a.b = B()
|
|||
reveal_type(a.b) # revealed: B
|
||||
reveal_type(a.b.c1) # revealed: C | None
|
||||
reveal_type(a.b.c2) # revealed: C | None
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a.b.c1.d) # revealed: D | None
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a.b.c2.d) # revealed: D | None
|
||||
```
|
||||
|
||||
|
@ -295,9 +295,9 @@ class C:
|
|||
reveal_type(b.a.x[0]) # revealed: Literal[0]
|
||||
|
||||
def _():
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(b.a.x[0]) # revealed: Unknown | int | None
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(b.a.x) # revealed: Unknown | list[int | None]
|
||||
reveal_type(b.a) # revealed: Unknown | A | None
|
||||
```
|
||||
|
|
|
@ -161,7 +161,7 @@ class _:
|
|||
a.b = B()
|
||||
|
||||
class _:
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(a.b.c1.d) # revealed: D | None
|
||||
reveal_type(a.b.c1) # revealed: C | None
|
||||
```
|
||||
|
|
|
@ -60,7 +60,7 @@ def _(obj: WithSpam):
|
|||
```
|
||||
|
||||
When a class may or may not have a `spam` attribute, `hasattr` narrowing can provide evidence that
|
||||
the attribute exists. Here, no `possibly-unbound-attribute` error is emitted in the `if` branch:
|
||||
the attribute exists. Here, no `possibly-missing-attribute` error is emitted in the `if` branch:
|
||||
|
||||
```py
|
||||
def returns_bool() -> bool:
|
||||
|
@ -71,7 +71,7 @@ class MaybeWithSpam:
|
|||
spam: int = 42
|
||||
|
||||
def _(obj: MaybeWithSpam):
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(obj.spam) # revealed: int
|
||||
|
||||
if hasattr(obj, "spam"):
|
||||
|
@ -81,7 +81,7 @@ def _(obj: MaybeWithSpam):
|
|||
reveal_type(obj) # revealed: MaybeWithSpam & ~<Protocol with members 'spam'>
|
||||
|
||||
# TODO: Ideally, we would emit `[unresolved-attribute]` and reveal `Unknown` here:
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(obj.spam) # revealed: int
|
||||
```
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class C:
|
|||
if flag:
|
||||
x = 2
|
||||
|
||||
# error: [possibly-unbound-attribute] "Attribute `x` on type `<class 'C'>` is possibly unbound"
|
||||
# error: [possibly-missing-attribute] "Attribute `x` on type `<class 'C'>` may be missing"
|
||||
reveal_type(C.x) # revealed: Unknown | Literal[2]
|
||||
reveal_type(C.y) # revealed: Unknown | Literal[1]
|
||||
```
|
||||
|
@ -52,7 +52,7 @@ class C:
|
|||
elif coinflip():
|
||||
x: str = "abc"
|
||||
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
reveal_type(C.x) # revealed: int | str
|
||||
```
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: async_for.md - Async - Error cases - Possibly unbound `__aiter__` method
|
||||
mdtest name: async_for.md - Async - Error cases - Possibly missing `__aiter__` method
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/loops/async_for.md
|
||||
---
|
||||
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: async_for.md - Async - Error cases - Possibly unbound `__anext__` method
|
||||
mdtest name: async_for.md - Async - Error cases - Possibly missing `__anext__` method
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/loops/async_for.md
|
||||
---
|
||||
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: attribute_assignment.md - Attribute assignment - Possibly-unbound attributes
|
||||
mdtest name: attribute_assignment.md - Attribute assignment - Possibly-missing attributes
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/attribute_assignment.md
|
||||
---
|
||||
|
||||
|
@ -17,37 +17,37 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/attribute_as
|
|||
3 | if flag:
|
||||
4 | attr: int = 0
|
||||
5 |
|
||||
6 | C.attr = 1 # error: [possibly-unbound-attribute]
|
||||
6 | C.attr = 1 # error: [possibly-missing-attribute]
|
||||
7 |
|
||||
8 | instance = C()
|
||||
9 | instance.attr = 1 # error: [possibly-unbound-attribute]
|
||||
9 | instance.attr = 1 # error: [possibly-missing-attribute]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
warning[possibly-unbound-attribute]: Attribute `attr` on type `<class 'C'>` is possibly unbound
|
||||
warning[possibly-missing-attribute]: Attribute `attr` on type `<class 'C'>` may be missing
|
||||
--> src/mdtest_snippet.py:6:5
|
||||
|
|
||||
4 | attr: int = 0
|
||||
5 |
|
||||
6 | C.attr = 1 # error: [possibly-unbound-attribute]
|
||||
6 | C.attr = 1 # error: [possibly-missing-attribute]
|
||||
| ^^^^^^
|
||||
7 |
|
||||
8 | instance = C()
|
||||
|
|
||||
info: rule `possibly-unbound-attribute` is enabled by default
|
||||
info: rule `possibly-missing-attribute` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
warning[possibly-unbound-attribute]: Attribute `attr` on type `C` is possibly unbound
|
||||
warning[possibly-missing-attribute]: Attribute `attr` on type `C` may be missing
|
||||
--> src/mdtest_snippet.py:9:5
|
||||
|
|
||||
8 | instance = C()
|
||||
9 | instance.attr = 1 # error: [possibly-unbound-attribute]
|
||||
9 | instance.attr = 1 # error: [possibly-missing-attribute]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
info: rule `possibly-unbound-attribute` is enabled by default
|
||||
info: rule `possibly-missing-attribute` is enabled by default
|
||||
|
||||
```
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: for.md - For loops - Possibly unbound `__iter__` and possibly invalid `__getitem__`
|
||||
mdtest name: for.md - For loops - Possibly missing `__iter__` and possibly invalid `__getitem__`
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/loops/for.md
|
||||
---
|
||||
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: for.md - For loops - Possibly unbound `__iter__` and bad `__getitem__` method
|
||||
mdtest name: for.md - For loops - Possibly missing `__iter__` and bad `__getitem__` method
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/loops/for.md
|
||||
---
|
||||
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: for.md - For loops - Possibly unbound `__iter__` and possibly unbound `__getitem__`
|
||||
mdtest name: for.md - For loops - Possibly missing `__iter__` and possibly missing `__getitem__`
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/loops/for.md
|
||||
---
|
||||
|
|
@ -3,7 +3,7 @@ source: crates/ty_test/src/lib.rs
|
|||
expression: snapshot
|
||||
---
|
||||
---
|
||||
mdtest name: invalid_await.md - Invalid await diagnostics - Custom type with possibly unbound `__await__`
|
||||
mdtest name: invalid_await.md - Invalid await diagnostics - Custom type with possibly missing `__await__`
|
||||
mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/invalid_await.md
|
||||
---
|
||||
|
||||
|
@ -41,7 +41,7 @@ error[invalid-await]: `PossiblyUnbound` is not awaitable
|
|||
| --------------- method defined here
|
||||
6 | yield
|
||||
|
|
||||
info: `__await__` is possibly unbound
|
||||
info: `__await__` may be missing
|
||||
info: rule `invalid-await` is enabled by default
|
||||
|
||||
```
|
|
@ -70,7 +70,7 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/diagnostics/union_call.m
|
|||
56 | # error: [invalid-argument-type] "Argument to function `f5` is incorrect: Expected `str`, found `Literal[3]`"
|
||||
57 | # error: [no-matching-overload] "No overload of function `f6` matches arguments"
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
```
|
||||
|
||||
|
@ -81,7 +81,7 @@ error[call-non-callable]: Object of type `Literal[5]` is not callable
|
|||
--> src/mdtest_snippet.py:60:9
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
|
@ -92,11 +92,11 @@ info: rule `call-non-callable` is enabled by default
|
|||
```
|
||||
|
||||
```
|
||||
error[call-non-callable]: Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)
|
||||
error[call-non-callable]: Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)
|
||||
--> src/mdtest_snippet.py:60:9
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
|
@ -111,7 +111,7 @@ error[missing-argument]: No argument provided for required parameter `b` of func
|
|||
--> src/mdtest_snippet.py:60:9
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
|
@ -126,7 +126,7 @@ error[no-matching-overload]: No overload of function `f6` matches arguments
|
|||
--> src/mdtest_snippet.py:60:9
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^^^^
|
||||
|
|
||||
|
@ -162,7 +162,7 @@ error[invalid-argument-type]: Argument to function `f2` is incorrect
|
|||
--> src/mdtest_snippet.py:60:11
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^ Expected `str`, found `Literal[3]`
|
||||
|
|
||||
|
@ -186,7 +186,7 @@ error[invalid-argument-type]: Argument to function `f4` is incorrect
|
|||
--> src/mdtest_snippet.py:60:11
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^ Argument type `Literal[3]` does not satisfy upper bound `str` of type variable `T`
|
||||
|
|
||||
|
@ -210,7 +210,7 @@ error[invalid-argument-type]: Argument to function `f5` is incorrect
|
|||
--> src/mdtest_snippet.py:60:11
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^ Expected `str`, found `Literal[3]`
|
||||
|
|
||||
|
@ -237,7 +237,7 @@ error[too-many-positional-arguments]: Too many positional arguments to function
|
|||
--> src/mdtest_snippet.py:60:11
|
||||
|
|
||||
58 | # error: [call-non-callable] "Object of type `Literal[5]` is not callable"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly unbound `__call__` method)"
|
||||
59 | # error: [call-non-callable] "Object of type `PossiblyNotCallable` is not callable (possibly missing `__call__` method)"
|
||||
60 | x = f(3)
|
||||
| ^
|
||||
|
|
||||
|
|
|
@ -1530,7 +1530,7 @@ if flag():
|
|||
```
|
||||
|
||||
```py
|
||||
# error: [possibly-unbound-import]
|
||||
# error: [possibly-missing-import]
|
||||
from module import symbol
|
||||
```
|
||||
|
||||
|
|
|
@ -14,7 +14,11 @@ a = NotSubscriptable()[0] # error: "Cannot subscript object of type `NotSubscri
|
|||
class NotSubscriptable:
|
||||
__getitem__ = None
|
||||
|
||||
# error: "Method `__getitem__` of type `Unknown | None` is possibly not callable on object of type `NotSubscriptable`"
|
||||
# TODO: this would be more user-friendly if the `call-non-callable` diagnostic was
|
||||
# transformed into a `not-subscriptable` diagnostic with a subdiagnostic explaining
|
||||
# that this was because `__getitem__` was possibly not callable
|
||||
#
|
||||
# error: [call-non-callable] "Method `__getitem__` of type `Unknown | None` may not be callable on object of type `NotSubscriptable`"
|
||||
a = NotSubscriptable()[0]
|
||||
```
|
||||
|
||||
|
@ -82,7 +86,7 @@ class NoSetitem:
|
|||
__setitem__ = None
|
||||
|
||||
a = NoSetitem()
|
||||
a[0] = 0 # error: "Method `__setitem__` of type `Unknown | None` is possibly not callable on object of type `NoSetitem`"
|
||||
a[0] = 0 # error: "Method `__setitem__` of type `Unknown | None` may not be callable on object of type `NoSetitem`"
|
||||
```
|
||||
|
||||
## Valid `__setitem__` method
|
||||
|
|
|
@ -198,7 +198,7 @@ import sys
|
|||
|
||||
if sys.platform == "win32":
|
||||
# TODO: we should not emit an error here
|
||||
# error: [possibly-unbound-attribute]
|
||||
# error: [possibly-missing-attribute]
|
||||
sys.getwindowsversion()
|
||||
```
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ async def _(flag: bool):
|
|||
class NotAContextManager: ...
|
||||
context_expr = Manager1() if flag else NotAContextManager()
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager1 | NotAContextManager` cannot be used with `async with` because the methods `__aenter__` and `__aexit__` are possibly unbound"
|
||||
# error: [invalid-context-manager] "Object of type `Manager1 | NotAContextManager` cannot be used with `async with` because the methods `__aenter__` and `__aexit__` are possibly missing"
|
||||
async with context_expr as f:
|
||||
reveal_type(f) # revealed: str
|
||||
```
|
||||
|
@ -129,7 +129,7 @@ async def _(flag: bool):
|
|||
|
||||
async def __exit__(self, *args): ...
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `async with` because the method `__aenter__` is possibly unbound"
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `async with` because the method `__aenter__` may be missing"
|
||||
async with Manager() as f:
|
||||
reveal_type(f) # revealed: CoroutineType[Any, Any, str]
|
||||
```
|
||||
|
|
|
@ -113,7 +113,7 @@ def _(flag: bool):
|
|||
class NotAContextManager: ...
|
||||
context_expr = Manager1() if flag else NotAContextManager()
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager1 | NotAContextManager` cannot be used with `with` because the methods `__enter__` and `__exit__` are possibly unbound"
|
||||
# error: [invalid-context-manager] "Object of type `Manager1 | NotAContextManager` cannot be used with `with` because the methods `__enter__` and `__exit__` are possibly missing"
|
||||
with context_expr as f:
|
||||
reveal_type(f) # revealed: str
|
||||
```
|
||||
|
@ -129,7 +129,7 @@ def _(flag: bool):
|
|||
|
||||
def __exit__(self, *args): ...
|
||||
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because the method `__enter__` is possibly unbound"
|
||||
# error: [invalid-context-manager] "Object of type `Manager` cannot be used with `with` because the method `__enter__` may be missing"
|
||||
with Manager() as f:
|
||||
reveal_type(f) # revealed: str
|
||||
```
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue