mirror of
https://github.com/astral-sh/ruff
synced 2026-01-20 21:10:48 -05:00
[ty] Rename non-subscriptable error code to not-subscriptable (#22193)
This commit is contained in:
48
crates/ty/docs/rules.md
generated
48
crates/ty/docs/rules.md
generated
@@ -2005,30 +2005,6 @@ def func(x: bool): ...
|
||||
func("string") # error: [no-matching-overload]
|
||||
```
|
||||
|
||||
## `non-subscriptable`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20non-subscriptable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1453" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
**What it does**
|
||||
|
||||
Checks for subscripting objects that do not support subscripting.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
Subscripting an object that does not support it will raise a `TypeError` at runtime.
|
||||
|
||||
**Examples**
|
||||
|
||||
```python
|
||||
4[1] # TypeError: 'int' object is not subscriptable
|
||||
```
|
||||
|
||||
## `not-iterable`
|
||||
|
||||
<small>
|
||||
@@ -2055,6 +2031,30 @@ for i in 34: # TypeError: 'int' object is not iterable
|
||||
pass
|
||||
```
|
||||
|
||||
## `not-subscriptable`
|
||||
|
||||
<small>
|
||||
Default level: <a href="../../rules#rule-levels" title="This lint has a default level of 'error'."><code>error</code></a> ·
|
||||
Added in <a href="https://github.com/astral-sh/ty/releases/tag/0.0.1-alpha.1">0.0.1-alpha.1</a> ·
|
||||
<a href="https://github.com/astral-sh/ty/issues?q=sort%3Aupdated-desc%20is%3Aissue%20is%3Aopen%20not-subscriptable" target="_blank">Related issues</a> ·
|
||||
<a href="https://github.com/astral-sh/ruff/blob/main/crates%2Fty_python_semantic%2Fsrc%2Ftypes%2Fdiagnostic.rs#L1453" target="_blank">View source</a>
|
||||
</small>
|
||||
|
||||
|
||||
**What it does**
|
||||
|
||||
Checks for subscripting objects that do not support subscripting.
|
||||
|
||||
**Why is this bad?**
|
||||
|
||||
Subscripting an object that does not support it will raise a `TypeError` at runtime.
|
||||
|
||||
**Examples**
|
||||
|
||||
```python
|
||||
4[1] # TypeError: 'int' object is not subscriptable
|
||||
```
|
||||
|
||||
## `override-of-final-method`
|
||||
|
||||
<small>
|
||||
|
||||
@@ -149,7 +149,7 @@ fn both_warnings_and_errors() -> anyhow::Result<()> {
|
||||
"test.py",
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
print(4[1]) # [not-subscriptable]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -162,18 +162,18 @@ fn both_warnings_and_errors() -> anyhow::Result<()> {
|
||||
|
|
||||
2 | print(x) # [unresolved-reference]
|
||||
| ^
|
||||
3 | print(4[1]) # [non-subscriptable]
|
||||
3 | print(4[1]) # [not-subscriptable]
|
||||
|
|
||||
info: rule `unresolved-reference` was selected on the command line
|
||||
|
||||
error[non-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
error[not-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
--> test.py:3:7
|
||||
|
|
||||
2 | print(x) # [unresolved-reference]
|
||||
3 | print(4[1]) # [non-subscriptable]
|
||||
3 | print(4[1]) # [not-subscriptable]
|
||||
| ^^^^
|
||||
|
|
||||
info: rule `non-subscriptable` is enabled by default
|
||||
info: rule `not-subscriptable` is enabled by default
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -189,7 +189,7 @@ fn both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::Result<()>
|
||||
"test.py",
|
||||
r###"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
print(4[1]) # [not-subscriptable]
|
||||
"###,
|
||||
)?;
|
||||
|
||||
@@ -202,18 +202,18 @@ fn both_warnings_and_errors_and_error_on_warning_is_true() -> anyhow::Result<()>
|
||||
|
|
||||
2 | print(x) # [unresolved-reference]
|
||||
| ^
|
||||
3 | print(4[1]) # [non-subscriptable]
|
||||
3 | print(4[1]) # [not-subscriptable]
|
||||
|
|
||||
info: rule `unresolved-reference` was selected on the command line
|
||||
|
||||
error[non-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
error[not-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
--> test.py:3:7
|
||||
|
|
||||
2 | print(x) # [unresolved-reference]
|
||||
3 | print(4[1]) # [non-subscriptable]
|
||||
3 | print(4[1]) # [not-subscriptable]
|
||||
| ^^^^
|
||||
|
|
||||
info: rule `non-subscriptable` is enabled by default
|
||||
info: rule `not-subscriptable` is enabled by default
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
@@ -229,7 +229,7 @@ fn exit_zero_is_true() -> anyhow::Result<()> {
|
||||
"test.py",
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
print(4[1]) # [not-subscriptable]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -242,18 +242,18 @@ fn exit_zero_is_true() -> anyhow::Result<()> {
|
||||
|
|
||||
2 | print(x) # [unresolved-reference]
|
||||
| ^
|
||||
3 | print(4[1]) # [non-subscriptable]
|
||||
3 | print(4[1]) # [not-subscriptable]
|
||||
|
|
||||
info: rule `unresolved-reference` was selected on the command line
|
||||
|
||||
error[non-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
error[not-subscriptable]: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
--> test.py:3:7
|
||||
|
|
||||
2 | print(x) # [unresolved-reference]
|
||||
3 | print(4[1]) # [non-subscriptable]
|
||||
3 | print(4[1]) # [not-subscriptable]
|
||||
| ^^^^
|
||||
|
|
||||
info: rule `non-subscriptable` is enabled by default
|
||||
info: rule `not-subscriptable` is enabled by default
|
||||
|
||||
Found 2 diagnostics
|
||||
|
||||
|
||||
@@ -634,7 +634,7 @@ fn concise_diagnostics() -> anyhow::Result<()> {
|
||||
"test.py",
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
print(4[1]) # [not-subscriptable]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
@@ -643,7 +643,7 @@ fn concise_diagnostics() -> anyhow::Result<()> {
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
test.py:2:7: warning[unresolved-reference] Name `x` used when not defined
|
||||
test.py:3:7: error[non-subscriptable] Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
test.py:3:7: error[not-subscriptable] Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
Found 2 diagnostics
|
||||
|
||||
----- stderr -----
|
||||
@@ -658,7 +658,7 @@ fn gitlab_diagnostics() -> anyhow::Result<()> {
|
||||
"test.py",
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
print(4[1]) # [not-subscriptable]
|
||||
from typing_extensions import reveal_type
|
||||
reveal_type('str'.lower()) # [revealed-type]
|
||||
"#,
|
||||
@@ -694,8 +694,8 @@ fn gitlab_diagnostics() -> anyhow::Result<()> {
|
||||
}
|
||||
},
|
||||
{
|
||||
"check_name": "non-subscriptable",
|
||||
"description": "non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method",
|
||||
"check_name": "not-subscriptable",
|
||||
"description": "not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method",
|
||||
"severity": "major",
|
||||
"fingerprint": "[FINGERPRINT]",
|
||||
"location": {
|
||||
@@ -744,7 +744,7 @@ fn github_diagnostics() -> anyhow::Result<()> {
|
||||
"test.py",
|
||||
r#"
|
||||
print(x) # [unresolved-reference]
|
||||
print(4[1]) # [non-subscriptable]
|
||||
print(4[1]) # [not-subscriptable]
|
||||
from typing_extensions import reveal_type
|
||||
reveal_type('str'.lower()) # [revealed-type]
|
||||
"#,
|
||||
@@ -755,7 +755,7 @@ fn github_diagnostics() -> anyhow::Result<()> {
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
::warning title=ty (unresolved-reference),file=<temp_dir>/test.py,line=2,col=7,endLine=2,endColumn=8::test.py:2:7: unresolved-reference: Name `x` used when not defined
|
||||
::error title=ty (non-subscriptable),file=<temp_dir>/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: non-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
::error title=ty (not-subscriptable),file=<temp_dir>/test.py,line=3,col=7,endLine=3,endColumn=11::test.py:3:7: not-subscriptable: Cannot subscript object of type `Literal[4]` with no `__getitem__` method
|
||||
::notice title=ty (revealed-type),file=<temp_dir>/test.py,line=5,col=13,endLine=5,endColumn=26::test.py:5:13: revealed-type: Revealed type: `LiteralString`
|
||||
|
||||
----- stderr -----
|
||||
|
||||
@@ -53,7 +53,7 @@ class ClassWithNormalDunder:
|
||||
def __getitem__(self, key: int) -> str:
|
||||
return str(key)
|
||||
|
||||
# error: [non-subscriptable]
|
||||
# error: [not-subscriptable]
|
||||
ClassWithNormalDunder[0]
|
||||
```
|
||||
|
||||
@@ -85,7 +85,7 @@ class ThisFails:
|
||||
|
||||
this_fails = ThisFails()
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `ThisFails` with no `__getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `ThisFails` with no `__getitem__` method"
|
||||
reveal_type(this_fails[0]) # revealed: Unknown
|
||||
```
|
||||
|
||||
@@ -259,8 +259,8 @@ class NotSubscriptable2:
|
||||
self.__getitem__ = external_getitem
|
||||
|
||||
def _(union: NotSubscriptable1 | NotSubscriptable2):
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `NotSubscriptable2` with no `__getitem__` method"
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `NotSubscriptable1` with no `__getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `NotSubscriptable2` with no `__getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `NotSubscriptable1` with no `__getitem__` method"
|
||||
union[0]
|
||||
```
|
||||
|
||||
|
||||
@@ -667,6 +667,6 @@ class B(A): ...
|
||||
|
||||
reveal_type(A()[0]) # revealed: int
|
||||
reveal_type(super(B, B()).__getitem__) # revealed: bound method B.__getitem__(key: int) -> int
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `<super: <class 'B'>, B>` with no `__getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `<super: <class 'B'>, B>` with no `__getitem__` method"
|
||||
super(B, B())[0]
|
||||
```
|
||||
|
||||
@@ -216,7 +216,7 @@ class OnlyDelItem:
|
||||
d = OnlyDelItem()
|
||||
del d[0] # OK
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `OnlyDelItem` with no `__getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `OnlyDelItem` with no `__getitem__` method"
|
||||
d[0]
|
||||
```
|
||||
|
||||
@@ -232,7 +232,7 @@ class OnlyGetItem:
|
||||
g = OnlyGetItem()
|
||||
reveal_type(g[0]) # revealed: str
|
||||
|
||||
# error: [non-subscriptable] "Cannot delete subscript on object of type `OnlyGetItem` with no `__delitem__` method"
|
||||
# error: [not-subscriptable] "Cannot delete subscript on object of type `OnlyGetItem` with no `__delitem__` method"
|
||||
del g[0]
|
||||
```
|
||||
|
||||
|
||||
@@ -72,32 +72,32 @@ from typing import TypeVar, Protocol, TypedDict
|
||||
|
||||
type B = ...
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias"
|
||||
reveal_type(B[int]) # revealed: Unknown
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias"
|
||||
def _(b: B[int]):
|
||||
reveal_type(b) # revealed: Unknown
|
||||
|
||||
type IntOrStr = int | str
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias"
|
||||
def _(c: IntOrStr[int]):
|
||||
reveal_type(c) # revealed: Unknown
|
||||
|
||||
type ListOfInts = list[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized"
|
||||
def _(l: ListOfInts[int]):
|
||||
reveal_type(l) # revealed: Unknown
|
||||
|
||||
type List[T] = list[T]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed"
|
||||
def _(l: List[int][int]):
|
||||
reveal_type(l) # revealed: Unknown
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'list[T@DoubleSpecialization]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'list[T@DoubleSpecialization]'>` is already specialized"
|
||||
type DoubleSpecialization[T] = list[T][T]
|
||||
|
||||
def _(d: DoubleSpecialization[int]):
|
||||
@@ -105,7 +105,7 @@ def _(d: DoubleSpecialization[int]):
|
||||
|
||||
type Tuple = tuple[int, str]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `tuple[int, str]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `tuple[int, str]` is already specialized"
|
||||
def _(doubly_specialized: Tuple[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
@@ -116,7 +116,7 @@ class LegacyProto(Protocol[T]):
|
||||
|
||||
type LegacyProtoInt = LegacyProto[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `LegacyProto[int]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `LegacyProto[int]` is already specialized"
|
||||
def _(x: LegacyProtoInt[int]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
|
||||
@@ -125,7 +125,7 @@ class Proto[T](Protocol):
|
||||
|
||||
type ProtoInt = Proto[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `Proto[int]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `Proto[int]` is already specialized"
|
||||
def _(x: ProtoInt[int]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
|
||||
@@ -135,7 +135,7 @@ class LegacyDict(TypedDict[T]):
|
||||
|
||||
type LegacyDictInt = LegacyDict[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias"
|
||||
def _(x: LegacyDictInt[int]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
|
||||
@@ -144,13 +144,13 @@ class Dict[T](TypedDict):
|
||||
|
||||
type DictInt = Dict[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `Dict[int]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `Dict[int]` is already specialized"
|
||||
def _(x: DictInt[int]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
|
||||
type Union = list[str] | list[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `list[str] | list[int]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `list[str] | list[int]` is already specialized"
|
||||
def _(x: Union[int]):
|
||||
reveal_type(x) # revealed: Unknown
|
||||
```
|
||||
|
||||
@@ -664,18 +664,18 @@ from typing import Protocol, TypeVar, TypedDict
|
||||
|
||||
ListOfInts = list[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'list[int]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'list[int]'>` is already specialized"
|
||||
def _(doubly_specialized: ListOfInts[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
type ListOfInts2 = list[int]
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: `list[int]` is already specialized"
|
||||
DoublySpecialized = ListOfInts2[int]
|
||||
|
||||
def _(doubly_specialized: DoublySpecialized):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'list[int]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'list[int]'>` is already specialized"
|
||||
List = list[int][int]
|
||||
|
||||
def _(doubly_specialized: List):
|
||||
@@ -683,7 +683,7 @@ def _(doubly_specialized: List):
|
||||
|
||||
Tuple = tuple[int, str]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'tuple[int, str]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'tuple[int, str]'>` is already specialized"
|
||||
def _(doubly_specialized: Tuple[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
@@ -694,7 +694,7 @@ class LegacyProto(Protocol[T]):
|
||||
|
||||
LegacyProtoInt = LegacyProto[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'LegacyProto[int]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'LegacyProto[int]'>` is already specialized"
|
||||
def _(doubly_specialized: LegacyProtoInt[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
@@ -703,7 +703,7 @@ class Proto[T](Protocol):
|
||||
|
||||
ProtoInt = Proto[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'Proto[int]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'Proto[int]'>` is already specialized"
|
||||
def _(doubly_specialized: ProtoInt[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
@@ -711,10 +711,10 @@ def _(doubly_specialized: ProtoInt[int]):
|
||||
class LegacyDict(TypedDict[T]):
|
||||
x: T
|
||||
|
||||
# TODO: should be a `non-subscriptable` error
|
||||
# TODO: should be a `not-subscriptable` error
|
||||
LegacyDictInt = LegacyDict[int]
|
||||
|
||||
# TODO: should be a `non-subscriptable` error
|
||||
# TODO: should be a `not-subscriptable` error
|
||||
def _(doubly_specialized: LegacyDictInt[int]):
|
||||
# TODO: should be `Unknown`
|
||||
reveal_type(doubly_specialized) # revealed: @Todo(Inference of subscript on special form)
|
||||
@@ -724,20 +724,20 @@ class Dict[T](TypedDict):
|
||||
|
||||
DictInt = Dict[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<class 'Dict[int]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<class 'Dict[int]'>` is already specialized"
|
||||
def _(doubly_specialized: DictInt[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
Union = list[str] | list[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type: `<types.UnionType special-form 'list[str] | list[int]'>` is already specialized"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type: `<types.UnionType special-form 'list[str] | list[int]'>` is already specialized"
|
||||
def _(doubly_specialized: Union[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
|
||||
type MyListAlias[T] = list[T]
|
||||
MyListOfInts = MyListAlias[int]
|
||||
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type alias: Double specialization is not allowed"
|
||||
def _(doubly_specialized: MyListOfInts[int]):
|
||||
reveal_type(doubly_specialized) # revealed: Unknown
|
||||
```
|
||||
@@ -775,7 +775,7 @@ def this_does_not_work() -> TypeOf[IntOrStr]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def _(
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type"
|
||||
specialized: this_does_not_work()[int],
|
||||
):
|
||||
reveal_type(specialized) # revealed: Unknown
|
||||
@@ -784,7 +784,7 @@ def _(
|
||||
Similarly, if you try to specialize a union type without a binding context, we emit an error:
|
||||
|
||||
```py
|
||||
# error: [non-subscriptable] "Cannot subscript non-generic type"
|
||||
# error: [not-subscriptable] "Cannot subscript non-generic type"
|
||||
x: (list[T] | set[T])[int]
|
||||
|
||||
def _():
|
||||
|
||||
@@ -247,11 +247,11 @@ does["not"]["exist"] = 0
|
||||
# error: [unresolved-reference]
|
||||
reveal_type(does["not"]["exist"]) # revealed: Unknown
|
||||
|
||||
non_subscriptable = 1
|
||||
not_subscriptable = 1
|
||||
# error: [invalid-assignment]
|
||||
non_subscriptable[0] = 0
|
||||
# error: [non-subscriptable]
|
||||
reveal_type(non_subscriptable[0]) # revealed: Unknown
|
||||
not_subscriptable[0] = 0
|
||||
# error: [not-subscriptable]
|
||||
reveal_type(not_subscriptable[0]) # revealed: Unknown
|
||||
```
|
||||
|
||||
### No narrowing for custom classes with arbitrary `__getitem__` / `__setitem__`
|
||||
|
||||
@@ -14,20 +14,20 @@ mdtest path: crates/ty_python_semantic/resources/mdtest/subscript/instance.md
|
||||
```
|
||||
1 | class NotSubscriptable: ...
|
||||
2 |
|
||||
3 | a = NotSubscriptable()[0] # error: [non-subscriptable]
|
||||
3 | a = NotSubscriptable()[0] # error: [not-subscriptable]
|
||||
```
|
||||
|
||||
# Diagnostics
|
||||
|
||||
```
|
||||
error[non-subscriptable]: Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method
|
||||
error[not-subscriptable]: Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method
|
||||
--> src/mdtest_snippet.py:3:5
|
||||
|
|
||||
1 | class NotSubscriptable: ...
|
||||
2 |
|
||||
3 | a = NotSubscriptable()[0] # error: [non-subscriptable]
|
||||
3 | a = NotSubscriptable()[0] # error: [not-subscriptable]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
info: rule `non-subscriptable` is enabled by default
|
||||
info: rule `not-subscriptable` is enabled by default
|
||||
|
||||
```
|
||||
|
||||
@@ -69,7 +69,7 @@ def _(flag: bool):
|
||||
|
||||
else:
|
||||
class Spam: ...
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `<class 'Spam'>` with no `__class_getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `<class 'Spam'>` with no `__class_getitem__` method"
|
||||
# revealed: str | Unknown
|
||||
reveal_type(Spam[42])
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
```py
|
||||
class NotSubscriptable: ...
|
||||
|
||||
a = NotSubscriptable()[0] # error: [non-subscriptable]
|
||||
a = NotSubscriptable()[0] # error: [not-subscriptable]
|
||||
```
|
||||
|
||||
## `__getitem__` not callable
|
||||
|
||||
@@ -416,7 +416,7 @@ def test2(val: tuple[str, None] | list[int | float]):
|
||||
|
||||
```py
|
||||
def test3(val: tuple[str] | tuple[int] | int):
|
||||
# error: [non-subscriptable] "Cannot subscript object of type `int` with no `__getitem__` method"
|
||||
# error: [not-subscriptable] "Cannot subscript object of type `int` with no `__getitem__` method"
|
||||
reveal_type(val[0]) # revealed: str | int | Unknown
|
||||
```
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ pub(crate) fn register_lints(registry: &mut LintRegistryBuilder) {
|
||||
registry.register_lint(&INVALID_TYPE_VARIABLE_CONSTRAINTS);
|
||||
registry.register_lint(&MISSING_ARGUMENT);
|
||||
registry.register_lint(&NO_MATCHING_OVERLOAD);
|
||||
registry.register_lint(&NON_SUBSCRIPTABLE);
|
||||
registry.register_lint(&NOT_SUBSCRIPTABLE);
|
||||
registry.register_lint(&NOT_ITERABLE);
|
||||
registry.register_lint(&UNSUPPORTED_BOOL_CONVERSION);
|
||||
registry.register_lint(&PARAMETER_ALREADY_ASSIGNED);
|
||||
@@ -1461,7 +1461,7 @@ declare_lint! {
|
||||
/// ```python
|
||||
/// 4[1] # TypeError: 'int' object is not subscriptable
|
||||
/// ```
|
||||
pub(crate) static NON_SUBSCRIPTABLE = {
|
||||
pub(crate) static NOT_SUBSCRIPTABLE = {
|
||||
summary: "detects subscripting objects that do not support subscripting",
|
||||
status: LintStatus::stable("0.0.1-alpha.1"),
|
||||
default_level: Level::Error,
|
||||
@@ -2402,24 +2402,24 @@ pub(super) fn report_index_out_of_bounds(
|
||||
}
|
||||
|
||||
/// Emit a diagnostic declaring that a type does not support subscripting.
|
||||
pub(super) fn report_non_subscriptable(
|
||||
pub(super) fn report_not_subscriptable(
|
||||
context: &InferContext,
|
||||
node: &ast::ExprSubscript,
|
||||
non_subscriptable_ty: Type,
|
||||
not_subscriptable_ty: Type,
|
||||
method: &str,
|
||||
) {
|
||||
let Some(builder) = context.report_lint(&NON_SUBSCRIPTABLE, node) else {
|
||||
let Some(builder) = context.report_lint(&NOT_SUBSCRIPTABLE, node) else {
|
||||
return;
|
||||
};
|
||||
if method == "__delitem__" {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Cannot delete subscript on object of type `{}` with no `{method}` method",
|
||||
non_subscriptable_ty.display(context.db())
|
||||
not_subscriptable_ty.display(context.db())
|
||||
));
|
||||
} else {
|
||||
builder.into_diagnostic(format_args!(
|
||||
"Cannot subscript object of type `{}` with no `{method}` method",
|
||||
non_subscriptable_ty.display(context.db())
|
||||
not_subscriptable_ty.display(context.db())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ use crate::types::diagnostic::{
|
||||
INVALID_LEGACY_TYPE_VARIABLE, INVALID_METACLASS, INVALID_NAMED_TUPLE, INVALID_NEWTYPE,
|
||||
INVALID_OVERLOAD, INVALID_PARAMETER_DEFAULT, INVALID_PARAMSPEC, INVALID_PROTOCOL,
|
||||
INVALID_TYPE_ARGUMENTS, INVALID_TYPE_FORM, INVALID_TYPE_GUARD_CALL,
|
||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, NON_SUBSCRIPTABLE,
|
||||
INVALID_TYPE_VARIABLE_CONSTRAINTS, IncompatibleBases, NOT_SUBSCRIPTABLE,
|
||||
POSSIBLY_MISSING_ATTRIBUTE, POSSIBLY_MISSING_IMPLICIT_CALL, POSSIBLY_MISSING_IMPORT,
|
||||
SUBCLASS_OF_FINAL_CLASS, TypedDictDeleteErrorKind, UNDEFINED_REVEAL, UNRESOLVED_ATTRIBUTE,
|
||||
UNRESOLVED_GLOBAL, UNRESOLVED_IMPORT, UNRESOLVED_REFERENCE, UNSUPPORTED_OPERATOR,
|
||||
@@ -80,7 +80,7 @@ use crate::types::diagnostic::{
|
||||
report_invalid_or_unsupported_base, report_invalid_return_type,
|
||||
report_invalid_type_checking_constant, report_invalid_type_param_order,
|
||||
report_named_tuple_field_with_leading_underscore,
|
||||
report_namedtuple_field_without_default_after_field_with_default, report_non_subscriptable,
|
||||
report_namedtuple_field_without_default_after_field_with_default, report_not_subscriptable,
|
||||
report_possibly_missing_attribute, report_possibly_unresolved_reference,
|
||||
report_rebound_typevar, report_slice_step_size_zero, report_unsupported_augmented_assignment,
|
||||
report_unsupported_binary_operation, report_unsupported_comparison,
|
||||
@@ -4372,7 +4372,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
}
|
||||
}
|
||||
CallDunderError::MethodNotAvailable => {
|
||||
report_non_subscriptable(
|
||||
report_not_subscriptable(
|
||||
&self.context,
|
||||
target,
|
||||
object_ty,
|
||||
@@ -12191,7 +12191,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
// Type parameter list cannot be empty, so if we reach here, `value_ty` is not a generic type.
|
||||
if let Some(builder) = self
|
||||
.context
|
||||
.report_lint(&NON_SUBSCRIPTABLE, &*subscript.value)
|
||||
.report_lint(&NOT_SUBSCRIPTABLE, &*subscript.value)
|
||||
{
|
||||
let mut diagnostic =
|
||||
builder.into_diagnostic("Cannot subscript non-generic type");
|
||||
@@ -12449,7 +12449,7 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
_,
|
||||
) if alias.generic_context(db).is_none() => {
|
||||
debug_assert!(alias.specialization(db).is_none());
|
||||
if let Some(builder) = self.context.report_lint(&NON_SUBSCRIPTABLE, subscript) {
|
||||
if let Some(builder) = self.context.report_lint(&NOT_SUBSCRIPTABLE, subscript) {
|
||||
let value_type = alias.raw_value_type(db);
|
||||
let mut diagnostic =
|
||||
builder.into_diagnostic("Cannot subscript non-generic type alias");
|
||||
@@ -12658,11 +12658,11 @@ impl<'db, 'ast> TypeInferenceBuilder<'db, 'ast> {
|
||||
.as_class_literal()
|
||||
.is_some_and(|class| class.iter_mro(db, None).contains(&ClassBase::Generic))
|
||||
{
|
||||
report_non_subscriptable(context, subscript, value_ty, "__class_getitem__");
|
||||
report_not_subscriptable(context, subscript, value_ty, "__class_getitem__");
|
||||
}
|
||||
} else {
|
||||
if expr_context != ExprContext::Store {
|
||||
report_non_subscriptable(context, subscript, value_ty, "__getitem__");
|
||||
report_not_subscriptable(context, subscript, value_ty, "__getitem__");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use super::{DeferredExpressionState, TypeInferenceBuilder};
|
||||
use crate::FxOrderSet;
|
||||
use crate::semantic_index::semantic_index;
|
||||
use crate::types::diagnostic::{
|
||||
self, INVALID_TYPE_FORM, NON_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form,
|
||||
self, INVALID_TYPE_FORM, NOT_SUBSCRIPTABLE, report_invalid_argument_number_to_special_form,
|
||||
report_invalid_arguments_to_callable,
|
||||
};
|
||||
use crate::types::generics::bind_typevar;
|
||||
@@ -921,7 +921,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
KnownInstanceType::TypeAliasType(type_alias @ TypeAliasType::PEP695(_)) => {
|
||||
if type_alias.specialization(self.db()).is_some() {
|
||||
if let Some(builder) =
|
||||
self.context.report_lint(&NON_SUBSCRIPTABLE, subscript)
|
||||
self.context.report_lint(&NOT_SUBSCRIPTABLE, subscript)
|
||||
{
|
||||
let mut diagnostic =
|
||||
builder.into_diagnostic("Cannot subscript non-generic type alias");
|
||||
@@ -951,7 +951,7 @@ impl<'db> TypeInferenceBuilder<'db, '_> {
|
||||
self.infer_type_expression(slice);
|
||||
|
||||
if let Some(builder) =
|
||||
self.context.report_lint(&NON_SUBSCRIPTABLE, subscript)
|
||||
self.context.report_lint(&NOT_SUBSCRIPTABLE, subscript)
|
||||
{
|
||||
let value_type = type_alias.raw_value_type(self.db());
|
||||
let mut diagnostic = builder
|
||||
|
||||
12
ty.schema.json
generated
12
ty.schema.json
generated
@@ -886,9 +886,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"non-subscriptable": {
|
||||
"title": "detects subscripting objects that do not support subscripting",
|
||||
"description": "## What it does\nChecks for subscripting objects that do not support subscripting.\n\n## Why is this bad?\nSubscripting an object that does not support it will raise a `TypeError` at runtime.\n\n## Examples\n```python\n4[1] # TypeError: 'int' object is not subscriptable\n```",
|
||||
"not-iterable": {
|
||||
"title": "detects iteration over an object that is not iterable",
|
||||
"description": "## What it does\nChecks for objects that are not iterable but are used in a context that requires them to be.\n\n## Why is this bad?\nIterating over an object that is not iterable will raise a `TypeError` at runtime.\n\n## Examples\n\n```python\nfor i in 34: # TypeError: 'int' object is not iterable\n pass\n```",
|
||||
"default": "error",
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -896,9 +896,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"not-iterable": {
|
||||
"title": "detects iteration over an object that is not iterable",
|
||||
"description": "## What it does\nChecks for objects that are not iterable but are used in a context that requires them to be.\n\n## Why is this bad?\nIterating over an object that is not iterable will raise a `TypeError` at runtime.\n\n## Examples\n\n```python\nfor i in 34: # TypeError: 'int' object is not iterable\n pass\n```",
|
||||
"not-subscriptable": {
|
||||
"title": "detects subscripting objects that do not support subscripting",
|
||||
"description": "## What it does\nChecks for subscripting objects that do not support subscripting.\n\n## Why is this bad?\nSubscripting an object that does not support it will raise a `TypeError` at runtime.\n\n## Examples\n```python\n4[1] # TypeError: 'int' object is not subscriptable\n```",
|
||||
"default": "error",
|
||||
"oneOf": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user