mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 20:42:10 +00:00
Rename Red Knot (#17820)
This commit is contained in:
parent
e6a798b962
commit
b51c4f82ea
1564 changed files with 1598 additions and 1578 deletions
169
crates/ty_python_semantic/resources/mdtest/unary/custom.md
Normal file
169
crates/ty_python_semantic/resources/mdtest/unary/custom.md
Normal file
|
@ -0,0 +1,169 @@
|
|||
# Custom unary operations
|
||||
|
||||
## Class instances
|
||||
|
||||
```py
|
||||
class Yes:
|
||||
def __pos__(self) -> bool:
|
||||
return False
|
||||
|
||||
def __neg__(self) -> str:
|
||||
return "negative"
|
||||
|
||||
def __invert__(self) -> int:
|
||||
return 17
|
||||
|
||||
class Sub(Yes): ...
|
||||
class No: ...
|
||||
|
||||
reveal_type(+Yes()) # revealed: bool
|
||||
reveal_type(-Yes()) # revealed: str
|
||||
reveal_type(~Yes()) # revealed: int
|
||||
|
||||
reveal_type(+Sub()) # revealed: bool
|
||||
reveal_type(-Sub()) # revealed: str
|
||||
reveal_type(~Sub()) # revealed: int
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `No`"
|
||||
reveal_type(+No()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `No`"
|
||||
reveal_type(-No()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `No`"
|
||||
reveal_type(~No()) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Classes
|
||||
|
||||
Dunder methods defined in a class are available to instances of that class, but not to the class
|
||||
itself. (For these operators to work on the class itself, they would have to be defined on the
|
||||
class's type, i.e. `type`.)
|
||||
|
||||
```py
|
||||
class Yes:
|
||||
def __pos__(self) -> bool:
|
||||
return False
|
||||
|
||||
def __neg__(self) -> str:
|
||||
return "negative"
|
||||
|
||||
def __invert__(self) -> int:
|
||||
return 17
|
||||
|
||||
class Sub(Yes): ...
|
||||
class No: ...
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[Yes]`"
|
||||
reveal_type(+Yes) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[Yes]`"
|
||||
reveal_type(-Yes) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[Yes]`"
|
||||
reveal_type(~Yes) # revealed: Unknown
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[Sub]`"
|
||||
reveal_type(+Sub) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[Sub]`"
|
||||
reveal_type(-Sub) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[Sub]`"
|
||||
reveal_type(~Sub) # revealed: Unknown
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[No]`"
|
||||
reveal_type(+No) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[No]`"
|
||||
reveal_type(-No) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[No]`"
|
||||
reveal_type(~No) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Function literals
|
||||
|
||||
```py
|
||||
def f():
|
||||
pass
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `def f() -> Unknown`"
|
||||
reveal_type(+f) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `def f() -> Unknown`"
|
||||
reveal_type(-f) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `def f() -> Unknown`"
|
||||
reveal_type(~f) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Subclass
|
||||
|
||||
```py
|
||||
class Yes:
|
||||
def __pos__(self) -> bool:
|
||||
return False
|
||||
|
||||
def __neg__(self) -> str:
|
||||
return "negative"
|
||||
|
||||
def __invert__(self) -> int:
|
||||
return 17
|
||||
|
||||
class Sub(Yes): ...
|
||||
class No: ...
|
||||
|
||||
def yes() -> type[Yes]:
|
||||
return Yes
|
||||
|
||||
def sub() -> type[Sub]:
|
||||
return Sub
|
||||
|
||||
def no() -> type[No]:
|
||||
return No
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `type[Yes]`"
|
||||
reveal_type(+yes()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `type[Yes]`"
|
||||
reveal_type(-yes()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `type[Yes]`"
|
||||
reveal_type(~yes()) # revealed: Unknown
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `type[Sub]`"
|
||||
reveal_type(+sub()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `type[Sub]`"
|
||||
reveal_type(-sub()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `type[Sub]`"
|
||||
reveal_type(~sub()) # revealed: Unknown
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `type[No]`"
|
||||
reveal_type(+no()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `type[No]`"
|
||||
reveal_type(-no()) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `type[No]`"
|
||||
reveal_type(~no()) # revealed: Unknown
|
||||
```
|
||||
|
||||
## Metaclass
|
||||
|
||||
```py
|
||||
class Meta(type):
|
||||
def __pos__(self) -> bool:
|
||||
return False
|
||||
|
||||
def __neg__(self) -> str:
|
||||
return "negative"
|
||||
|
||||
def __invert__(self) -> int:
|
||||
return 17
|
||||
|
||||
class Yes(metaclass=Meta): ...
|
||||
class Sub(Yes): ...
|
||||
class No: ...
|
||||
|
||||
reveal_type(+Yes) # revealed: bool
|
||||
reveal_type(-Yes) # revealed: str
|
||||
reveal_type(~Yes) # revealed: int
|
||||
|
||||
reveal_type(+Sub) # revealed: bool
|
||||
reveal_type(-Sub) # revealed: str
|
||||
reveal_type(~Sub) # revealed: int
|
||||
|
||||
# error: [unsupported-operator] "Unary operator `+` is unsupported for type `Literal[No]`"
|
||||
reveal_type(+No) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `-` is unsupported for type `Literal[No]`"
|
||||
reveal_type(-No) # revealed: Unknown
|
||||
# error: [unsupported-operator] "Unary operator `~` is unsupported for type `Literal[No]`"
|
||||
reveal_type(~No) # revealed: Unknown
|
||||
```
|
25
crates/ty_python_semantic/resources/mdtest/unary/integers.md
Normal file
25
crates/ty_python_semantic/resources/mdtest/unary/integers.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Unary Operations
|
||||
|
||||
## Unary Addition
|
||||
|
||||
```py
|
||||
reveal_type(+0) # revealed: Literal[0]
|
||||
reveal_type(+1) # revealed: Literal[1]
|
||||
reveal_type(+True) # revealed: Literal[1]
|
||||
```
|
||||
|
||||
## Unary Subtraction
|
||||
|
||||
```py
|
||||
reveal_type(-0) # revealed: Literal[0]
|
||||
reveal_type(-1) # revealed: Literal[-1]
|
||||
reveal_type(-True) # revealed: Literal[-1]
|
||||
```
|
||||
|
||||
## Unary Bitwise Inversion
|
||||
|
||||
```py
|
||||
reveal_type(~0) # revealed: Literal[-1]
|
||||
reveal_type(~1) # revealed: Literal[-2]
|
||||
reveal_type(~True) # revealed: Literal[-2]
|
||||
```
|
|
@ -0,0 +1,33 @@
|
|||
# Invert, UAdd, USub
|
||||
|
||||
## Instance
|
||||
|
||||
```py
|
||||
from typing import Literal
|
||||
|
||||
class Number:
|
||||
def __init__(self, value: int):
|
||||
self.value = 1
|
||||
|
||||
def __pos__(self) -> int:
|
||||
return +self.value
|
||||
|
||||
def __neg__(self) -> int:
|
||||
return -self.value
|
||||
|
||||
def __invert__(self) -> Literal[True]:
|
||||
return True
|
||||
|
||||
a = Number(0)
|
||||
|
||||
reveal_type(+a) # revealed: int
|
||||
reveal_type(-a) # revealed: int
|
||||
reveal_type(~a) # revealed: Literal[True]
|
||||
|
||||
class NoDunder: ...
|
||||
|
||||
b = NoDunder()
|
||||
+b # error: [unsupported-operator] "Unary operator `+` is unsupported for type `NoDunder`"
|
||||
-b # error: [unsupported-operator] "Unary operator `-` is unsupported for type `NoDunder`"
|
||||
~b # error: [unsupported-operator] "Unary operator `~` is unsupported for type `NoDunder`"
|
||||
```
|
217
crates/ty_python_semantic/resources/mdtest/unary/not.md
Normal file
217
crates/ty_python_semantic/resources/mdtest/unary/not.md
Normal file
|
@ -0,0 +1,217 @@
|
|||
# Unary not
|
||||
|
||||
## None
|
||||
|
||||
```py
|
||||
reveal_type(not None) # revealed: Literal[True]
|
||||
reveal_type(not not None) # revealed: Literal[False]
|
||||
```
|
||||
|
||||
## Function
|
||||
|
||||
```py
|
||||
def f():
|
||||
return 1
|
||||
|
||||
reveal_type(not f) # revealed: Literal[False]
|
||||
# TODO Unknown should not be part of the type of typing.reveal_type
|
||||
# reveal_type(not reveal_type) revealed: Literal[False]
|
||||
```
|
||||
|
||||
## Module
|
||||
|
||||
```py
|
||||
import b
|
||||
import warnings
|
||||
|
||||
reveal_type(not b) # revealed: Literal[False]
|
||||
reveal_type(not warnings) # revealed: Literal[False]
|
||||
```
|
||||
|
||||
`b.py`:
|
||||
|
||||
```py
|
||||
y = 1
|
||||
```
|
||||
|
||||
## Union
|
||||
|
||||
```py
|
||||
def _(flag: bool):
|
||||
if flag:
|
||||
p = 1
|
||||
q = 3.3
|
||||
r = "hello"
|
||||
s = "world"
|
||||
t = 0
|
||||
else:
|
||||
p = "hello"
|
||||
q = 4
|
||||
r = ""
|
||||
s = 0
|
||||
t = ""
|
||||
|
||||
reveal_type(not p) # revealed: Literal[False]
|
||||
reveal_type(not q) # revealed: bool
|
||||
reveal_type(not r) # revealed: bool
|
||||
reveal_type(not s) # revealed: bool
|
||||
reveal_type(not t) # revealed: Literal[True]
|
||||
```
|
||||
|
||||
## Integer literal
|
||||
|
||||
```py
|
||||
reveal_type(not 1) # revealed: Literal[False]
|
||||
reveal_type(not 1234567890987654321) # revealed: Literal[False]
|
||||
reveal_type(not 0) # revealed: Literal[True]
|
||||
reveal_type(not -1) # revealed: Literal[False]
|
||||
reveal_type(not -1234567890987654321) # revealed: Literal[False]
|
||||
reveal_type(not --987) # revealed: Literal[False]
|
||||
```
|
||||
|
||||
## Boolean literal
|
||||
|
||||
```py
|
||||
w = True
|
||||
reveal_type(w) # revealed: Literal[True]
|
||||
|
||||
x = False
|
||||
reveal_type(x) # revealed: Literal[False]
|
||||
|
||||
reveal_type(not w) # revealed: Literal[False]
|
||||
|
||||
reveal_type(not x) # revealed: Literal[True]
|
||||
```
|
||||
|
||||
## String literal
|
||||
|
||||
```py
|
||||
reveal_type(not "hello") # revealed: Literal[False]
|
||||
reveal_type(not "") # revealed: Literal[True]
|
||||
reveal_type(not "0") # revealed: Literal[False]
|
||||
reveal_type(not "hello" + "world") # revealed: Literal[False]
|
||||
```
|
||||
|
||||
## Bytes literal
|
||||
|
||||
```py
|
||||
reveal_type(not b"hello") # revealed: Literal[False]
|
||||
reveal_type(not b"") # revealed: Literal[True]
|
||||
reveal_type(not b"0") # revealed: Literal[False]
|
||||
reveal_type(not b"hello" + b"world") # revealed: Literal[False]
|
||||
```
|
||||
|
||||
## Tuple
|
||||
|
||||
```py
|
||||
reveal_type(not (1,)) # revealed: Literal[False]
|
||||
reveal_type(not (1, 2)) # revealed: Literal[False]
|
||||
reveal_type(not (1, 2, 3)) # revealed: Literal[False]
|
||||
reveal_type(not ()) # revealed: Literal[True]
|
||||
reveal_type(not ("hello",)) # revealed: Literal[False]
|
||||
reveal_type(not (1, "hello")) # revealed: Literal[False]
|
||||
```
|
||||
|
||||
## Instance
|
||||
|
||||
Not operator is inferred based on
|
||||
<https://docs.python.org/3/library/stdtypes.html#truth-value-testing>. An instance is True or False
|
||||
if the `__bool__` method says so.
|
||||
|
||||
At runtime, the `__len__` method is a fallback for `__bool__`, but we can't make use of that. If we
|
||||
have a class that defines `__len__` but not `__bool__`, it is possible that any subclass could add a
|
||||
`__bool__` method that would invalidate whatever conclusion we drew from `__len__`. So instances of
|
||||
classes without a `__bool__` method, with or without `__len__`, must be inferred as unknown
|
||||
truthiness.
|
||||
|
||||
```py
|
||||
from typing import Literal
|
||||
|
||||
class AlwaysTrue:
|
||||
def __bool__(self) -> Literal[True]:
|
||||
return True
|
||||
|
||||
# revealed: Literal[False]
|
||||
reveal_type(not AlwaysTrue())
|
||||
|
||||
class AlwaysFalse:
|
||||
def __bool__(self) -> Literal[False]:
|
||||
return False
|
||||
|
||||
# revealed: Literal[True]
|
||||
reveal_type(not AlwaysFalse())
|
||||
|
||||
# At runtime, no `__bool__` and no `__len__` means truthy, but we can't rely on that, because
|
||||
# a subclass could add a `__bool__` method.
|
||||
class NoBoolMethod: ...
|
||||
|
||||
# revealed: bool
|
||||
reveal_type(not NoBoolMethod())
|
||||
|
||||
# And we can't rely on `__len__` for the same reason: a subclass could add `__bool__`.
|
||||
class LenZero:
|
||||
def __len__(self) -> Literal[0]:
|
||||
return 0
|
||||
|
||||
# revealed: bool
|
||||
reveal_type(not LenZero())
|
||||
|
||||
class LenNonZero:
|
||||
def __len__(self) -> Literal[1]:
|
||||
return 1
|
||||
|
||||
# revealed: bool
|
||||
reveal_type(not LenNonZero())
|
||||
|
||||
class WithBothLenAndBool1:
|
||||
def __bool__(self) -> Literal[False]:
|
||||
return False
|
||||
|
||||
def __len__(self) -> Literal[2]:
|
||||
return 2
|
||||
|
||||
# revealed: Literal[True]
|
||||
reveal_type(not WithBothLenAndBool1())
|
||||
|
||||
class WithBothLenAndBool2:
|
||||
def __bool__(self) -> Literal[True]:
|
||||
return True
|
||||
|
||||
def __len__(self) -> Literal[0]:
|
||||
return 0
|
||||
|
||||
# revealed: Literal[False]
|
||||
reveal_type(not WithBothLenAndBool2())
|
||||
|
||||
class MethodBoolInvalid:
|
||||
def __bool__(self) -> int:
|
||||
return 0
|
||||
|
||||
# error: [unsupported-bool-conversion] "Boolean conversion is unsupported for type `MethodBoolInvalid`"
|
||||
# revealed: bool
|
||||
reveal_type(not MethodBoolInvalid())
|
||||
|
||||
# Don't trust a possibly-unbound `__bool__` method:
|
||||
def get_flag() -> bool:
|
||||
return True
|
||||
|
||||
class PossiblyUnboundBool:
|
||||
if get_flag():
|
||||
def __bool__(self) -> Literal[False]:
|
||||
return False
|
||||
|
||||
# revealed: bool
|
||||
reveal_type(not PossiblyUnboundBool())
|
||||
```
|
||||
|
||||
## Object that implements `__bool__` incorrectly
|
||||
|
||||
<!-- snapshot-diagnostics -->
|
||||
|
||||
```py
|
||||
class NotBoolable:
|
||||
__bool__: int = 3
|
||||
|
||||
# error: [unsupported-bool-conversion]
|
||||
not NotBoolable()
|
||||
```
|
Loading…
Add table
Add a link
Reference in a new issue