1 import os
2 import sys
3 __all__ = ["cliargs", "redirect", "redirect_decorator", "CLIargsError"]
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
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
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
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
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