Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import inspect
- def typed(__return_type__ = None, __accept_subclasses__ = True, **argument_types):
- """
- typed - run-time simulation of static typing in python
- A decorator that will throw a TypeError if the type of an argument value passed to the decorated function
- does not match the type defined by this decorator.
- Usage example below. Would throw a TypeError if the "string" argument is not of type str and if the type of the
- returned value is not int:
- @typed(int, string = str)
- def getStringLength(string):
- return len(string)
- """
- def decorator(wrappee): # The decorator function that will be returned by typed()
- def wrapper(*args, **kwargs):
- """
- The wrapper function that will be returned by decorator when the decorated function is called
- This is the actual function that will be run before the wrapped function runs
- """
- def checkType(arg, expected_type, found_value, return_value = False):
- """
- Raise an exception if the found value doesn't match the expected type
- Adapt exception text to return value/argument
- """
- # Will be set to True if the found_value doesn't match the expected type
- bad_type = False
- # If the option accept subclasses is true, check if the found value is an instance of the expected
- # type and set bad_type = True if not
- if __accept_subclasses__:
- if not isinstance(found_value, expected_type):
- bad_type = True
- # If the option accept subclasses is false, check that the class of the found_value matches the
- # expected type exactly, and set bad_type = True if not
- else:
- if not found_value.__class__ == expected_type: #isinstance(found_value, expected_type):
- bad_type = True
- # Raise a TypeError if a bad type was found and adapt the text depending on if its a return type
- # or argument type that was bad
- if bad_type:
- if return_value:
- raise TypeError(u"Return value of %s() expected type %s but found type %s" % (wrappee.__name__, __return_type__, found_value.__class__))
- else:
- raise TypeError(u"Argument %s of %s() expected type %s but found type %s" % (arg, wrappee.__name__, expected_type, found_value.__class__))
- # Fetch an ordered list of the arguments defined for the wrapped function
- wrappee_args,_,_,_ = inspect.getargspec(wrappee)
- # Check all arguments defined by the wrapped function against the types defined
- for i, arg in enumerate(wrappee_args):
- if i >= len(args):
- break
- checkType(arg, argument_types[arg], args[i])
- # Check all keywords arguments defined by the wrapped function against the types defined
- for arg in argument_types.keys():
- if kwargs.has_key(arg):
- checkType(arg, argument_types[arg], kwargs[arg])
- # Run the wrapped function
- result = wrappee(*args, **kwargs)
- # Check the return value against the type defined
- if __return_type__ is not None:
- checkType("", __return_type__, result, return_value = True)
- return result
- return wrapper
- return decorator
- ###
- # Usage example
- ###
- @typed(int, string = str)
- def getStringLength(string):
- return len(string)
- #####
- # Simple tests below
- #####
- def raisesTypeError(func, *args, **kwargs):
- try:
- func(*args, **kwargs)
- return False
- except TypeError:
- return True
- assert getStringLength("four") == 4
- assert raisesTypeError(getStringLength, 4)
- @typed(int, string = str)
- def getStringLengthFloat(string):
- return float(len(string))
- assert raisesTypeError(getStringLengthFloat, "four")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement