I want my business objects to be able to do this: class Person(base): def __init__(self): self.name = None
@base.validator def validate_name(self): if not self.name: return ['Name cannot be empty'] p = Person() print p.invalid # Prints ['Name cannot be empty'] p.name = 'foo' print p.invalid # Prints [] print bool(p.invalid) # Prints False The invalid attribute and validator decorator would be in the base class: class base(object): @staticmethod # so child can say: @base.validator def validator(func): """Mark the function as a validator.""" func._validator = True return func def _get_invalid(self): """Collect all validation results from registered validators""" result = [] for attrName in dir(self): # Prevent recursive calls if attrName == 'get_invalid' or attrName == 'invalid': continue attr = eval('self.' + attrName) # Get attribute if str(type(attr)) == "<type 'instancemethod'>": # Check if is function if hasattr(attr, '_validator'): # Check if function is a validator valerr = attr() # Get result of validation # Validation result can be a single string, list of strings, or None. # If the validation fails, it will be a string or list of strings # which describe what the validation errors are. # If the validation succeeds, None is returned. if type(valerr) == type([]): for err in valerr: result.append(err) else: if valerr != None: result.append(valerr) return result # List of validation error strings invalid = property(_get_invalid, None, None, "List of validation errors") # Read-only, so no fset or fdel I don't really like the _get_invalid() logic that reflects over each attribute and does ugly string comparisons. Is there a cleaner/more pythonic way to do this reflection? Also, I am using a decorator to simply mark a function as being a validator. This works, but I must enumerate all of the object's attributes to find all the validators. My original plan was to use a decorator to "register" a function as being a validator. Then the _get_invalid() call would only need to enumerate the registered functions. I ran into problems when I couldn't figure out how to use a decorator to store a function in an attribute of the function's class: # Decorator to register function as a validator def validator(func): """Save func in a list of validator functions on the object that contains func""" self._validation_functions.append(func) # ERROR: Cannot access self this way return func I appreciate your feedback. I am relatively new to python but have become completely enamored by it after looking for alternatives to the MS languages I use to develop business apps. -- http://mail.python.org/mailman/listinfo/python-list