Source code for easydev.decorators
# -*- python -*-
# -*- coding: utf-8 -*-
#
# This file is part of the easydev software
#
# Copyright (c) 2012-2014 -
#
# File author(s): Thomas Cokelaer (cokelaer, gmail.com)
#
# Distributed under the GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: https://github.com/cokelaer/easydev
# website: http://github.com/cokelaer/easydev
#
##############################################################################
# $Id$
"""Handy decorators"""
from functools import wraps
import threading
__all__ = ['ifpylab', 'requires', 'ifpandas']
# decorator with arguments and optional arguments for a method
def _require(*args_deco, **kwds_deco):
"""Decorator for class method to check if an attribute exist
.. doctest::
from easydev.decorators import require
class Test(object):
def __init__(self):
self.m = 1
@require('m', "set the m attribute first")
def print(self):
print self.m
t = Test()
t.print()
.. todo:: first argument could be a list
"""
if len(args_deco) != 2:
raise ValueError("require decorator expects 2 parameter. First one is" +
"the required attribute. Second one is an error message.")
attribute = args_deco[0]
msg = args_deco[1]
if len(attribute.split('.')) > 2:
raise AttributeError('This version of require decorator introspect only 2 levels')
def decorator(func):
# func: function object of decorated method; has
# useful info like f.func_name for the name of
# the decorated method.
def newf(*args, **kwds):
# This code will be executed in lieu of the
# method you've decorated. You can call the
# decorated method via f(_args, _kwds).
names = attribute.split('.')
if len(names) == 1:
if hasattr(args[0], attribute):
return func(*args, **kwds)
else:
raise AttributeError('%s not found. %s' % (names, msg))
elif len(names) == 2:
if hasattr(getattr(args[0], names[0]), names[1]):
return func(*args, **kwds)
else:
raise AttributeError('%s not found. %s' % (names, msg))
newf.__name__ = func.__name__
newf.__doc__ = func.__doc__
return newf
return decorator
# for book keeping, could be useful:
def _blocking(not_avail):
def blocking(f, *args, **kw):
if not hasattr(f, "thread"):
# no thread running
def set_result():
f.result = f(*args, **kw)
f.thread = threading.Thread(None, set_result)
f.thread.start()
return not_avail
elif f.thread.isAlive():
return not_avail
else:
# the thread is ended, return the stored result
del f.thread
return f.result
return blocking
# same as require decorator but works with list of stirngs of
# single string and uses the functools utilities
[docs]def requires(requires, msg=""):
"""Decorator for class method to check if an attribute exist
.. doctest::
>>> from easydev.decorators import requires
>>> class Test(object):
... def __init__(self):
... self.m = 1
... self.x = 1
... @requires(['m','x'], "set the m attribute first")
... def printthis(self):
... print(self.m+self.x)
>>> t = Test()
>>> t.printthis()
2
"""
if isinstance(requires, str):
requires = [requires]
elif isinstance(requires, list) == False:
raise TypeError("First argument of the /requires/ decorator must be a" +
"string or list of string representing the required attributes" +
"to be found in your class. Second argument is a " +
"complementary message. ")
def actualDecorator(f):
@wraps(f)
def wrapper(*args, **kwds):
for require in requires:
if hasattr(args[0], require) == False:
raise AttributeError("{} not found in {}. ".format(require, args[0]) + msg)
return f(*args, **kwds)
return wrapper
return actualDecorator
# could be a macro maybe
[docs]def ifpandas(func):
"""check if pandas is available. If so, just return
the function, otherwise returns dumming function
that does nothing
"""
def wrapper(*args, **kwds):
return func(*args, **kwds)
try:
import pandas
return wrapper
except Exception:
def dummy():
pass
return dummy
[docs]def ifpylab(func):
"""check if pandas is available. If so, just return
the function, otherwise returns dumming function
that does nothing
"""
# for functions
def wrapper(*args, **kwds):
return func(*args, **kwds)
# for methods
try:
import pylab
return wrapper
except Exception:
def dummy():
pass
return dummy