Skip to content

Instantly share code, notes, and snippets.

@MattOates
Created February 17, 2020 16:37
Show Gist options
  • Save MattOates/c14089385ab433311a072e63b2bb6a51 to your computer and use it in GitHub Desktop.
Save MattOates/c14089385ab433311a072e63b2bb6a51 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__
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