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

Fix decorators on class __init__ methods #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Conversation

villelaitila
Copy link

This fixes a few issues around decorators, specifically resolves python#5398 and python#1706. Not sure if this is exactly the way you want to fix this. Probably better would be to get rid of the Decorator class altogether, but this provides a workable fix. My reasoning on it is this:

  • Many places check whether a Node is callable by checking whether it is an instance of FuncBase.
  • Replace these with a get_callable method, which will return a FuncBase if it makes sense to construct one for the passed in Node, otherwise return None.
  • This method currently only checks if a Node is a FuncBase or a callable Decorator, but could conceivably be expanded to cover other cases with minimal additional work.
  • In the case of a Decorator return an instance of the CallableDecorator class, which inherits from FuncItem iff the decorated function is still callable.
    This works, but creates problems in a few places in the codebase that explicitly assume that an instance of FuncBase is not decorated. I have fixed the instances of this I could find, and all of the existing tests pass, but we probably want to do more testing on this to be sure.

Stray observations:

  • It would be nice if we didn't have to treat property and similar descriptor-based decorators as special cases and could work with them more directly. Possibly by having their implementations in typeshed be Generics with appropriate types. This would probably require more robust type annotation than we currently support though.
  • It may make sense to either rename Var.is_staticmethod and Var.is_classmethod to Var.is_static and Var.is_class or rename FuncBase.is_static and FuncBase.is_class to FuncBase.is_staticmethod and FuncBase.is_classmethod. They duplicate the same functionality, and this would help remove some unneeded type checks in a few places.
  • I experimented with having properties just return their property type, rather than being treated as a special type of callable. This made a few things nicer, in particular fixing the false positive in testInferListInitializedToEmptyInClassBodyAndOverriden, but created problems in other places. This may be worth investigating further.
  • This change may make it easier to implement properties with different get/set types as suggested in What to do about setters of a different type than their property? python/mypy#3004, I will need to investigate further.
  • This change probably means that there is a lot of code related to handling Decorators that is no longer needed, but I am not familiar enough with the codebase to say that for sure.
  • This fix requires that the decorator is explicitly annotated to return a Callable. It seems like this should be something we could determine through type inference, but I'm not sure how easy that would be to do.

I look forward to your criticisms.

root added 2 commits October 17, 2018 19:15
commit 95cafcd
Author: root <[email protected]>
Date:   Wed Oct 17 19:03:27 2018 -0700

    Fix broken tests, add new tests, and remove things added for debugging

commit c845501
Author: Joel Croteau <[email protected]>
Date:   Mon Oct 15 16:07:46 2018 -0700

    Fix some test failures

commit 32f05cb
Author: Joel Croteau <[email protected]>
Date:   Mon Oct 15 11:52:52 2018 -0700

    Fix false positive and add some type annotations

commit cbaab5b
Author: root <[email protected]>
Date:   Thu Oct 11 17:31:33 2018 -0700

    Here, have some code
@ilevkivskyi, I see your point about how overriding `__instancecheck__`
would create problems with debugging and `mypyc`, so I have implemented
an alternate solution. I have created a `get_callable` method to check
whether a node is callable and, in the case of a decorator, return an
instance of a separate `CallableDecorator` class that inherits from
`FuncItem`. I had originally thought to just have an `is_callable` method
that would test whether a `Node` was either an instance of `FuncBase`
or a callable `Decorator`, but this created problems with type resolution.
This solution is not exactly ideal either, but I think will create fewer
problems. I agree that the best solution would be to remove the `Decorator`
class altogether, but this would be a fairly major refactor. The problem
is that we do need a `Decorator` class in early passes before we have
type information, and we use the `Node.accept` method to add type information
to an instance, we don't have a simple way to replace a node with another
node of a different type. Let me know what you think of this approach.

One other stray observation:
* This fix requires that the decorator is explicitly annotated to return
  a `Callable`. It seems like this should be something we could determine
  through type inference, but I'm not sure how easy that would be to do.
@softagram-bot
Copy link

Softagram Impact Report for pull/2 (head commit: 6f9a449)

⭐ Visual Overview

Changed elements and changed dependencies.
Changed dependencies - click for full size
Graph legend
(Open in Softagram Desktop for full details)

⭐ Change Impact

How the changed files are used by the rest of the project
Impacted files - click for full size
Graph legend
(Open in Softagram Desktop for full details)

📄 Full report

Give feedback of this report to [email protected]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Decorator on __init__ causes loss of type info
2 participants