Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/source/error_code_list2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -676,3 +676,26 @@ Example:
print("red")
case _:
print("other")

.. _code-untyped-decorator:

Error if an untyped decorator makes a typed function effectively untyped [untyped-decorator]
--------------------------------------------------------------------------------------------

If enabled with :option:`--disallow-untyped-decorators <mypy --disallow-untyped-decorators>`
mypy generates an error if a typed function is wrapped by an untyped decorator
(as this would effectively remove the benefits of typing the function).

Example:

.. code-block:: python

def printing_decorator(func):
def wrapper(*args, **kwds):
print("Calling", func)
return func(*args, **kwds)
return wrapper
# A decorated function.
@printing_decorator # E: Untyped decorator makes function "add_forty_two" untyped [untyped-decorator]
def add_forty_two(value: int) -> int:
return value + 42
7 changes: 7 additions & 0 deletions mypy/errorcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,13 @@ def __hash__(self) -> int:
sub_code_of=MISC,
)

UNTYPED_DECORATOR: Final = ErrorCode(
"untyped-decorator",
"Error if an untyped decorator makes a typed function untyped",
"General",
sub_code_of=MISC,
)

NARROWED_TYPE_NOT_SUBTYPE: Final = ErrorCode(
"narrowed-type-not-subtype",
"Warn if a TypeIs function's narrowed type is not a subtype of the original type",
Expand Down
6 changes: 5 additions & 1 deletion mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2008,7 +2008,11 @@ def untyped_decorated_function(self, typ: Type, context: Context) -> None:
)

def typed_function_untyped_decorator(self, func_name: str, context: Context) -> None:
self.fail(f'Untyped decorator makes function "{func_name}" untyped', context)
self.fail(
f'Untyped decorator makes function "{func_name}" untyped',
context,
code=codes.UNTYPED_DECORATOR,
)

def bad_proto_variance(
self, actual: int, tvar_name: str, expected: int, context: Context
Expand Down
13 changes: 13 additions & 0 deletions test-data/unit/check-errorcodes.test
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,19 @@ def f() -> None:
def g():
pass

[case testErrorCodeUntypedDecorator]
# flags: --disallow-untyped-decorators --warn-unused-ignores
def d(f): return f

@d # E: Untyped decorator makes function "x" untyped [untyped-decorator]
def x() -> int: return 1
@d # type: ignore
def y() -> int: return 2
@d # type: ignore[untyped-decorator]
def best() -> int: return 3
@d # type: ignore[misc] # E: Unused "type: ignore" comment, use narrower [untyped-decorator] instead of [misc] code [unused-ignore]
def z() -> int: return 4

[case testErrorCodeIndexing]
from typing import Dict
x: Dict[int, int]
Expand Down
Loading