mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
[ty] Check assignments to implicit global symbols are assignable to the types declared on types.ModuleType
(#18077)
This commit is contained in:
parent
301d9985d8
commit
65e48cb439
3 changed files with 137 additions and 19 deletions
|
@ -40,6 +40,39 @@ reveal_type(__dict__)
|
|||
reveal_type(__init__)
|
||||
```
|
||||
|
||||
## `ModuleType` globals combined with explicit assignments and declarations
|
||||
|
||||
A `ModuleType` attribute can be overridden in the global scope with a different type, but it must be
|
||||
a type assignable to the declaration on `ModuleType` unless it is accompanied by an explicit
|
||||
redeclaration:
|
||||
|
||||
`module.py`:
|
||||
|
||||
```py
|
||||
__file__ = None
|
||||
__path__: list[str] = []
|
||||
__doc__: int # error: [invalid-declaration] "Cannot declare type `int` for inferred type `str | None`"
|
||||
# error: [invalid-declaration] "Cannot shadow implicit global attribute `__package__` with declaration of type `int`"
|
||||
__package__: int = 42
|
||||
__spec__ = 42 # error: [invalid-assignment] "Object of type `Literal[42]` is not assignable to `ModuleSpec | None`"
|
||||
```
|
||||
|
||||
`main.py`:
|
||||
|
||||
```py
|
||||
import module
|
||||
|
||||
reveal_type(module.__file__) # revealed: Unknown | None
|
||||
reveal_type(module.__path__) # revealed: list[str]
|
||||
reveal_type(module.__doc__) # revealed: Unknown
|
||||
reveal_type(module.__spec__) # revealed: Unknown | ModuleSpec | None
|
||||
|
||||
def nested_scope():
|
||||
global __loader__
|
||||
reveal_type(__loader__) # revealed: LoaderProtocol | None
|
||||
__loader__ = 56 # error: [invalid-assignment] "Object of type `Literal[56]` is not assignable to `LoaderProtocol | None`"
|
||||
```
|
||||
|
||||
## Accessed as attributes
|
||||
|
||||
`ModuleType` attributes can also be accessed as attributes on module-literal types. The special
|
||||
|
@ -105,16 +138,16 @@ defined as a global, however, a name lookup should union the `ModuleType` type w
|
|||
conditionally defined type:
|
||||
|
||||
```py
|
||||
__file__ = 42
|
||||
__file__ = "foo"
|
||||
|
||||
def returns_bool() -> bool:
|
||||
return True
|
||||
|
||||
if returns_bool():
|
||||
__name__ = 1
|
||||
__name__ = 1 # error: [invalid-assignment] "Object of type `Literal[1]` is not assignable to `str`"
|
||||
|
||||
reveal_type(__file__) # revealed: Literal[42]
|
||||
reveal_type(__name__) # revealed: Literal[1] | str
|
||||
reveal_type(__file__) # revealed: Literal["foo"]
|
||||
reveal_type(__name__) # revealed: str
|
||||
```
|
||||
|
||||
## Conditionally global or `ModuleType` attribute, with annotation
|
||||
|
@ -122,12 +155,14 @@ reveal_type(__name__) # revealed: Literal[1] | str
|
|||
The same is true if the name is annotated:
|
||||
|
||||
```py
|
||||
# error: [invalid-declaration] "Cannot shadow implicit global attribute `__file__` with declaration of type `int`"
|
||||
__file__: int = 42
|
||||
|
||||
def returns_bool() -> bool:
|
||||
return True
|
||||
|
||||
if returns_bool():
|
||||
# error: [invalid-declaration] "Cannot shadow implicit global attribute `__name__` with declaration of type `int`"
|
||||
__name__: int = 1
|
||||
|
||||
reveal_type(__file__) # revealed: Literal[42]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue