Last active
March 24, 2017 13:27
-
-
Save numberoverzero/a18deec64e6434d4c95854754d71a619 to your computer and use it in GitHub Desktop.
PEP 487 is insane, holy fuck this is awesome
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
from typing import Any, Dict, List, NamedTuple, Optional, Tuple, TypeVar, Generic, Type | |
T = TypeVar("T") | |
class Field(Generic[T]): | |
key: str | |
t: Type[T] | |
readonly: bool | |
def __init__(self, t: Type[T], readonly: bool=True) -> None: | |
self.t = t | |
self.readonly = readonly | |
def __get__(self, instance: Any, owner: Any) -> T: | |
return instance.__dict__[self.key] | |
def __set__(self, instance: Any, new: T): | |
assert not self.readonly | |
old = instance.__dict__.get(self.key) | |
instance.__dict__[self.key] = new | |
if old != new: | |
self.notify(instance, old, new) | |
def notify(self, instance: Any, old: Any, new: Any) -> None: | |
print(self, instance, old, new) | |
class MutableField(Field[T]): | |
def __init__(self, t: Type[T]) -> None: | |
super().__init__(t, readonly=False) | |
class BaseModel: | |
def __init_subclass__(cls, **kwargs) -> None: | |
cls.fields = fields = {} | |
for name, attr in cls.__annotations__.items(): | |
if issubclass(attr.__origin__, Field): | |
field_cls = attr.__origin__ | |
fields[name] = field = field_cls(*attr.__args__) | |
setattr(cls, name, field) | |
field.key = name | |
def __init__(self, *args, **kwargs: Any) -> None: | |
for name, value in zip(cls.fields, args): | |
self.__dict__[name] = value | |
for name in kwargs: | |
if name in cls.fields: | |
self.__dict__[name] = kwargs[name] | |
cls.__init__ = __init__ | |
super().__init_subclass__() | |
# USAGE | |
import pendulum | |
class Blob(BaseModel): | |
id: Field[int] | |
content: Field[bytes] | |
last_modified: MutableField[pendulum.Pendulum] | |
blob = Blob(3, b"hello") | |
blob.last_modified = pendulum.now() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment