📄 utils.py
字号:
"""General Utilities(part of web.py)"""__all__ = [ "Storage", "storage", "storify", "iters", "rstrips", "lstrips", "strips", "utf8", "TimeoutError", "timelimit", "Memoize", "memoize", "re_compile", "re_subm", "group", "IterBetter", "iterbetter", "dictreverse", "dictfind", "dictfindall", "dictincr", "dictadd", "listget", "intget", "datestr", "numify", "denumify", "dateify", "CaptureStdout", "capturestdout", "Profile", "profile", "tryall", "ThreadedDict", "autoassign", "to36", "safemarkdown"]import re, sys, time, threadingtry: import datetimeexcept ImportError: passclass Storage(dict): """ A Storage object is like a dictionary except `obj.foo` can be used in addition to `obj['foo']`. >>> o = storage(a=1) >>> o.a 1 >>> o['a'] 1 >>> o.a = 2 >>> o['a'] 2 >>> del o.a >>> o.a Traceback (most recent call last): ... AttributeError: 'a' """ def __getattr__(self, key): try: return self[key] except KeyError, k: raise AttributeError, k def __setattr__(self, key, value): self[key] = value def __delattr__(self, key): try: del self[key] except KeyError, k: raise AttributeError, k def __repr__(self): return '<Storage ' + dict.__repr__(self) + '>'storage = Storagedef storify(mapping, *requireds, **defaults): """ Creates a `storage` object from dictionary `mapping`, raising `KeyError` if d doesn't have all of the keys in `requireds` and using the default values for keys found in `defaults`. For example, `storify({'a':1, 'c':3}, b=2, c=0)` will return the equivalent of `storage({'a':1, 'b':2, 'c':3})`. If a `storify` value is a list (e.g. multiple values in a form submission), `storify` returns the last element of the list, unless the key appears in `defaults` as a list. Thus: >>> storify({'a':[1, 2]}).a 2 >>> storify({'a':[1, 2]}, a=[]).a [1, 2] >>> storify({'a':1}, a=[]).a [1] >>> storify({}, a=[]).a [] Similarly, if the value has a `value` attribute, `storify will return _its_ value, unless the key appears in `defaults` as a dictionary. >>> storify({'a':storage(value=1)}).a 1 >>> storify({'a':storage(value=1)}, a={}).a <Storage {'value': 1}> >>> storify({}, a={}).a {} """ def getvalue(x): if hasattr(x, 'value'): return x.value else: return x stor = Storage() for key in requireds + tuple(mapping.keys()): value = mapping[key] if isinstance(value, list): if isinstance(defaults.get(key), list): value = [getvalue(x) for x in value] else: value = value[-1] if not isinstance(defaults.get(key), dict): value = getvalue(value) if isinstance(defaults.get(key), list) and not isinstance(value, list): value = [value] setattr(stor, key, value) for (key, value) in defaults.iteritems(): result = value if hasattr(stor, key): result = stor[key] if value == () and not isinstance(result, tuple): result = (result,) setattr(stor, key, result) return storiters = [list, tuple]import __builtin__if hasattr(__builtin__, 'set'): iters.append(set)try: from sets import Set iters.append(Set)except ImportError: passclass _hack(tuple): passiters = _hack(iters)iters.__doc__ = """A list of iterable items (like lists, but not strings). Includes whicheverof lists, tuples, sets, and Sets are available in this version of Python."""def _strips(direction, text, remove): if direction == 'l': if text.startswith(remove): return text[len(remove):] elif direction == 'r': if text.endswith(remove): return text[:-len(remove)] else: raise ValueError, "Direction needs to be r or l." return textdef rstrips(text, remove): """ removes the string `remove` from the right of `text` >>> rstrips("foobar", "bar") 'foo' """ return _strips('r', text, remove)def lstrips(text, remove): """ removes the string `remove` from the left of `text` >>> lstrips("foobar", "foo") 'bar' """ return _strips('l', text, remove)def strips(text, remove): """removes the string `remove` from the both sides of `text` >>> strips("foobarfoo", "foo") 'bar' """ return rstrips(lstrips(text, remove), remove)def utf8(text): """Encodes text in utf-8. >> utf8(u'\u1234') # doctest doesn't seem to like utf-8 '\xe1\x88\xb4' >>> utf8('hello') 'hello' >>> utf8(42) '42' """ if isinstance(text, unicode): return text.encode('utf-8') elif isinstance(text, str): return text else: return str(text)class TimeoutError(Exception): passdef timelimit(timeout): """ A decorator to limit a function to `timeout` seconds, raising `TimeoutError` if it takes longer. >>> import time >>> def meaningoflife(): ... time.sleep(.2) ... return 42 >>> >>> timelimit(.1)(meaningoflife)() Traceback (most recent call last): ... TimeoutError: took too long >>> timelimit(1)(meaningoflife)() 42 _Caveat:_ The function isn't stopped after `timeout` seconds but continues executing in a separate thread. (There seems to be no way to kill a thread.) inspired by <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/473878> """ def _1(function): def _2(*args, **kw): class Dispatch(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.result = None self.error = None self.setDaemon(True) self.start() def run(self): try: self.result = function(*args, **kw) except: self.error = sys.exc_info() c = Dispatch() c.join(timeout) if c.isAlive(): raise TimeoutError, 'took too long' if c.error: raise c.error[0], c.error[1] return c.result return _2 return _1class Memoize: """ 'Memoizes' a function, caching its return values for each input. >>> import time >>> def meaningoflife(): ... time.sleep(.2) ... return 42 >>> fastlife = memoize(meaningoflife) >>> meaningoflife() 42 >>> timelimit(.1)(meaningoflife)() Traceback (most recent call last): ... TimeoutError: took too long >>> fastlife() 42 >>> timelimit(.1)(fastlife)() 42 """ def __init__(self, func): self.func = func self.cache = {} def __call__(self, *args, **keywords): key = (args, tuple(keywords.items())) if key not in self.cache: self.cache[key] = self.func(*args, **keywords) return self.cache[key]memoize = Memoizere_compile = memoize(re.compile) #@@ threadsafe?re_compile.__doc__ = """A memoized version of re.compile."""class _re_subm_proxy: def __init__(self): self.match = None def __call__(self, match): self.match = match return ''def re_subm(pat, repl, string): """ Like re.sub, but returns the replacement _and_ the match object. >>> t, m = re_subm('g(oo+)fball', r'f\\1lish', 'goooooofball') >>> t 'foooooolish' >>> m.groups() ('oooooo',) """ compiled_pat = re_compile(pat) proxy = _re_subm_proxy() compiled_pat.sub(proxy.__call__, string) return compiled_pat.sub(repl, string), proxy.matchdef group(seq, size): """ Returns an iterator over a series of lists of length size from iterable. >>> list(group([1,2,3,4], 2)) [[1, 2], [3, 4]] """ if not hasattr(seq, 'next'): seq = iter(seq) while True: yield [seq.next() for i in xrange(size)]class IterBetter: """ Returns an object that can be used as an iterator but can also be used via __getitem__ (although it cannot go backwards -- that is, you cannot request `iterbetter[0]` after requesting `iterbetter[1]`). >>> import itertools >>> c = iterbetter(itertools.count()) >>> c[1] 1 >>> c[5] 5 >>> c[3] Traceback (most recent call last): ... IndexError: already passed 3 """ def __init__(self, iterator): self.i, self.c = iterator, 0 def __iter__(self): while 1: yield self.i.next() self.c += 1 def __getitem__(self, i): #todo: slices if i < self.c: raise IndexError, "already passed "+str(i) try: while i > self.c: self.i.next() self.c += 1 # now self.c == i self.c += 1 return self.i.next() except StopIteration: raise IndexError, str(i)iterbetter = IterBetterdef dictreverse(mapping): """ >>> dictreverse({1: 2, 3: 4}) {2: 1, 4: 3} """ return dict([(value, key) for (key, value) in mapping.iteritems()])def dictfind(dictionary, element): """ Returns a key whose value in `dictionary` is `element` or, if none exists, None. >>> d = {1:2, 3:4} >>> dictfind(d, 4) 3 >>> dictfind(d, 5) """ for (key, value) in dictionary.iteritems(): if element is value: return keydef dictfindall(dictionary, element): """ Returns the keys whose values in `dictionary` are `element` or, if none exists, []. >>> d = {1:4, 3:4} >>> dictfindall(d, 4) [1, 3] >>> dictfindall(d, 5) [] """
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -