ruff UP043
labelled unknown
Analysis Nemotron 3 Super
Flags explicit default type arguments (`None`) for `Generator` and `AsyncGenerator` when they match the defaults introduced in Python 3.13.
Fix: Removes trailing type arguments that are exactly `None` for the second and/or third parameters of `Generator`, and the second parameter of `AsyncGenerator`, when they match the default values introduced in Python 3.13.
8 hazards
- Rewriting `Generator[T, None, None]` to `Generator[T]` changes meaning if the code targets Python <3.13 where defaults are not applied.
- If the annotation contains an inline comment (e.g., `Generator[int, None, None # comment]`), the fix may drop the comment, altering documentation.
- In a string annotation like `"Generator[int, None, None]"`, the fix does not apply, but if incorrectly applied, it would corrupt the string.
- If `None` is imported under an alias (e.g., `from types import NoneType as None`), the fixer might not recognize it as the default, leading to unsafe removal.
- When used in a union like `Union[Generator[int, None, None], str]`, removing the `None`s could change the union's structure if relied upon for overload resolution.
- In a forward reference evaluated later (e.g., in `TYPE_CHECKING` blocks), the rewritten form may resolve differently if the target scope lacks the updated built-in generics.
- If the code uses a custom subclass of `Generator` that overrides `__class_getitem__`, the fix assumes standard library semantics and may be incorrect.
- When the annotation is part of a larger expression (e.g., in a `Callable[[], Generator[int, None, None]]`), the fix only applies to the nested annotation and must not disturb the outer structure.
Programs
| id | result | title | hazard |
|---|---|---|---|
| r1-p001 | silent prediction off | Exception handling with Generator return annotation | Exceptions raised inside the rewritten code, finally/else clauses, exception chaining |
| r1-p002 | invalid | Dict ordering and hashability with Generator annotation | Dict ordering, duplicate keys, __hash__/__eq__ overrides, sets |
| r1-p003 | silent prediction off | Forward reference in TYPE_CHECKING block | In a forward reference evaluated later (e.g., in `TYPE_CHECKING` blocks), the rewritten form may resolve differently if the target scope lacks the updated built-in generics. |
| r1-p004 | silent prediction off | Keyword-only args with Generator annotation | keyword-only, positional-only, *args/**kwargs forwarding, defaults evaluated once |
| r1-p005 | invalid | None imported as alias affecting recognition | If `None` is imported under an alias (e.g., `from types import NoneType as None`), the fixer might not recognize it as the default, leading to unsafe removal. |
| r1-p006 | silent prediction off | Union type relying on explicit None for overload resolution | When used in a union like `Union[Generator[int, None, None], str]`, removing the `None`s could change the union's structure if relied upon for overload resolution. |
| r1-p007 | silent prediction off | Runtime evaluation of Generator annotation | type annotations evaluated at runtime, typing-only imports |
| r1-p008 | silent prediction off | Truthiness and identity checks with Generator in bool context | truthiness of custom __bool__/__len__, None vs falsy, 'is' vs '==' |
Sources
r1-p001 · Exception handling with Generator return annotation
1def f() -> Generator[int, None, None]:
2 try:
3 raise ValueError('test')
4 except ValueError as e:
5 yield 1
6 else:
7 yield 2
8 finally:
9 yield 3
10gen = f()
11print(list(gen))
[1, 3]
r1-p002 · Dict ordering and hashability with Generator annotation (generated program is not deterministic)
1class Key:
2 def __init__(self, v): self.v = v
3 def __hash__(self): return hash(self.v)
4 def __eq__(self, other): return isinstance(other, Key) and self.v == other.v
5def g() -> Generator[tuple[Key, int], None, None]:
6 yield (Key(1), 10)
7 yield (Key(2), 20)
8d = dict(g())
9print(list(d.items()))
r1-p003 · Forward reference in TYPE_CHECKING block
1from typing import TYPE_CHECKING, Generator
2if TYPE_CHECKING:
3 x: Generator[int, None, None]
4else:
5 x = (i for i in range(3))
6print(type(x).__name__)
generator
r1-p004 · Keyword-only args with Generator annotation
1def f(*, g: Generator[int, None, None] = (i for i in [1])):
2 return sum(g)
3print(f())
1
r1-p005 · None imported as alias affecting recognition (generated program does not parse: Traceback (most recent call last):)
1from types import NoneType as None
2def f() -> Generator[int, None, None]:
3 yield 1
4gen = f()
5print(next(gen))
r1-p006 · Union type relying on explicit None for overload resolution
1from typing import Union, Generator
2def process(x: Union[Generator[int, None, None], str]):
3 if isinstance(x, str):
4 return x.upper()
5 return list(x)
6print(process((i for i in [2])))
7print(process('hello'))
[2] HELLO
r1-p007 · Runtime evaluation of Generator annotation
1import typing
2t = typing.get_type_hints(lambda: None).__annotations__
3def f() -> Generator[int, None, None]: pass
4t2 = typing.get_type_hints(f).__annotations__['return']
5print(str(t2))
r1-p008 · Truthiness and identity checks with Generator in bool context
1class MyGen:
2 def __bool__(self): return False
3 def __len__(self): return 0
4def f() -> Generator[MyGen, None, None]:
5 yield MyGen()
6g = f()
7print(bool(g))
8print(g is None)
True False