Skip to content

Decorators are sensitive to import cycle ordering #1303

Closed

Description

@ddfisher

If we have two files:
test1.py:

from typing import Callable, Any
import test2

def deco(f: Callable[[int, int], Any]) -> Callable[[int, int], Any]:
    pass

@deco
def add(self, other: int) -> int:
    pass

test2.py:

import test1
test1.add(1, 1)

Running mypy test1.py test2.py results in:
test2.py:2: error: Cannot determine type of 'add'

Removing the @deco decorator from add or reversing the order of the files on the command line makes the error go away.

Activity

  1. JukkaL commented on Mar 18, 2016

    @JukkaL
    Collaborator

    Yeah, this is a known issue.

  2. ddfisher commented on Mar 18, 2016

    @ddfisher
    CollaboratorAuthor

    I didn't see it documented elsewhere, though?

  3. JukkaL commented on Mar 18, 2016

    @JukkaL
    Collaborator

    See #481 (though it's not very specific).

  4. JukkaL commented on Mar 18, 2016

    @JukkaL
    Collaborator

    I marked this as a bug as there is no acceptable workaround right now, and this is a common thing.

  5. JukkaL commented on Mar 23, 2016

    @JukkaL
    Collaborator

    The following was copied from #481 because it's relevant here:

    Infer types for (most) decorated functions before the final type checking pass. Either do this during semantic analysis (we already do some, but it's pretty limited) or introduce another type checking pass. Decorated functions often cause trouble as mypy sometimes only infers their types during the final pass, when it can be too late as modules must be type checked in some specific, linear order.

    A fairly simple approach would to improve the lightweight type inference engine we have just for function decorators.

    Some ideas of additional things to support:

    1. Decorator contains a call
    @decorator()
    def func(...): ...
    

    We could just "unwrap" the decorator type by taking the return type without checking the call otherwise.

    1. Decorator that always returns the same type (no type variables)
    def decorator(f: Callable[[int], str]) -> Callable[[int], str]:
        ...
    
    @decorator
    def func(x: int) -> str:
        ...
    

    We would just have to recognize if the return type has no type variables, which is easy, and then we can trivially infer the type of the decorated function.

    The current implementation lives in semanal.py (ThirdPass.visit_decorator). I suggest implementing at least these improvements in 0.3.2, as they should be simple. What do you think?

  6. added this to the milestone on Mar 24, 2016
  7. self-assigned this
    on Apr 7, 2016
  8. gvanrossum commented on Apr 14, 2016

    @gvanrossum
    Member

    Let's make this a stretch goal for the 0.3.2. release. It's important, but we feel only Jukka understands it well enough to be able to fix it. If Jukka can't do it, we can release 0.3.2 without this and push it to the next milestone -- rather than hold up the release.

  9. JukkaL commented on Apr 14, 2016

    @JukkaL
    Collaborator

    I started working on this a while back but haven't had time to finish it. I'll see if the current branch is good enough to merge already, even if it's not complete.

  10. JukkaL commented on May 5, 2016

    @JukkaL
    Collaborator

    The original example now works, so I'm closing this. We can create new issues for remaining cases where decorators don't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugmypy got something wrong

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions