3 from __future__ import with_statement
18 def printfmt(template):
20 This hides having to create the Template object and call substitute/safe_substitute on it. For example:
24 >>> printfmt("I would like to order $num units of $word, please") #doctest: +SKIP
25 I would like to order 10 units of spam, please
27 frame = inspect.stack()[-1][0]
29 print string.Template(template).safe_substitute(frame.f_locals)
35 return name.startswith("__") and name.endswith("__")
39 return name.startswith("_") and not is_special(name)
42 def privatize(clsName, attributeName):
44 At runtime, make an attributeName private
47 >>> class Test(object):
51 ... dir(Test).index("_Test__me")
56 >>> setattr(Test, privatize(Test.__name__, "me"), "Hello World")
58 ... dir(Test).index("_Test__me")
64 >>> print getattr(Test, obfuscate(Test.__name__, "__me"))
67 >>> is_private(privatize(Test.__name__, "me"))
69 >>> is_special(privatize(Test.__name__, "me"))
72 return "".join(["_", clsName, "__", attributeName])
75 def obfuscate(clsName, attributeName):
77 At runtime, turn a private name into the obfuscated form
80 >>> class Test(object):
81 ... __me = "Hello World"
84 ... dir(Test).index("_Test__me")
90 >>> print getattr(Test, obfuscate(Test.__name__, "__me"))
92 >>> is_private(obfuscate(Test.__name__, "__me"))
94 >>> is_special(obfuscate(Test.__name__, "__me"))
97 return "".join(["_", clsName, attributeName])
100 class PAOptionParser(optparse.OptionParser, object):
102 >>> if __name__ == '__main__':
103 ... #parser = PAOptionParser("My usage str")
104 ... parser = PAOptionParser()
105 ... parser.add_posarg("Foo", help="Foo usage")
106 ... parser.add_posarg("Bar", dest="bar_dest")
107 ... parser.add_posarg("Language", dest='tr_type', type="choice", choices=("Python", "Other"))
108 ... parser.add_option('--stocksym', dest='symbol')
109 ... values, args = parser.parse_args()
110 ... print values, args
116 python mycp.py foo bar
118 python mycp.py foo bar lava
119 Usage: pa.py <Foo> <Bar> <Language> [options]
121 Positional Arguments:
126 pa.py: error: option --Language: invalid choice: 'lava' (choose from 'Python', 'Other'
129 def __init__(self, *args, **kw):
131 super(PAOptionParser, self).__init__(*args, **kw)
133 def add_posarg(self, *args, **kw):
134 pa_help = kw.get("help", "")
135 kw["help"] = optparse.SUPPRESS_HELP
136 o = self.add_option("--%s" % args[0], *args[1:], **kw)
137 self.posargs.append((args[0], pa_help))
139 def get_usage(self, *args, **kwargs):
140 params = (' '.join(["<%s>" % arg[0] for arg in self.posargs]), '\n '.join(["%s: %s" % (arg) for arg in self.posargs]))
141 self.usage = "%%prog %s [options]\n\nPositional Arguments:\n %s" % params
142 return super(PAOptionParser, self).get_usage(*args, **kwargs)
144 def parse_args(self, *args, **kwargs):
147 for p, v in zip(self.posargs, args):
148 args0.append("--%s" % p[0])
151 options, args = super(PAOptionParser, self).parse_args(args, **kwargs)
152 if len(args) < len(self.posargs):
153 msg = 'Missing value(s) for "%s"\n' % ", ".join([arg[0] for arg in self.posargs][len(args):])
158 def explicitly(name, stackadd=0):
160 This is an alias for adding to '__all__'. Less error-prone than using
161 __all__ itself, since setting __all__ directly is prone to stomping on
162 things implicitly exported via L{alias}.
164 @note Taken from PyExport (which could turn out pretty cool):
165 @li @a http://codebrowse.launchpad.net/~glyph/
166 @li @a http://glyf.livejournal.com/74356.html
168 packageVars = sys._getframe(1+stackadd).f_locals
169 globalAll = packageVars.setdefault('__all__', [])
170 globalAll.append(name)
175 This is a decorator, for convenience. Rather than typing the name of your
176 function twice, you can decorate a function with this.
178 To be real, @public would need to work on methods as well, which gets into
181 @note Taken from PyExport (which could turn out pretty cool):
182 @li @a http://codebrowse.launchpad.net/~glyph/
183 @li @a http://glyf.livejournal.com/74356.html
185 explicitly(thunk.__name__, 1)
189 def _append_docstring(obj, message):
190 if obj.__doc__ is None:
191 obj.__doc__ = message
193 obj.__doc__ += message
196 def validate_decorator(decorator):
204 f.__dict__["member"] = True
208 if f.__name__ != g.__name__:
209 print f.__name__, "!=", g.__name__
211 if g.__doc__ is None:
212 print decorator.__name__, "has no doc string"
213 elif not g.__doc__.startswith(f.__doc__):
214 print g.__doc__, "didn't start with", f.__doc__
216 if not ("member" in g.__dict__ and g.__dict__["member"]):
217 print "'member' not in ", g.__dict__
220 def deprecated_api(func):
222 This is a decorator which can be used to mark functions
223 as deprecated. It will result in a warning being emitted
224 when the function is used.
226 >>> validate_decorator(deprecated_api)
229 @functools.wraps(func)
230 def newFunc(*args, **kwargs):
231 warnings.warn("Call to deprecated function %s." % func.__name__, category=DeprecationWarning)
232 return func(*args, **kwargs)
234 _append_docstring(newFunc, "\n@deprecated")
238 def unstable_api(func):
240 This is a decorator which can be used to mark functions
241 as deprecated. It will result in a warning being emitted
242 when the function is used.
244 >>> validate_decorator(unstable_api)
247 @functools.wraps(func)
248 def newFunc(*args, **kwargs):
249 warnings.warn("Call to unstable API function %s." % func.__name__, category=FutureWarning)
250 return func(*args, **kwargs)
251 _append_docstring(newFunc, "\n@unstable")
257 This decorator doesn't add any behavior
259 >>> validate_decorator(enabled)
266 This decorator disables the provided function, and does nothing
268 >>> validate_decorator(disabled)
271 @functools.wraps(func)
272 def emptyFunc(*args, **kargs):
274 _append_docstring(emptyFunc, "\n@note Temporarily Disabled")
278 def metadata(document=True, **kwds):
280 >>> validate_decorator(metadata(author="Ed"))
284 for k, v in kwds.iteritems():
287 _append_docstring(func, "\n@"+k+" "+v)
293 """Function decorator for defining property attributes
295 The decorated function is expected to return a dictionary
296 containing one or more of the following pairs:
297 fget - function for getting attribute value
298 fset - function for setting attribute value
299 fdel - function for deleting attribute
300 This can be conveniently constructed by the locals() builtin
302 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/205183
303 @author http://kbyanc.blogspot.com/2007/06/python-property-attribute-tricks.html
306 >>> #Due to transformation from function to property, does not need to be validated
307 >>> #validate_decorator(prop)
308 >>> class MyExampleClass(object):
311 ... "The foo property attribute's doc-string"
315 ... def fset(self, value):
317 ... self._foo = value
320 >>> me = MyExampleClass()
327 return property(doc=func.__doc__, **func())
330 def print_handler(e):
334 print "%s: %s" % (type(e).__name__, e)
341 print 'Ignoring %s exception: %s' % (type(e).__name__, e)
344 def print_traceback(e):
348 #print sys.exc_info()
349 traceback.print_exc(file=sys.stdout)
352 def ExpHandler(handler = print_handler, *exceptions):
354 An exception handling idiom using decorators
356 Specify exceptions in order, first one is handled first
359 >>> validate_decorator(ExpHandler())
360 >>> @ExpHandler(print_ignore, ZeroDivisionError)
361 ... @ExpHandler(None, AttributeError, ValueError)
364 >>> @ExpHandler(print_traceback, ZeroDivisionError)
371 >>> @ExpHandler(print_traceback, ZeroDivisionError)
377 Ignoring ZeroDivisionError exception: integer division or modulo by zero
378 >>> f2() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
379 Traceback (most recent call last):
381 ZeroDivisionError: integer division or modulo by zero
383 IndexError: tuple index out of range
389 localExceptions = exceptions
390 if not localExceptions:
391 localExceptions = [Exception]
392 t = [(ex, handler) for ex in localExceptions]
395 def newfunc(t, *args, **kwargs):
399 return f(*args, **kwargs)
401 #Recurse for embedded try/excepts
402 dec_func = functools.partial(newfunc, t[1:])
403 dec_func = functools.update_wrapper(dec_func, f)
404 return dec_func(*args, **kwargs)
408 dec_func = functools.partial(newfunc, t)
409 dec_func = functools.update_wrapper(dec_func, f)
414 def into_debugger(func):
416 >>> validate_decorator(into_debugger)
419 @functools.wraps(func)
420 def newFunc(*args, **kwargs):
422 return func(*args, **kwargs)
430 class bindclass(object):
432 >>> validate_decorator(bindclass)
433 >>> class Foo(BoundObject):
435 ... def foo(this_class, self):
436 ... return this_class, self
440 ... def bar(this_class, self):
441 ... return this_class, self
446 >>> f.foo() # doctest: +ELLIPSIS
447 (<class '...Foo'>, <...Foo object at ...>)
448 >>> b.foo() # doctest: +ELLIPSIS
449 (<class '...Foo'>, <...Bar object at ...>)
450 >>> b.bar() # doctest: +ELLIPSIS
451 (<class '...Bar'>, <...Bar object at ...>)
454 def __init__(self, f):
456 self.__name__ = f.__name__
457 self.__doc__ = f.__doc__
458 self.__dict__.update(f.__dict__)
461 def bind(self, cls, attr):
463 def bound_m(*args, **kwargs):
464 return self.f(cls, *args, **kwargs)
465 bound_m.__name__ = attr
468 def __get__(self, obj, objtype=None):
469 return self.m.__get__(obj, objtype)
472 class ClassBindingSupport(type):
475 def __init__(mcs, name, bases, attrs):
476 type.__init__(mcs, name, bases, attrs)
477 for attr, val in attrs.iteritems():
478 if isinstance(val, bindclass):
482 class BoundObject(object):
484 __metaclass__ = ClassBindingSupport
489 >>> validate_decorator(bindfunction)
491 ... def factorial(thisfunction, n):
492 ... # Within this function the name 'thisfunction' refers to the factorial
493 ... # function(with only one argument), even after 'factorial' is bound
494 ... # to another object
496 ... return n * thisfunction(n - 1)
505 def bound_f(*args, **kwargs):
506 return f(bound_f, *args, **kwargs)
510 class Memoize(object):
512 Memoize(fn) - an instance which acts like fn but memoizes its arguments
513 Will only work on functions with non-mutable arguments
514 @note Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52201
516 >>> validate_decorator(Memoize)
519 def __init__(self, fn):
521 self.__name__ = fn.__name__
522 self.__doc__ = fn.__doc__
523 self.__dict__.update(fn.__dict__)
526 def __call__(self, *args):
527 if args not in self.memo:
528 self.memo[args] = self.fn(*args)
529 return self.memo[args]
532 class MemoizeMutable(object):
533 """Memoize(fn) - an instance which acts like fn but memoizes its arguments
534 Will work on functions with mutable arguments(slower than Memoize)
535 @note Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52201
537 >>> validate_decorator(MemoizeMutable)
540 def __init__(self, fn):
542 self.__name__ = fn.__name__
543 self.__doc__ = fn.__doc__
544 self.__dict__.update(fn.__dict__)
547 def __call__(self, *args, **kw):
548 text = cPickle.dumps((args, kw))
549 if text not in self.memo:
550 self.memo[text] = self.fn(*args, **kw)
551 return self.memo[text]
554 callTraceIndentationLevel = 0
559 Synchronization decorator.
561 >>> validate_decorator(call_trace)
566 Entering a((1, 2), {'c': 3})
567 Exiting a((1, 2), {'c': 3})
571 def verboseTrace(*args, **kw):
572 global callTraceIndentationLevel
574 print "%sEntering %s(%s, %s)" % ("\t"*callTraceIndentationLevel, f.__name__, args, kw)
575 callTraceIndentationLevel += 1
577 result = f(*args, **kw)
579 callTraceIndentationLevel -= 1
580 print "%sException %s(%s, %s)" % ("\t"*callTraceIndentationLevel, f.__name__, args, kw)
582 callTraceIndentationLevel -= 1
583 print "%sExiting %s(%s, %s)" % ("\t"*callTraceIndentationLevel, f.__name__, args, kw)
587 def smallTrace(*args, **kw):
588 global callTraceIndentationLevel
590 print "%sEntering %s" % ("\t"*callTraceIndentationLevel, f.__name__)
591 callTraceIndentationLevel += 1
593 result = f(*args, **kw)
595 callTraceIndentationLevel -= 1
596 print "%sException %s" % ("\t"*callTraceIndentationLevel, f.__name__)
598 callTraceIndentationLevel -= 1
599 print "%sExiting %s" % ("\t"*callTraceIndentationLevel, f.__name__)
606 @contextlib.contextmanager
607 def lexical_scope(*args):
609 @note Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/520586
612 >>> with lexical_scope(1) as (a):
616 >>> with lexical_scope(1,2,3) as (a,b,c):
620 >>> with lexical_scope():
629 frame = inspect.currentframe().f_back.f_back
630 saved = frame.f_locals.keys()
639 f_locals = frame.f_locals
640 for key in (x for x in f_locals.keys() if x not in saved):
645 def strip_number(prettynumber):
647 function to take a phone number and strip out all non-numeric
650 >>> strip_number("+012-(345)-678-90")
654 uglynumber = re.sub('\D', '', prettynumber)