Reputation: 45251
I want to validate the input value of a class member against a range. I am trying out the decorator module because of all the benefits it provides (such as preserving class meta data).
Here is my validation decorator:
from decorator import decorator
@decorator
def valid_range(f,*args,**kwargs):
value = args[1]
inrange = True
try:
inrange = (inrange and (value <= range['max_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value < range['max_exclusive']))
except KeyError: pass
try:
inrange = (inrange and (value >= range['min_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value > range['min_exclusive']))
except KeyError: pass
if inrange:
return f(*args,**kwargs)
else:
raise Exception
Here is the application of the decorator (assume value_setter
is in the body of some class):
@valid_range({'max_inclusive':1,'min_inclusive':0})
def value_setter(self,value):
self.value = value
Is there a way to pass the max/min dict
as an argument to my decorator (which is used as range
in the decorator definition itself)? I know how to do this using regular decorators, but as I said, I'd like to use the decorator module if at all possible.
If it isn't possible, how else can I do this and preserve all the identifying data? Any alternative modules I should consider using instead?
EDIT: Note that passing the range
dict
argument as part of *args
and **kwargs
isn't an option. I don't want to include it as part of my class definition.
Upvotes: 0
Views: 184
Reputation: 45251
Came up with the following solution. Basically, I am wrapping my decorator in another decorator.
This does allow separating the entry of max and min from the rest of the code, but it's definitely not a nice solution and misses the point of the decorator
module (which is to simplify the application of decorators). For this reason I prefer acushner's answer to my own.
from decorator import decorator
@decorator
def _valid_range(f,*args,**kwargs):
return f(*args,range = {'max_inclusive':1,'min_inclusive':0},**kwargs)
@decorator
@_valid_range
def valid_range(f,*args,**kwargs):
range = kwargs.pop('range',None)
value = args[0]
inrange = True
try:
inrange = (inrange and (value <= range['max_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value < range['max_exclusive']))
except KeyError: pass
try:
inrange = (inrange and (value >= range['min_inclusive']))
except KeyError: pass
try:
inrange = (inrange and (value > range['min_exclusive']))
except KeyError: pass
if inrange:
return f(*args,**kwargs)
else:
raise Exception
@valid_range
def value_setter(value):
print(value)
Upvotes: 0
Reputation: 9946
you can just write your own (shortened example):
from functools import wraps
def valid_range(min_val=0, max_val=0):
def deco(f):
@wraps(f)
def wrapper(*args, **kwargs):
val = args[0]
if min_val <= val <= max_val:
return f(*args, **kwargs):
else:
raise RangeError
return wrapper
return deco
usage:
@valid_range(10, 20)
def f(x):
pass
Upvotes: 4