hauntsaninja / no_implicit_optional

A codemod to make your implicit optional type hints PEP 484 compliant.
MIT License
79 stars 8 forks source link

should it rewrite `(x: Any = None)` ? #14

Closed asottile-sentry closed 1 year ago

asottile-sentry commented 1 year ago

Optional[Any] decays to Any anyway if I recall correctly

hauntsaninja commented 1 year ago

Good question, Optional[Any] is not equivalent to Any. It forces users to handle the None case. https://mypy-play.net/?mypy=latest&python=3.11&gist=289c03ec7772221a1bcbc3e3db89caeb

The playground doesn't support passing --implicit-optional, but if you try it out, you'll see that the transformation preserves mypy semantics if you were actually previously using --implicit-optional. The output in the below two cases is the same (beware of the new Github scrolling behaviour):

λ cat before.py 
from typing import Any, Optional

def f(x: Any = None):
    reveal_type(x)
    return x.split()

λ mypy --implicit-optional before.py
before.py:4: note: Revealed type is "Union[Any, None]"
before.py:5: error: Item "None" of "Optional[Any]" has no attribute "split"  [union-attr]
Found 1 error in 1 file (checked 1 source file)

λ cat after.py
from typing import Any, Optional

def f(x: Optional[Any] = None):
    reveal_type(x)
    return x.split()

λ mypy --no-implicit-optional after.py 
after.py:4: note: Revealed type is "Union[Any, None]"
after.py:5: error: Item "None" of "Optional[Any]" has no attribute "split"  [union-attr]
Found 1 error in 1 file (checked 1 source file)