Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mypy fails to infer the type of the decorated function used in the decorator #12944

Open
mristin opened this issue Jun 5, 2022 · 3 comments
Open

Comments

@mristin
Copy link

mristin commented Jun 5, 2022

Hi mypy team,

Bug Report
I'm looking into the issue with design-by-contract library icontract which heavily uses decorators to formalize contracts. For many functions and methods, the contracts involve the decorated function (or method) itself.

See the example from the issue Parquery/icontract#243:

from icontract import ensure

@ensure(
    lambda a, b, result: 
    result == myadd(b, a), 
    "Commutativity violated!"
)
def myadd(a: int, b: int) -> int:
    return a + b

Mypy 0.960 says:

tests_3_10\deleteme.py:5: error: Cannot determine type of "myadd"

If I add # type: ignore:

from icontract import ensure

@ensure(
    lambda a, b, result: 
    result == myadd(b, a),   # type: ignore
    "Commutativity violated!"
)
def myadd(a: int, b: int) -> int:
    return a + b

mypy does not complain any more.

I was actually a bit surprised that mypy tried to infer the types in the lambda. @claudio-ebel tried a couple of fixes using casting (see his comment Parquery/icontract#243 (comment)), but none of them worked.

I am actually not sure if this is a misunderstanding on our part or a bug in mypy. Any pointers about how to resolve the issue are very much appreciated! Please let us know if you need more information, or if there is anything we can do to help to fix this.

Your Environment

  • Mypy version used: 0.960
  • Mypy command-line flags: `--strict``
  • Python version used: 3.10.0
@mristin mristin added the bug mypy got something wrong label Jun 5, 2022
@erictraut
Copy link

This is an unresolvable circular reference from a type checker's perspective. Evaluating the call to ensure() requires the evaluation of the arguments, including the lambda. But evaluating the lambda involves the evaluation of myadd, which refers to the decorated symbol.

FWIW, pyright also emits an error in this case: Type of "myadd" could not be determined because it refers to itself.

Here's a workaround:

def _myadd(a: int, b: int) -> int:
    return a + b

myadd = ensure(lambda a, b, result: result == _myadd(b, a), "Commutativity violated!")

This breaks the cycle because the lambda refers to the undecorated symbol in this case.

@erictraut
Copy link

I don't think this is a bug in mypy. As I explained above, this is an unresolvable circular dependency from the perspective of a static type checker. I recommend closing unless you think it's worth improving the error message.

@JelleZijlstra
Copy link
Member

I do think we should improve the type message to say why we cannot determine the type. The Pyright error message @erictraut quoted above is better.

@JelleZijlstra JelleZijlstra added topic-usability topic-error-reporting How we report errors and removed bug mypy got something wrong topic-error-reporting How we report errors labels Aug 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants