Instantly share code, notes, and snippets.

@gvx /
Last active Dec 11, 2015

What would you like to do?
An experiment with metaclasses, with dynamic type verification
from veri import Verified
class Something(metaclass=Verified):
# a single type
some_int = int
some_str = str
# a 'struct' using tuples
some_tuple = (int, int, str)
# a list of integers
some_list = [int]
# a list containing zero or more ints, strs and floats
mixed_list = [int, str, float]
# a list containing anything
any_list = [Ellipsis]
# either an int, or None
maybe_int = {int, None}
# anything at all
any = Ellipsis
# a list of types
any_type = [type]
# a set of possible values (like an enum)
threat_level = {0, 1, 2, 3, 4}
function = {min, sum, len}
s = Something()
s.some_int = 1
#s.some_int = 'error'
s.some_str = 'hey'
#s.some_str = ['not going to happen']
s.some_tuple = (0, 0, 'seven')
#s.some_tuple = (0, 'this would error', 0)
s.some_list = [1, 2, 3]
#s.some_list = ['exception here']
s.mixed_list = ['one', 2, 3, 4.0, 'five']
#s.mixed_list = ['one', 2j, []]
s.any_list = [1, 'two', 3j]
#s.any_list = 'not a list'
s.maybe_int = 10
s.maybe_int = None
#s.maybe_int = 'nope'
s.any = [{any: 'thing'}, ('at',), all]
#no counter-example for s.any
s.any_type = [int, str, dict, set, tuple, type, Something, Verified]
#s.any_type = [max, 'nope']
s.threat_level = 3
#s.threat_level = 'five'
#s.threat_level = 5
s.function = min
s.function = len
#s.function = max
def verify(value, verifier):
if verifier is Ellipsis:
return True
if isinstance(verifier, type) and isinstance(value, verifier):
return True
if isinstance(verifier, tuple):
if not isinstance(value, tuple) or len(value) != len(verifier):
return False
return all(verify(val, ver) for val, ver in zip(value, verifier))
if isinstance(verifier, list):
if not isinstance(value, list):
return False
return all(any(verify(val, ver) for ver in verifier) for val in value)
if isinstance(verifier, set):
return any(verify(value, ver) for ver in verifier)
return value == verifier
class Verified(type):
def __new__(cls, name, bases, dct):
v = {}
def getV(self, name):
if name not in dct:
raise AttributeError()
return v[name]
def setV(self, name, value):
if name not in dct:
raise AttributeError()
if not verify(value, dct[name]):
raise TypeError("Validation error: got {!r}, wanted {!r}."
.format(value, dct[name]))
v[name] = value
return type.__new__(cls, name, bases,
{'__getattr__': getV, '__setattr__': setV})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment