Reputation:
I've got an interface that I'm working with to declares several verification methods. For simplicity's sake, we can consider three methods. verify_less_than()
, verify_equal()
, and verify_less_than_equal(
). (See below for an implementation). When I import these, I would like to decorate them such that if a verification fails - verify_less_than( 10, 5 )
- an exception will be raised.
I've got this working for the first two, but the third function is giving me a much harder time. Because verify_less_than_equal
is defined in terms of the previous two methods, if the first call fails - verify_less_than_equal( 5, 5 )
- an exception will be thrown before the second gets called.
Any help on this would be greatly appreciated
Example code:
class needs_decoration():
def verify_less_than( self, x, y ):
return( x < y )
def verify_equal( self, x, y ):
return( x == y )
def verify_less_than_equal( self, x, y ):
return( self.verify_less_than( x, y ) or self.verify_equal( x, y ) )
import types
import module
def decorate( fn ):
def wrapped( self, x, y ):
res = fn( self, x, y )
if res == False:
raise Exception( 'Verification failed!' )
return res
return wrapped
for k, v in vars( module.needs_decoration ).items():
if isinstance( v, types.FunctionType ):
if not '__init__' in str( vars( module.needs_decoration )[ k ] ):
vars( module.needs_decoration )[ k ] = decorate( v )
verifier = module.needs_decoration()
verifier.verify_less_than_equal( 5, 5 ) # This will raise an exception, and I would like it not to
Upvotes: 3
Views: 86
Reputation: 880577
You could define private (underscored) methods which will remain undecorated, so that _verify_less_than_equal
can call the undecorated functions. The for-loop
then can add the public API (methods without underscores) which are decorated versions of the private methods:
import types
def add_decorators(cls):
def decorate(fn):
def wrapped(self, x, y):
res = fn(self, x, y)
if not res:
raise ValueError('Verification failed! {}({}, {}) is False'
.format(fn.__name__, x, y))
return res
return wrapped
for k, v in vars(cls).items():
if isinstance(v, types.FunctionType):
if k.startswith('__'): continue
if k.startswith('_'):
setattr(cls, k[1:], decorate(v))
return cls
@add_decorators
class NeedsDecoration():
def _verify_less_than(self, x, y):
return x < y
def _verify_equal(self, x, y):
return x == y
def _verify_less_than_equal(self, x, y):
return self._verify_less_than(x, y) or self._verify_equal(x, y)
def __init__(self): pass
verifier = NeedsDecoration()
assert verifier.verify_less_than_equal(5, 5)
As desired, the last line does not raise an exception.
Upvotes: 1