Skip to content

Instantly share code, notes, and snippets.

@ztane
Last active September 19, 2016 10:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ztane/acf66661505f5344ac0d21ab86fa3f6f to your computer and use it in GitHub Desktop.
Save ztane/acf66661505f5344ac0d21ab86fa3f6f to your computer and use it in GitHub Desktop.
Typing testing
import warnings
import inspect
NONE = object()
class TypingWarning(Warning):
pass
class CheckedMeta(type):
def __new__(mcl, name, bases, nmspc):
new_type = super(CheckedMeta, mcl).__new__(mcl, name, bases, nmspc)
full_annotations = {}
for i in new_type.__mro__:
for k, v in getattr(i, '__annotations__', {}).items():
if k not in full_annotations:
full_annotations[k] = v
if hasattr(new_type, '__dict__'):
new_type.__full_annotations__ = full_annotations
return new_type
def __init__(cls, name, bases, nmspc):
super().__init__(name, bases, nmspc)
full_annotations = getattr(cls, '__full_annotations__', {})
for k, v in full_annotations.items():
val = getattr(cls, k, NONE)
if val is NONE or hasattr(val, '__get__') or hasattr(val, '__set__'):
continue
if not isinstance(val, v):
warnings.warn(f'{cls.__name__}.{k} value {val} doesn\'t'
f' match annotation {v}', TypingWarning,
stacklevel=2)
wrapped_attr_name = f'_checkedmeta_{k}'
def make_getter(wrapped_attr_name):
return lambda self: getattr(self, wrapped_attr_name)
def make_setter(wrapped_attr_name, type):
def setter(self, value):
if not isinstance(value, type):
warnings.warn(f'{cls.__name__}.{k} value {val} doesn\'t'
f' match annotation {v}', TypingWarning,
stacklevel=2)
setattr(self, wrapped_attr_name, value)
return setter
def make_deleter(wrapped_attr_name):
return lambda self: delattr(self, wrapped_attr_name)
wrapped_descriptor = property(fget=make_getter(wrapped_attr_name),
fset=make_setter(wrapped_attr_name, v),
fdel=make_deleter(wrapped_attr_name))
setattr(cls, wrapped_attr_name, val)
setattr(cls, k, wrapped_descriptor)
class CheckedBase(metaclass=CheckedMeta):
pass
class InstanceTest(CheckedBase):
a: int
b: str = '55'
class InstanceTest2(InstanceTest):
a: str = '42'
c: tuple = [1, 2]
x = InstanceTest2()
x.b = 55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment