

def validate(narg, conv, logMessage = None):
	def decorate(func):
		def funcDecorated(*args):
			newArgs = list(args)
			try:
				newArgs[narg] = conv(newArgs[narg])
			except Exception, e:
				# wrong argument! do some logging here and re-raise
				raise Exception("Invalid argument #{}: {} {}".format(narg, e, "({})".format(logMessage) if logMessage else ""))
			else:
				return func(*newArgs)

		return funcDecorated
	return decorate

def customValidationFunction(value):
	if value % 2 == 0:
		return value
	raise Exception("Value isn't even")

@validate(0, int)
@validate(1, int, logMessage='argument must respond to int()')
@validate(2, customValidationFunction)
def some_func(int_arg, int_arg2, other_arg):
    # the control gets here only after args are validated correctly
    return int_arg * int_arg2 * other_arg


def check(func):
	try:
		func()
	except Exception, e:
		return 'Wrong: {}'.format(e)
	else:
		return 'OK'

print 1, check(lambda: some_func(5,10,2))
print 2, check(lambda: some_func('five',10,2))
print 3, check(lambda: some_func(5,'ten',2))
print 4, check(lambda: some_func(5,10,1))
