Package cliutils :: Module decorators
[hide private]
[frames] | no frames]

Source Code for Module cliutils.decorators

  1  import os 
  2  import sys 
  3  __all__ = ["cliargs", "redirect", "redirect_decorator", "CLIargsError"] 
4 5 -def decorator(callable):
6 """ 7 Simple meta-decorator that makes decorators preserve the attributes of the 8 modified function. 9 10 Stolen from innumerable online recipes, but most directly from 11 U{http://wiki.python.org/moin/PythonDecoratorLibrary}. 12 """ 13 def inner(f): 14 dec = callable(f) 15 dec.__name__ = f.__name__ 16 dec.__doc__ = f.__doc__ 17 dec.__module__ = f.__module__ 18 dec.__dict__.update(f.__dict__) 19 return dec
20 inner.__name__ = callable.__name__ 21 inner.__module__ = callable.__module__ 22 inner.__doc__ = callable.__doc__ 23 inner.__dict__.update(callable.__dict__) 24 return inner 25
26 27 -class CLIargsError(Exception):
28 "Arguments were not passed in correctly."
29
30 31 @decorator 32 -def cliargs(callable):
33 """ 34 Decorator that parses C{sys.argv} and passes the results into the function. 35 36 Meant for functions that are a target of setuptools' automatic script 37 creation (by default, nothing is passed in, and the function must handle 38 sys.argv parsing itself). If something very simple is all that is required, 39 this is the answer. Fancier arguments should use C{getopt} or C{optparse}. 40 41 If the wrong args/kwargs are passed in such that a TypeError is raised, the 42 docstring is printed, so that's an ideal place to put usage information. 43 """ 44 def inner(): 45 args = sys.argv[1:] 46 opts = {} 47 prog_args = [] 48 while args: 49 if args[0].startswith('-'): 50 if args[1].startswith('-'): 51 opts[args[0].lstrip('-')] = True 52 args = args[1:] 53 else: 54 opts[args[0].lstrip('-')] = args[1] 55 args = args[2:] 56 else: 57 prog_args.append(args[0]) 58 args = args[1:] 59 try: 60 try: 61 return callable(*prog_args, **opts) 62 except TypeError, e: 63 raise CLIargsError(e) 64 except CLIargsError: 65 print callable.__doc__
66 return inner 67
68 69 -def redirect(fobj):
70 """ 71 Factory for a decorator that redirects sys.stdout to a given file-like 72 object during function execution. Thus, C{print} statements can become 73 logged statements. 74 75 >>> from StringIO import StringIO 76 >>> logfile = StringIO() 77 >>> logger = redirect(logfile) 78 >>> @logger 79 ... def func(): 80 ... print "ABCDEFGHIJK" 81 ... 82 >>> func() 83 >>> logfile.seek(0) 84 >>> logfile.read().strip() 85 'ABCDEFGHIJK' 86 87 """ 88 @decorator 89 def logdecorator(callable): 90 def inner(*args, **kwargs): 91 stdout_backup = sys.stdout 92 sys.stdout = fobj 93 result = callable(*args, **kwargs) 94 sys.stdout = stdout_backup 95 return result
96 return inner 97 return logdecorator 98
99 100 -def indir(newdir):
101 """ 102 Factory for decorator that ensures the decorated function is run in a 103 specified directory, then changes back to original directory. 104 105 >>> import tempfile 106 >>> realpath = os.path.realpath 107 >>> new, cur = map(realpath, (tempfile.mkdtemp(), os.curdir)) 108 >>> @indir(new) 109 ... def whereami(): 110 ... return realpath(os.curdir) 111 ... 112 >>> whereami() == new 113 True 114 >>> realpath(os.curdir) == cur 115 True 116 117 """ 118 @decorator 119 def dec(f): 120 def inner(*args, **kwargs): 121 olddir = os.path.abspath(os.curdir) 122 os.chdir(newdir) 123 result = f(*args, **kwargs) 124 os.chdir(olddir) 125 return result
126 return inner 127 return dec 128
129 130 -def logged(fobj):
131 """ 132 Provided for backwards compatibility with pre-0.1.3. 133 Will be removed in 0.1.5. 134 """ 135 import warnings 136 warnings.warn('The logged decorator is deprecated. Please use redirect' 137 ' instead.', DeprecationWarning, stacklevel=2) 138 return redirect(fobj)
139 log_decorator = logged 140