Skip to content

Commit

Permalink
Dedicated error code for explicit any
Browse files Browse the repository at this point in the history
  • Loading branch information
hauntsaninja committed Dec 31, 2024
1 parent 9bf5169 commit c9c39dd
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 46 deletions.
16 changes: 16 additions & 0 deletions docs/source/error_code_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,22 @@ Consider this example:
`PEP 705 <https://peps.python.org/pep-0705>`_ specifies
how ``ReadOnly`` special form works for ``TypedDict`` objects.

.. _code-narrowed-type-not-subtype:

Check that ``TypeIs`` narrows types [narrowed-type-not-subtype]
---------------------------------------------------------------

:pep:`742` requires that when ``TypeIs`` is used, the narrowed
type must be a subtype of the original type::

from typing_extensions import TypeIs

def f(x: int) -> TypeIs[str]: # Error, str is not a subtype of int
...

def g(x: object) -> TypeIs[str]: # OK
...

.. _code-misc:

Miscellaneous checks [misc]
Expand Down
21 changes: 11 additions & 10 deletions docs/source/error_code_list2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -594,18 +594,19 @@ Correct usage:
When this code is enabled, using ``reveal_locals`` is always an error,
because there's no way one can import it.

.. _code-narrowed-type-not-subtype:

Check that ``TypeIs`` narrows types [narrowed-type-not-subtype]
---------------------------------------------------------------
.. _code-explicit-any:

:pep:`742` requires that when ``TypeIs`` is used, the narrowed
type must be a subtype of the original type::
Check that explicit Any type annotations are not allowed [explicit-any]
-----------------------------------------------------------------------

from typing_extensions import TypeIs
If you use :option:`--disallow-any-explicit <mypy --disallow-any-explicit>`, mypy generates an error
if you use an explicit ``Any`` type annotation.

def f(x: int) -> TypeIs[str]: # Error, str is not a subtype of int
...
Example:

def g(x: object) -> TypeIs[str]: # OK
...
.. code-block:: python
# mypy: disallow-any-explicit
from typing import Any
x: Any = 1 # Error: Explicit "Any" type annotation [explicit-any]
6 changes: 6 additions & 0 deletions mypy/errorcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,12 @@ def __hash__(self) -> int:
"General",
)

EXPLICIT_ANY: Final = ErrorCode(
"explicit-any",
"Warn about explicit Any type annotations",
"General",
)

DEPRECATED: Final = ErrorCode(
"deprecated",
"Warn when importing or using deprecated (overloaded) functions, methods or classes",
Expand Down
2 changes: 1 addition & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1821,7 +1821,7 @@ def need_annotation_for_var(
)

def explicit_any(self, ctx: Context) -> None:
self.fail('Explicit "Any" is not allowed', ctx)
self.fail('Explicit "Any" is not allowed', ctx, code=codes.EXPLICIT_ANY)

def unsupported_target_for_star_typeddict(self, typ: Type, ctx: Context) -> None:
self.fail(
Expand Down
66 changes: 33 additions & 33 deletions test-data/unit/check-flags.test
Original file line number Diff line number Diff line change
Expand Up @@ -1829,120 +1829,120 @@ x: A # E:4: Missing type parameters for generic type "A"
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitDefSignature]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes

from typing import Any, List

def f(x: Any) -> None: # E: Explicit "Any" is not allowed
def f(x: Any) -> None: # E: Explicit "Any" is not allowed [explicit-any]
pass

def g() -> Any: # E: Explicit "Any" is not allowed
def g() -> Any: # E: Explicit "Any" is not allowed [explicit-any]
pass

def h() -> List[Any]: # E: Explicit "Any" is not allowed
def h() -> List[Any]: # E: Explicit "Any" is not allowed [explicit-any]
pass
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitVarDeclaration]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any
v: Any = '' # E: Explicit "Any" is not allowed
w = '' # type: Any # E: Explicit "Any" is not allowed
v: Any = '' # E: Explicit "Any" is not allowed [explicit-any]
w = '' # type: Any # E: Explicit "Any" is not allowed [explicit-any]
class X:
y = '' # type: Any # E: Explicit "Any" is not allowed
y = '' # type: Any # E: Explicit "Any" is not allowed [explicit-any]

[case testDisallowAnyExplicitGenericVarDeclaration]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List
v: List[Any] = [] # E: Explicit "Any" is not allowed
v: List[Any] = [] # E: Explicit "Any" is not allowed [explicit-any]
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitInheritance]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List

class C(Any): # E: Explicit "Any" is not allowed
class C(Any): # E: Explicit "Any" is not allowed [explicit-any]
pass

class D(List[Any]): # E: Explicit "Any" is not allowed
class D(List[Any]): # E: Explicit "Any" is not allowed [explicit-any]
pass
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitAlias]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List

X = Any # E: Explicit "Any" is not allowed
Y = List[Any] # E: Explicit "Any" is not allowed
X = Any # E: Explicit "Any" is not allowed [explicit-any]
Y = List[Any] # E: Explicit "Any" is not allowed [explicit-any]

def foo(x: X) -> Y: # no error
x.nonexistent() # no error
return x
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitGenericAlias]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, TypeVar, Tuple

T = TypeVar('T')

TupleAny = Tuple[Any, T] # E: Explicit "Any" is not allowed
TupleAny = Tuple[Any, T] # E: Explicit "Any" is not allowed [explicit-any]

def foo(x: TupleAny[str]) -> None: # no error
pass

def goo(x: TupleAny[Any]) -> None: # E: Explicit "Any" is not allowed
def goo(x: TupleAny[Any]) -> None: # E: Explicit "Any" is not allowed [explicit-any]
pass
[builtins fixtures/tuple.pyi]

[case testDisallowAnyExplicitCast]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List, cast

x = 1
y = cast(Any, x) # E: Explicit "Any" is not allowed
z = cast(List[Any], x) # E: Explicit "Any" is not allowed
y = cast(Any, x) # E: Explicit "Any" is not allowed [explicit-any]
z = cast(List[Any], x) # E: Explicit "Any" is not allowed [explicit-any]
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitNamedTuple]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List, NamedTuple

Point = NamedTuple('Point', [('x', List[Any]), ('y', Any)]) # E: Explicit "Any" is not allowed
Point = NamedTuple('Point', [('x', List[Any]), ('y', Any)]) # E: Explicit "Any" is not allowed [explicit-any]
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitTypeVarConstraint]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List, TypeVar

T = TypeVar('T', Any, List[Any]) # E: Explicit "Any" is not allowed
T = TypeVar('T', Any, List[Any]) # E: Explicit "Any" is not allowed [explicit-any]
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitNewType]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from typing import Any, List, NewType

# this error does not come from `--disallow-any-explicit` flag
Baz = NewType('Baz', Any) # E: Argument 2 to NewType(...) must be subclassable (got "Any")
Bar = NewType('Bar', List[Any]) # E: Explicit "Any" is not allowed
Baz = NewType('Baz', Any) # E: Argument 2 to NewType(...) must be subclassable (got "Any") [valid-newtype]
Bar = NewType('Bar', List[Any]) # E: Explicit "Any" is not allowed [explicit-any]
[builtins fixtures/list.pyi]

[case testDisallowAnyExplicitTypedDictSimple]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from mypy_extensions import TypedDict
from typing import Any

M = TypedDict('M', {'x': str, 'y': Any}) # E: Explicit "Any" is not allowed
M = TypedDict('M', {'x': str, 'y': Any}) # E: Explicit "Any" is not allowed [explicit-any]
M(x='x', y=2) # no error
def f(m: M) -> None: pass # no error
[builtins fixtures/dict.pyi]

[case testDisallowAnyExplicitTypedDictGeneric]
# flags: --disallow-any-explicit
# flags: --disallow-any-explicit --show-error-codes
from mypy_extensions import TypedDict
from typing import Any, List

M = TypedDict('M', {'x': str, 'y': List[Any]}) # E: Explicit "Any" is not allowed
M = TypedDict('M', {'x': str, 'y': List[Any]}) # E: Explicit "Any" is not allowed [explicit-any]
N = TypedDict('N', {'x': str, 'y': List}) # no error
[builtins fixtures/dict.pyi]

Expand Down
3 changes: 1 addition & 2 deletions test-data/unit/fixtures/typing-typeddict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ class Iterator(Iterable[T_co], Protocol):
def __next__(self) -> T_co: pass

class Sequence(Iterable[T_co]):
# misc is for explicit Any.
def __getitem__(self, n: Any) -> T_co: pass # type: ignore[misc]
def __getitem__(self, n: Any) -> T_co: pass # type: ignore[explicit-any]

class Mapping(Iterable[T], Generic[T, T_co], metaclass=ABCMeta):
def keys(self) -> Iterable[T]: pass # Approximate return type
Expand Down

0 comments on commit c9c39dd

Please sign in to comment.