1 import os
2 import sys
3 __all__ = ["cliargs", "logged", "log_decorator"]
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 @decorator
27 -def cliargs(callable):
28 """
29 Decorator that parses C{sys.argv} and passes the results into the function.
30
31 Meant for functions that are a target of setuptools' automatic script
32 creation (by default, nothing is passed in, and the function must handle
33 sys.argv parsing itself). If something very simple is all that is required,
34 this is the answer. Fancier arguments should use C{getopt} or C{optparse}.
35
36 If the wrong args/kwargs are passed in such that a TypeError is raised, the
37 docstring is printed, so that's an ideal place to put usage information.
38 """
39 def inner():
40 args = sys.argv[1:]
41 opts = {}
42 prog_args = []
43 while args:
44 if args[0].startswith('-'):
45 if args[1].startswith('-'):
46 opts[args[0].lstrip('-')] = True
47 args = args[1:]
48 else:
49 opts[args[0].lstrip('-')] = args[1]
50 args = args[2:]
51 else:
52 prog_args.append(args[0])
53 args = args[1:]
54 try: return callable(*prog_args, **opts)
55 except TypeError: print callable.__doc__
56 return inner
57
59 """
60 Factory for a decorator that redirects sys.stdout to a given file-like
61 object during function execution. Thus, C{print} statements can become
62 logged statements.
63 """
64 @decorator
65 def logdecorator(callable):
66 def inner(*args, **kwargs):
67 stdout_backup = sys.stdout
68 sys.stdout = fobj
69 result = callable(*args, **kwargs)
70 sys.stdout = stdout_backup
71 return result
72 return inner
73 return logdecorator
74
76 """
77 Create a L{logged} decorator for re-use.
78
79 >>> from StringIO import StringIO
80 >>> logfile = StringIO()
81 >>> logger = log_decorator(logfile)
82 >>> @logger
83 ... def func():
84 ... print "ABCDEFGHIJK"
85 ...
86 >>> func()
87 >>> logfile.seek(0)
88 >>> logfile.read().strip()
89 'ABCDEFGHIJK'
90
91 """
92 return logged(fobj)
93
96 """
97 Factory for decorator that ensures the decorated function is run in a
98 specified directory, then changes back to original directory.
99
100 >>> import tempfile
101 >>> realpath = os.path.realpath
102 >>> new, cur = map(realpath, (tempfile.mkdtemp(), os.curdir))
103 >>> @indir(new)
104 ... def whereami():
105 ... return realpath(os.curdir)
106 ...
107 >>> whereami() == new
108 True
109 >>> realpath(os.curdir) == cur
110 True
111
112 """
113 @decorator
114 def dec(f):
115 def inner(*args, **kwargs):
116 olddir = os.path.abspath(os.curdir)
117 os.chdir(newdir)
118 result = f(*args, **kwargs)
119 os.chdir(olddir)
120 return result
121 return inner
122 return dec
123