From 7dc6a22a48f8a30e6a567e2f4b5d564649ac9afe Mon Sep 17 00:00:00 2001 From: Denise Kaur Date: Sun, 30 Apr 2023 16:21:31 -0400 Subject: [PATCH 1/5] Created new error code, added test and documentation --- docs/source/error_code_list2.rst | 15 +++++++++++++++ mypy/checker.py | 12 ++++++++++-- mypy/errorcodes.py | 3 +++ mypy/message_registry.py | 6 ++++++ test-data/unit/check-errorcodes.test | 9 +++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index f160515f0a9e..cc84277e83aa 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -62,6 +62,21 @@ Example: def __init__(self) -> None: self.value = 0 +Check that every function has a return annotation [no-incomplete-def] +------------------------------------------------------------ + +If you use :option:`--disallow-incomplete-defs `, mypy requires that all functions +fully annotated + +Example: + +.. code-block:: python + + # mypy: disallow-incomplete-defs + + def example(x: int): # Error: Function is missing a return type annotation [no-incomplete-def] + pass + Check that cast is not redundant [redundant-cast] ------------------------------------------------- diff --git a/mypy/checker.py b/mypy/checker.py index 09dc0a726b99..9c118c09f40f 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1401,7 +1401,9 @@ def is_unannotated_any(t: Type) -> bool: self.fail(message_registry.FUNCTION_TYPE_EXPECTED, fdef) elif isinstance(fdef.type, CallableType): ret_type = get_proper_type(fdef.type.ret_type) - if is_unannotated_any(ret_type): + if is_unannotated_any(ret_type) and check_incomplete_defs: + self.fail(message_registry.RETURN_TYPE_EXPECTED_INCOMPLETE_DEF, fdef) + elif is_unannotated_any(ret_type): self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) elif fdef.is_generator: if is_unannotated_any( @@ -1411,9 +1413,15 @@ def is_unannotated_any(t: Type) -> bool: elif fdef.is_coroutine and isinstance(ret_type, Instance): if is_unannotated_any(self.get_coroutine_return_type(ret_type)): self.fail(message_registry.RETURN_TYPE_EXPECTED, fdef) - if any(is_unannotated_any(t) for t in fdef.type.arg_types): + if ( + any(is_unannotated_any(t) for t in fdef.type.arg_types) + and check_incomplete_defs + ): + self.fail(message_registry.ARGUMENT_TYPE_EXPECTED_INCOMPLETE_DEF, fdef) + elif any(is_unannotated_any(t) for t in fdef.type.arg_types): self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef) + def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None: self_type = fill_typevars_with_any(fdef.info) bound_type = bind_self(typ, self_type, is_classmethod=True) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index d274bb6dd5f0..b29582e7821e 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -221,6 +221,9 @@ def __str__(self) -> str: USED_BEFORE_DEF: Final[ErrorCode] = ErrorCode( "used-before-def", "Warn about variables that are used before they are defined", "General" ) +NO_INCOMPLETE_DEF: Final[ErrorCode] = ErrorCode( + "no-incomplete-def", "Function is missing a return type annotation", "General" +) # Syntax errors are often blocking. diff --git a/mypy/message_registry.py b/mypy/message_registry.py index b32edc06571a..d3e282fa3825 100644 --- a/mypy/message_registry.py +++ b/mypy/message_registry.py @@ -119,9 +119,15 @@ def with_additional_msg(self, info: str) -> ErrorMessage: RETURN_TYPE_EXPECTED: Final = ErrorMessage( "Function is missing a return type annotation", codes.NO_UNTYPED_DEF ) +RETURN_TYPE_EXPECTED_INCOMPLETE_DEF: Final = ErrorMessage( + "Function is missing a return type annotation", codes.NO_INCOMPLETE_DEF +) ARGUMENT_TYPE_EXPECTED: Final = ErrorMessage( "Function is missing a type annotation for one or more arguments", codes.NO_UNTYPED_DEF ) +ARGUMENT_TYPE_EXPECTED_INCOMPLETE_DEF: Final = ErrorMessage( + "Function is missing a type annotation for one or more arguments", codes.NO_INCOMPLETE_DEF +) KEYWORD_ARGUMENT_REQUIRES_STR_KEY_TYPE: Final = ErrorMessage( 'Keyword argument only valid with "str" key type in call to "dict"' ) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 33c8f7365375..34f22ee2399c 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -379,6 +379,15 @@ def f() -> None: def g(): pass +[case testErrorCodeNoReturnAnnotation] +# flags: --disallow-incomplete-defs + +def f(i: int): # E: Function is missing a return type annotation [no-incomplete-def] + pass + +def g(i) -> None: # E: Function is missing a type annotation for one or more arguments [no-incomplete-def] + pass + [case testErrorCodeIndexing] from typing import Dict x: Dict[int, int] From 6accaa2e23b4e529ad09600e7848ad061a04cd6b Mon Sep 17 00:00:00 2001 From: Denise Kaur Date: Sun, 30 Apr 2023 16:37:55 -0400 Subject: [PATCH 2/5] Changes for consistent coding style --- mypy/checker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 9c118c09f40f..bc4be0411ac6 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -1421,7 +1421,6 @@ def is_unannotated_any(t: Type) -> bool: elif any(is_unannotated_any(t) for t in fdef.type.arg_types): self.fail(message_registry.ARGUMENT_TYPE_EXPECTED, fdef) - def check___new___signature(self, fdef: FuncDef, typ: CallableType) -> None: self_type = fill_typevars_with_any(fdef.info) bound_type = bind_self(typ, self_type, is_classmethod=True) From a9219435c8fa6c5aea8d60ccbc27ff164eb0f5ae Mon Sep 17 00:00:00 2001 From: Denise Kaur Date: Sun, 30 Apr 2023 17:10:35 -0400 Subject: [PATCH 3/5] Fixing error on title underline in documentation --- docs/source/error_code_list2.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/error_code_list2.rst b/docs/source/error_code_list2.rst index cc84277e83aa..673ac62b5058 100644 --- a/docs/source/error_code_list2.rst +++ b/docs/source/error_code_list2.rst @@ -63,10 +63,10 @@ Example: self.value = 0 Check that every function has a return annotation [no-incomplete-def] ------------------------------------------------------------- +--------------------------------------------------------------------- If you use :option:`--disallow-incomplete-defs `, mypy requires that all functions -fully annotated +fully annotated. Example: From c4c86e4dae52e986db9d8a582d9fce5180a50fc6 Mon Sep 17 00:00:00 2001 From: Denise Kaur Date: Wed, 3 May 2023 13:16:14 -0400 Subject: [PATCH 4/5] Fixing conflicts w master --- mypy/errorcodes.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index b29582e7821e..1476a1f0de07 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -221,6 +221,9 @@ def __str__(self) -> str: USED_BEFORE_DEF: Final[ErrorCode] = ErrorCode( "used-before-def", "Warn about variables that are used before they are defined", "General" ) + + + NO_INCOMPLETE_DEF: Final[ErrorCode] = ErrorCode( "no-incomplete-def", "Function is missing a return type annotation", "General" ) From ce3d4aababdbf8a9d4828a2e75edf704e9fdc52f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 17:16:51 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- mypy/errorcodes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy/errorcodes.py b/mypy/errorcodes.py index 1476a1f0de07..a066635341e3 100644 --- a/mypy/errorcodes.py +++ b/mypy/errorcodes.py @@ -223,7 +223,6 @@ def __str__(self) -> str: ) - NO_INCOMPLETE_DEF: Final[ErrorCode] = ErrorCode( "no-incomplete-def", "Function is missing a return type annotation", "General" )