Created
January 18, 2014 21:38
-
-
Save jsborjesson/8496924 to your computer and use it in GitHub Desktop.
Revisions
-
Jimmy Börjesson created this gist
Jan 18, 2014 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,111 @@ import re from weakref import WeakKeyDictionary class AdvancedDescriptor(object): """ Base class for descriptors, is hard to understand but works for most cases. from https://www.youtube.com/watch?v=P92z7m-kZpc """ def __init__(self, name=None): self.name = self.mangle(name) def __get__(self, instance, owner): if instance is None: raise AttributeError('Can only be accessed from instance') if self.name not in instance.__dict__: raise AttributeError return instance.__dict__[self.name] def __set__(self, instance, value): if self.name == None: self.fetchattr(instance) instance.__dict__[self.name] = value def __delete__(self, instance): del instance.__dict__[self.name] def fetchattr(self, instance): for attr in instance.__class__.__dict__: if attr.startswith('__'): continue obj = instance.__class__.__dict__[attr] if obj == self: self.name = self.mangle(attr) break def mangle(self, name): """Mangle name to __name.""" if name != None: if name.startswith('__'): raise AttributeError('Name conflict') elif name.startswith('_'): return '_' + name else: return '__' + name return name class ValidationDescriptor(object): """Simple base descriptor with support for validation.""" def __init__(self, default=None): self.default = default self.data = WeakKeyDictionary() def __get__(self, instance, owner): return self.data.get(instance, self.default) def __set__(self, instance, value): self.data[instance] = self.validate(value) def __delete__(self, instance): del self.data[instance] def validate(self, value): """Can either raise an exception or return a valid value.""" raise NotImplementedError('You need to implement a validate method') class RegexValidator(ValidationDescriptor): """Descriptor that validates a regex when set.""" def __init__(self, regex=None): self.regex = re.compile(regex) if isinstance(regex, str) else regex super(RegexValidator, self).__init__() def validate(self, value): if self.regex.match(value) != None: return value else: raise TypeError('"{}" is not valid.'.format(value)) class Person(object): email = RegexValidator(r'^(\w*)@(\w*)\.(\w{3})$') def __init__(self, name, email): self.name = name self.email = email def __str__(self): return '{}: {}'.format(self.name, self.email) # demo if __name__ == '__main__': d = Person('Alice', '[email protected]') print(d) try: p = Person('Wallace', 'notanemail.com') except Exception as e: print(e)