python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.4k stars 2.82k forks source link

False warning: Returning Any from function declared to return "bool" #5697

Closed stefanhoelzl closed 6 years ago

stefanhoelzl commented 6 years ago

class Structure(): def eq(self, other: Any) -> bool: return {} == other

* What is the actual behavior/output? 
```console
mypytest.py:5: warning: Returning Any from function declared to return "bool"
ilevkivskyi commented 6 years ago

Why do you think the warning is false? It looks like a totally reasonable warning, since --warn-return-any is part of --strict. If you don't like it, don't use this flag.

stefanhoelzl commented 6 years ago

because {} == other should evaluate to a bool. Which means the method returns a bool. Then getting a warning Returning Any seems false to me.

ilevkivskyi commented 6 years ago

Everything applied to Any evaluates to Any. A dynamic class can define __eq__ that returns a string, there is no guarantee it is a bool.

ylathouris commented 3 years ago

Everything applied to Any evaluates to Any. A dynamic class can define __eq__ that returns a string, there is no guarantee it is a bool.

This was helpful. Thank you!

Torxed commented 2 years ago

I get the same error when using:

def verify_password(plain_password :str, hashed_password :str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

Which is taken from the FastAPI docs. In this case .verify() is a verification function that to the best of my knowledge can only return True or False but is not typed: https://foss.heptapod.net/python-libs/passlib/-/blob/01dfe753e4f4590307611ef5c6304279a7364305/passlib/context.py?page=3#L2272-2313

I think I understand the rules of the Any evaluation, but perhaps I've misunderstood how mypy evaluates these cases. Shouldn't the return value matter in mypy's checks? That is that it's a static value of False or True that gets returned?

In any case, the fix is simple enough:

def verify_password(plain_password :str, hashed_password :str) -> bool:
    return bool(pwd_context.verify(plain_password, hashed_password))

But it feels excessive to enforce one additional function call per call stack to please mypy, even in --strict mode. It's the first time trying to use linters and type checkers, and this thread came up. I assumed it would deal with these cases "smartly", is that not the case?

JelleZijlstra commented 2 years ago

@Torxed the fix seems simple here: mypy needs to be told what the return type of .verify() is. If there's no annotation, it doesn't know.

I would not recommend turning on the option that generates this error. It's too strict to be useful for most code.

hauntsaninja commented 2 years ago

--no-warn-return-any :-)

mattmontero commented 5 months ago

same issue here 👋

My little hack for this is to set a new variable, and type the variable. (Similar to @Torxed, but not explicitly casting)

from typing import Any

class Structure():
    def __eq__(self, other: Any) -> bool:
        outcome: bool = {} == other
        return outcome
BabakAmini commented 5 months ago

@Torxed the fix seems simple here: mypy needs to be told what the return type of .verify() is. If there's no annotation, it doesn't know.

The same problem affects me. It is evident that .verify() returns a boolean. Why is it invisible to Mypy?

image

Torxed commented 5 months ago

@Torxed the fix seems simple here: mypy needs to be told what the return type of .verify() is. If there's no annotation, it doesn't know.

The same problem affects me. It is evident that .verify() returns a boolean. Why is it invisible to Mypy?

image

It's actually not completely evident. Because the .verify() function actually lacks a typed annotation that mypy can interpret. Your IDE however, might be able to parse the sphinx docstring since the verify docstring has a :returns: or, if exist, :rtype:.

But to the best of my understanding, passlib simply lacks native annotation in all possible .verify() functions.

And to the best of my understanding, mypy does not read or understand docstrings, and why would it, as it's a sphinx invented thing (as I understand it).

Would be nice if the project moved to https://pypi.org/project/sphinx-autodoc-typehints/ or something similar.

BabakAmini commented 5 months ago

@Torxed Thank you for your thoughtful explanations, as I had not given this topic much thought.