Flake8 Type Annotation Checking
typing.overload
decorated functions.Per #92, there exists a discrepancy in behavior between linting of functions with PEP 3107-style annotations and PEP 484-style function-level type comments. Because PEP 484 does not describe a method to provide partial function-level type comments, there is a potential for ambiguity in the context of both class methods and classmethods when aligning type comments to method arguments.
These two class methods, for example, should lint equivalently:
def bar(self, a):
# type: (int) -> int
...
def bar(self, a: int) -> int
...
When this example type comment is parsed by ast
and then matched with the method's arguments, it associates the int
hint to self
rather than a
, so a dummy hint needs to be provided in situations where self
or class
are not hinted in the type comment in order to achieve equivalent linting results to PEP-3107 style annotations.
A dummy ast.Ellipses
constant is injected into the parsed node if the following criteria are met:
typing.overload
decorator handlingPer #94, the typing.overload
was being handled too literally (aka: ignored) by the linter, resulting in emitted linting errors that do not align with the purpose of the decorator.
For example, this code:
import typing
@typing.overload
def foo(a: int) -> int:
...
def foo(a):
...
Would raise linting errors for missing annotations for the arguments & return of the non-decorated foo
definition; this interpretation disagrees with the purpose of the decorator.
Per the documentation:
A series of
@overload
-decorated definitions must be followed by exactly one non-@overload
-decorated definition (for the same function/method)
Errors for missing annotations for non-@overload
-decorated functions are now ignored if they meet this criteria.
NOTE: If importing directly, the typing.overload
decorator will not be recognized if it is imported with an alias (e.g. from typing import overload as please_dont_do_this
). Aliasing of the typing
module is supported (e.g. import typing as t; @t.overload
)
--mypy-init-return
to allow omission of a return type hint for __init__
if at least one argument is annotated.To help provide compatibility with Mypy for maintainers that wish to do so, the --mypy-init-return
flag has been introduced to mimic Mypy's allowance for the omission of return type hints for __init__
methods that are not dynamically typed (at least one argument is annotated). With this flag set, ANN200
level errors will be suppressed for __init__
methods if at least one argument is explicitly annotated.
For example, from Mypy's documentation:
class C1: # Return annotated
def __init__(self) -> None:
self.var = 42
class C2: # Return annotated
def __init__(self, arg: int):
self.var = arg
class C3:
def __init__(self): # Return not annotated
# This body is not type checked
self.var = 42 + 'abc'
NOTE: By default, Mypy does not enforce annotations for self
in class methods, so to completely mimic Mypy's behavior with flake8-annotations
ANN101
will need to be added to the repository's ignored linting codes.
See Mypy's documentation for additional details: https://mypy.readthedocs.io/en/stable/class_basics.html?#annotating-init-methods
--allow-untyped-defs
to suppress all errors from dynamically typed functions. A function is considered dynamically typed if it does not contain any type hints.pep8-naming
to linting toolchainblack
check-merge-conflict
check-toml
check-yaml
end-of-file-fixer
mixed-line-ending
python-check-blanket-noqa
Argument
and Function
__repr__
methods to make the string more helpful to readNone
returning functions when they contained nested functions with non-None
returns (thanks @isidentical!)The previous approach being taken for nesting as to use a generic_visit() on the node to visit any nested functions. However, from the bugs reported (#67, #69) it was made clear that this approach was too generic & a method for either restricting or keeping track of the depth of this generic visit was required.
Both the FunctionVisitor
and ReturnVisitor
classes have been rearchitected to keep track of the parent context of the nodes being visited in order to properly classify methods of nested classes and return values of nested functions, respectively.
You can view a full writeup here on discuss.python.org.
TYP
to ANN
in order to deconflict with flake8-typing-imports
Per #64, due to prefix shadowing of TYP
between flake8-annotations
and flake8-typing-imports
, it's been suggested that the prefix for this repository be changed to ANN
so the plugins can coexist peacefully.
--suppress-none-returning
configuration option to suppress TYP200 level errors for functions that either lack a return
statement or only explicitly return None
.black
as an explicit developer requirement (codebase already adheres to black
formatting)This release adds the --suppress-none-returning
configuration option, as requested by #41. If this flag is set, TYP200
-level errors are suppressed for functions that meet one of the following criteria:
return
statement, orreturn
statement(s) all return None
(explicitly or implicitly).For example:
def foo():
"""This is a test function."""
a = 2 + 2
if a == 4:
return None
else:
return
Will not yield a TYP201
error, with the flag set:
$ flake8 test.py
test.py:1:11: TYP201 Missing return type annotation for public function
$ flake8 test.py --suppress-none-returning
<No output>
And:
def foo():
"""This is a test function."""
a = 2 + 2
if a == 4:
return True
else:
return
Will still yield a TYP201
error, with the flag set:
$ flake8 test.py
test.py:1:11: TYP201 Missing return type annotation for public function
$ flake8 test.py --suppress-none-returning
test.py:1:11: TYP201 Missing return type annotation for public function
The default value of this configuration option is False
, so this addition should be transparent to existing users.