sco1/flake8-annotations

Add Flag to Suppress Warnings for Dynamically Typed Functions

Dreamsorcerer opened this issue · 12 comments

For consistency with mypy, it would be nice to have an option/rule that behaved the same way as mypy regarding typing of __init__().

Currently, flake8-annotations always raises a violation if there is no return type annotation.

Mypy, however, raises an error if there are no annotations at all (as this would indicate an untyped function).
i.e. If there are any annotations on parameters, then a return type is not needed. The return type is only needed when there are no parameters in order to mark the function as statically typed.
e.g. def __init__(self, foo: str): and def __init__(self) -> None: are both correctly typed.

sco1 commented

Suppressing ANN204 will ignore these warnings.

Yes, but it doesn't give any violation for def __init__(self):, which Mypy does. Allowing or suppressing will result in different behaviour to Mypy (more lenient or more strict respectively).

So, to be consistent with Mypy, I'm expecting violations for:
def __init__(self):
but, no violations for:
def __init__(self, foo: str):

i.e. Mypy assumes an implicit return type of None for __init__(). But, there has to be atleast 1 annotation somewhere in order for the function to be marked as statically typed. No annotations indicates a dynamically typed function.
So, standard practice for def __init__(self): is to add a return type annotation to mark it as statically typed.

sco1 commented

Ok, I'm following now, sorry.

Right now we don't have a mechanism for discriminating between statically and dynamically typed functions like Mypy does (not just for __init__). Adding something like --allow-untyped-defs a la Mypy's --disallow-untyped-defs shouldn't be too complicated to add and would be worthwhile to provide as a flag.

In the interim you could probably fake it with the --suppress-non-returning flag, though it's not really semantically what you're looking for.

Indeed, I actually just disabled that flag, as Mypy will complain about no return types on regular functions. It's only __init__() that gets an implicit return type.

Unfortunately, that doesn't really resolve the problem, although still a nice addition to have.

For me, I want to:

  • ensure all functions are statically typed.
  • not add a return type to __init__(), unless it is required to make it statically typed (i.e. there are no typed parameters).

If there is a typed parameter, then it is considered statically typed. Mypy will infer the return type for __init__(), so there is no need to add an annotation for it.

Expected results:

def __init__(self, foo: int): pass
def __init__(self) -> None: pass
def __init__(self, foo): fail
def __init__(self): fail
def __init__(self, foo) -> None: fail
def __init__(self, foo: int) -> None: Maybe fail (or just allow the redundant return type).

sco1 commented

Ok. I guess we'll have to take another look at your specific use case. Sorry about that.

sco1 commented

Hopefully I got it right this time, would you be interested in checking out the dev-next branch (#91) to verify that we are able to provide a behavior that Mypy users would expect?

I cloned the branch, however I'm unsure how to make flake8 load it as a plugin..

@Dreamsorcerer Activate your virtual environment if you're using one and then run pip install -U /path/to/clone/directory

Perfect, seems to be working correctly with the extra argument enabled.