Last active
February 17, 2020 16:52
-
-
Save MattOates/dc6464cd27b035721c36fb2679aa812c to your computer and use it in GitHub Desktop.
The general problem is that mypy doesn't really understand that a descriptor on an attribute is going to have the return value of __get__ not __call__/__init__
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
If you run the following with mypy you will get the following type error | |
mypy descriptor_typing_problem.py | |
descriptor_typing_problem.py:36: error: Incompatible types in assignment (expression has type "attr_descriptor", variable has type "int") | |
""" | |
from enum import Enum | |
from typing import Type, Any | |
Sentinels = Enum("Sentinels", "NO_INIT") | |
class attr_descriptor: | |
def __init__(self, default=Sentinels.NO_INIT): | |
self.default = default | |
def __set_name__(self, owner, name): | |
self.owner = owner | |
self.name = name | |
if hasattr(owner, "__annotations__"): | |
self.value_type = owner.__annotations__.get(name, None) | |
self.value_type = Sentinels.NO_INIT | |
def __get__(self, instance: 'BaseClass', typevar: Type['BaseClass']) -> Any: | |
if instance is None: | |
return self | |
if self.name in instance.__dict__: | |
return instance.__dict__[self.name] | |
if self.default != Sentinels.NO_INIT: | |
return self.default | |
if self.value_type != Sentinels.NO_INIT: | |
return self.value_type() | |
return None | |
class BaseClass: | |
thing: int = attr_descriptor(default=10) | |
def __init__(self, thing): | |
if thing: | |
self.thing = thing | |
BaseClass(thing=2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment