mirror of https://github.com/astral-sh/ruff
[ty] Use `range` instead of custom `IntIterable` (#21138)
## Summary We previously didn't understand `range` and wrote these custom `IntIterable`/`IntIterator` classes for tests. We can now remove them and make the tests shorter in some places.
This commit is contained in:
parent
1ebedf6df5
commit
1b0ee4677e
|
|
@ -300,14 +300,6 @@ reveal_type(c_instance.b) # revealed: Unknown | list[Literal[2, 3]]
|
||||||
#### Attributes defined in for-loop (unpacking)
|
#### Attributes defined in for-loop (unpacking)
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class IntIterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
class IntIterable:
|
|
||||||
def __iter__(self) -> IntIterator:
|
|
||||||
return IntIterator()
|
|
||||||
|
|
||||||
class TupleIterator:
|
class TupleIterator:
|
||||||
def __next__(self) -> tuple[int, str]:
|
def __next__(self) -> tuple[int, str]:
|
||||||
return (1, "a")
|
return (1, "a")
|
||||||
|
|
@ -320,7 +312,7 @@ class NonIterable: ...
|
||||||
|
|
||||||
class C:
|
class C:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
for self.x in IntIterable():
|
for self.x in range(3):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for _, self.y in TupleIterable():
|
for _, self.y in TupleIterable():
|
||||||
|
|
@ -378,14 +370,6 @@ reveal_type(c_instance.y) # revealed: Unknown | int
|
||||||
#### Attributes defined in comprehensions
|
#### Attributes defined in comprehensions
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class IntIterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 1
|
|
||||||
|
|
||||||
class IntIterable:
|
|
||||||
def __iter__(self) -> IntIterator:
|
|
||||||
return IntIterator()
|
|
||||||
|
|
||||||
class TupleIterator:
|
class TupleIterator:
|
||||||
def __next__(self) -> tuple[int, str]:
|
def __next__(self) -> tuple[int, str]:
|
||||||
return (1, "a")
|
return (1, "a")
|
||||||
|
|
@ -398,7 +382,7 @@ class C:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
# TODO: Should not emit this diagnostic
|
# TODO: Should not emit this diagnostic
|
||||||
# error: [unresolved-attribute]
|
# error: [unresolved-attribute]
|
||||||
[... for self.a in IntIterable()]
|
[... for self.a in range(3)]
|
||||||
# TODO: Should not emit this diagnostic
|
# TODO: Should not emit this diagnostic
|
||||||
# error: [unresolved-attribute]
|
# error: [unresolved-attribute]
|
||||||
# error: [unresolved-attribute]
|
# error: [unresolved-attribute]
|
||||||
|
|
@ -406,11 +390,11 @@ class C:
|
||||||
# TODO: Should not emit this diagnostic
|
# TODO: Should not emit this diagnostic
|
||||||
# error: [unresolved-attribute]
|
# error: [unresolved-attribute]
|
||||||
# error: [unresolved-attribute]
|
# error: [unresolved-attribute]
|
||||||
[... for self.d in IntIterable() for self.e in IntIterable()]
|
[... for self.d in range(3) for self.e in range(3)]
|
||||||
# TODO: Should not emit this diagnostic
|
# TODO: Should not emit this diagnostic
|
||||||
# error: [unresolved-attribute]
|
# error: [unresolved-attribute]
|
||||||
[[... for self.f in IntIterable()] for _ in IntIterable()]
|
[[... for self.f in range(3)] for _ in range(3)]
|
||||||
[[... for self.g in IntIterable()] for self in [D()]]
|
[[... for self.g in range(3)] for self in [D()]]
|
||||||
|
|
||||||
class D:
|
class D:
|
||||||
g: int
|
g: int
|
||||||
|
|
@ -2058,16 +2042,8 @@ mod.global_symbol = 1
|
||||||
# TODO: this should be an error, but we do not understand list unpackings yet.
|
# TODO: this should be an error, but we do not understand list unpackings yet.
|
||||||
[_, mod.global_symbol] = [1, 2]
|
[_, mod.global_symbol] = [1, 2]
|
||||||
|
|
||||||
class IntIterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 42
|
|
||||||
|
|
||||||
class IntIterable:
|
|
||||||
def __iter__(self) -> IntIterator:
|
|
||||||
return IntIterator()
|
|
||||||
|
|
||||||
# error: [invalid-assignment] "Object of type `int` is not assignable to attribute `global_symbol` of type `str`"
|
# error: [invalid-assignment] "Object of type `int` is not assignable to attribute `global_symbol` of type `str`"
|
||||||
for mod.global_symbol in IntIterable():
|
for mod.global_symbol in range(3):
|
||||||
pass
|
pass
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,71 +3,47 @@
|
||||||
## Basic comprehensions
|
## Basic comprehensions
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class IntIterator:
|
# revealed: int
|
||||||
def __next__(self) -> int:
|
[reveal_type(x) for x in range(3)]
|
||||||
return 42
|
|
||||||
|
|
||||||
class IntIterable:
|
class Row:
|
||||||
def __iter__(self) -> IntIterator:
|
def __next__(self) -> range:
|
||||||
return IntIterator()
|
return range(3)
|
||||||
|
|
||||||
|
class Table:
|
||||||
|
def __iter__(self) -> Row:
|
||||||
|
return Row()
|
||||||
|
|
||||||
|
# revealed: tuple[int, range]
|
||||||
|
[reveal_type((cell, row)) for row in Table() for cell in row]
|
||||||
|
|
||||||
# revealed: int
|
# revealed: int
|
||||||
[reveal_type(x) for x in IntIterable()]
|
{reveal_type(x): 0 for x in range(3)}
|
||||||
|
|
||||||
class IteratorOfIterables:
|
|
||||||
def __next__(self) -> IntIterable:
|
|
||||||
return IntIterable()
|
|
||||||
|
|
||||||
class IterableOfIterables:
|
|
||||||
def __iter__(self) -> IteratorOfIterables:
|
|
||||||
return IteratorOfIterables()
|
|
||||||
|
|
||||||
# revealed: tuple[int, IntIterable]
|
|
||||||
[reveal_type((x, y)) for y in IterableOfIterables() for x in y]
|
|
||||||
|
|
||||||
# revealed: int
|
# revealed: int
|
||||||
{reveal_type(x): 0 for x in IntIterable()}
|
{0: reveal_type(x) for x in range(3)}
|
||||||
|
|
||||||
# revealed: int
|
|
||||||
{0: reveal_type(x) for x in IntIterable()}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Nested comprehension
|
## Nested comprehension
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class IntIterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 42
|
|
||||||
|
|
||||||
class IntIterable:
|
|
||||||
def __iter__(self) -> IntIterator:
|
|
||||||
return IntIterator()
|
|
||||||
|
|
||||||
# revealed: tuple[int, int]
|
# revealed: tuple[int, int]
|
||||||
[[reveal_type((x, y)) for x in IntIterable()] for y in IntIterable()]
|
[[reveal_type((x, y)) for x in range(3)] for y in range(3)]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Comprehension referencing outer comprehension
|
## Comprehension referencing outer comprehension
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class IntIterator:
|
class Row:
|
||||||
def __next__(self) -> int:
|
def __next__(self) -> range:
|
||||||
return 42
|
return range(3)
|
||||||
|
|
||||||
class IntIterable:
|
class Table:
|
||||||
def __iter__(self) -> IntIterator:
|
def __iter__(self) -> Row:
|
||||||
return IntIterator()
|
return Row()
|
||||||
|
|
||||||
class IteratorOfIterables:
|
# revealed: tuple[int, range]
|
||||||
def __next__(self) -> IntIterable:
|
[[reveal_type((cell, row)) for cell in row] for row in Table()]
|
||||||
return IntIterable()
|
|
||||||
|
|
||||||
class IterableOfIterables:
|
|
||||||
def __iter__(self) -> IteratorOfIterables:
|
|
||||||
return IteratorOfIterables()
|
|
||||||
|
|
||||||
# revealed: tuple[int, IntIterable]
|
|
||||||
[[reveal_type((x, y)) for x in y] for y in IterableOfIterables()]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Comprehension with unbound iterable
|
## Comprehension with unbound iterable
|
||||||
|
|
@ -79,17 +55,9 @@ Iterating over an unbound iterable yields `Unknown`:
|
||||||
# revealed: Unknown
|
# revealed: Unknown
|
||||||
[reveal_type(z) for z in x]
|
[reveal_type(z) for z in x]
|
||||||
|
|
||||||
class IntIterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 42
|
|
||||||
|
|
||||||
class IntIterable:
|
|
||||||
def __iter__(self) -> IntIterator:
|
|
||||||
return IntIterator()
|
|
||||||
|
|
||||||
# error: [not-iterable] "Object of type `int` is not iterable"
|
# error: [not-iterable] "Object of type `int` is not iterable"
|
||||||
# revealed: tuple[int, Unknown]
|
# revealed: tuple[int, Unknown]
|
||||||
[reveal_type((x, z)) for x in IntIterable() for z in x]
|
[reveal_type((x, z)) for x in range(3) for z in x]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Starred expressions
|
## Starred expressions
|
||||||
|
|
@ -99,16 +67,8 @@ Starred expressions must be iterable
|
||||||
```py
|
```py
|
||||||
class NotIterable: ...
|
class NotIterable: ...
|
||||||
|
|
||||||
class Iterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 42
|
|
||||||
|
|
||||||
class Iterable:
|
|
||||||
def __iter__(self) -> Iterator:
|
|
||||||
return Iterator()
|
|
||||||
|
|
||||||
# This is fine:
|
# This is fine:
|
||||||
x = [*Iterable()]
|
x = [*range(3)]
|
||||||
|
|
||||||
# error: [not-iterable] "Object of type `NotIterable` is not iterable"
|
# error: [not-iterable] "Object of type `NotIterable` is not iterable"
|
||||||
y = [*NotIterable()]
|
y = [*NotIterable()]
|
||||||
|
|
@ -138,16 +98,8 @@ This tests that we understand that `async` comprehensions do *not* work accordin
|
||||||
iteration protocol
|
iteration protocol
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class Iterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 42
|
|
||||||
|
|
||||||
class Iterable:
|
|
||||||
def __iter__(self) -> Iterator:
|
|
||||||
return Iterator()
|
|
||||||
|
|
||||||
async def _():
|
async def _():
|
||||||
# error: [not-iterable] "Object of type `Iterable` is not async-iterable"
|
# error: [not-iterable] "Object of type `range` is not async-iterable"
|
||||||
# revealed: Unknown
|
# revealed: Unknown
|
||||||
[reveal_type(x) async for x in Iterable()]
|
[reveal_type(x) async for x in range(3)]
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,6 @@
|
||||||
# Comprehensions with invalid syntax
|
# Comprehensions with invalid syntax
|
||||||
|
|
||||||
```py
|
```py
|
||||||
class IntIterator:
|
|
||||||
def __next__(self) -> int:
|
|
||||||
return 42
|
|
||||||
|
|
||||||
class IntIterable:
|
|
||||||
def __iter__(self) -> IntIterator:
|
|
||||||
return IntIterator()
|
|
||||||
|
|
||||||
# Missing 'in' keyword.
|
# Missing 'in' keyword.
|
||||||
|
|
||||||
# It's reasonably clear here what they *meant* to write,
|
# It's reasonably clear here what they *meant* to write,
|
||||||
|
|
@ -16,7 +8,7 @@ class IntIterable:
|
||||||
|
|
||||||
# error: [invalid-syntax] "Expected 'in', found name"
|
# error: [invalid-syntax] "Expected 'in', found name"
|
||||||
# revealed: int
|
# revealed: int
|
||||||
[reveal_type(a) for a IntIterable()]
|
[reveal_type(a) for a range(3)]
|
||||||
|
|
||||||
|
|
||||||
# Missing iteration variable
|
# Missing iteration variable
|
||||||
|
|
@ -25,7 +17,7 @@ class IntIterable:
|
||||||
# error: [invalid-syntax] "Expected 'in', found name"
|
# error: [invalid-syntax] "Expected 'in', found name"
|
||||||
# error: [unresolved-reference]
|
# error: [unresolved-reference]
|
||||||
# revealed: Unknown
|
# revealed: Unknown
|
||||||
[reveal_type(b) for in IntIterable()]
|
[reveal_type(b) for in range(3)]
|
||||||
|
|
||||||
|
|
||||||
# Missing iterable
|
# Missing iterable
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue