PageRenderTime 69ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 0ms

/Tanto/src/mako/util.py

https://bitbucket.org/verilab/tanto
Python | 426 lines | 382 code | 23 blank | 21 comment | 32 complexity | 13e9ade23c32b59b785b61bd1e699d1a MD5 | raw file
  1. # mako/util.py
  2. # Copyright (C) 2006-2012 the Mako authors and contributors <see AUTHORS file>
  3. #
  4. # This module is part of Mako and is released under
  5. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  6. import imp
  7. import sys
  8. py3k = getattr(sys, 'py3kwarning', False) or sys.version_info >= (3, 0)
  9. py24 = sys.version_info >= (2, 4) and sys.version_info < (2, 5)
  10. jython = sys.platform.startswith('java')
  11. win32 = sys.platform.startswith('win')
  12. if py3k:
  13. from io import StringIO
  14. else:
  15. try:
  16. from cStringIO import StringIO
  17. except:
  18. from StringIO import StringIO
  19. import codecs, re, weakref, os, time, operator
  20. import collections
  21. try:
  22. import threading
  23. import thread
  24. except ImportError:
  25. import dummy_threading as threading
  26. import dummy_thread as thread
  27. if win32 or jython:
  28. time_func = time.clock
  29. else:
  30. time_func = time.time
  31. def function_named(fn, name):
  32. """Return a function with a given __name__.
  33. Will assign to __name__ and return the original function if possible on
  34. the Python implementation, otherwise a new function will be constructed.
  35. """
  36. fn.__name__ = name
  37. return fn
  38. try:
  39. from functools import partial
  40. except:
  41. def partial(func, *args, **keywords):
  42. def newfunc(*fargs, **fkeywords):
  43. newkeywords = keywords.copy()
  44. newkeywords.update(fkeywords)
  45. return func(*(args + fargs), **newkeywords)
  46. return newfunc
  47. if py24:
  48. def exception_name(exc):
  49. try:
  50. return exc.__class__.__name__
  51. except AttributeError:
  52. return exc.__name__
  53. else:
  54. def exception_name(exc):
  55. return exc.__class__.__name__
  56. class PluginLoader(object):
  57. def __init__(self, group):
  58. self.group = group
  59. self.impls = {}
  60. def load(self, name):
  61. if name in self.impls:
  62. return self.impls[name]()
  63. else:
  64. import pkg_resources
  65. for impl in pkg_resources.iter_entry_points(
  66. self.group,
  67. name):
  68. self.impls[name] = impl.load
  69. return impl.load()
  70. else:
  71. raise exceptions.RuntimeException(
  72. "Can't load plugin %s %s" %
  73. (self.group, name))
  74. def register(self, name, modulepath, objname):
  75. def load():
  76. mod = __import__(modulepath)
  77. for token in modulepath.split(".")[1:]:
  78. mod = getattr(mod, token)
  79. return getattr(mod, objname)
  80. self.impls[name] = load
  81. def verify_directory(dir):
  82. """create and/or verify a filesystem directory."""
  83. tries = 0
  84. while not os.path.exists(dir):
  85. try:
  86. tries += 1
  87. os.makedirs(dir, 0775)
  88. except:
  89. if tries > 5:
  90. raise
  91. def to_list(x, default=None):
  92. if x is None:
  93. return default
  94. if not isinstance(x, (list, tuple)):
  95. return [x]
  96. else:
  97. return x
  98. class memoized_property(object):
  99. """A read-only @property that is only evaluated once."""
  100. def __init__(self, fget, doc=None):
  101. self.fget = fget
  102. self.__doc__ = doc or fget.__doc__
  103. self.__name__ = fget.__name__
  104. def __get__(self, obj, cls):
  105. if obj is None:
  106. return self
  107. obj.__dict__[self.__name__] = result = self.fget(obj)
  108. return result
  109. class memoized_instancemethod(object):
  110. """Decorate a method memoize its return value.
  111. Best applied to no-arg methods: memoization is not sensitive to
  112. argument values, and will always return the same value even when
  113. called with different arguments.
  114. """
  115. def __init__(self, fget, doc=None):
  116. self.fget = fget
  117. self.__doc__ = doc or fget.__doc__
  118. self.__name__ = fget.__name__
  119. def __get__(self, obj, cls):
  120. if obj is None:
  121. return self
  122. def oneshot(*args, **kw):
  123. result = self.fget(obj, *args, **kw)
  124. memo = lambda *a, **kw: result
  125. memo.__name__ = self.__name__
  126. memo.__doc__ = self.__doc__
  127. obj.__dict__[self.__name__] = memo
  128. return result
  129. oneshot.__name__ = self.__name__
  130. oneshot.__doc__ = self.__doc__
  131. return oneshot
  132. class SetLikeDict(dict):
  133. """a dictionary that has some setlike methods on it"""
  134. def union(self, other):
  135. """produce a 'union' of this dict and another (at the key level).
  136. values in the second dict take precedence over that of the first"""
  137. x = SetLikeDict(**self)
  138. x.update(other)
  139. return x
  140. class FastEncodingBuffer(object):
  141. """a very rudimentary buffer that is faster than StringIO,
  142. but doesn't crash on unicode data like cStringIO."""
  143. def __init__(self, encoding=None, errors='strict', unicode=False):
  144. self.data = collections.deque()
  145. self.encoding = encoding
  146. if unicode:
  147. self.delim = u''
  148. else:
  149. self.delim = ''
  150. self.unicode = unicode
  151. self.errors = errors
  152. self.write = self.data.append
  153. def truncate(self):
  154. self.data = collections.deque()
  155. self.write = self.data.append
  156. def getvalue(self):
  157. if self.encoding:
  158. return self.delim.join(self.data).encode(self.encoding,
  159. self.errors)
  160. else:
  161. return self.delim.join(self.data)
  162. class LRUCache(dict):
  163. """A dictionary-like object that stores a limited number of items,
  164. discarding lesser used items periodically.
  165. this is a rewrite of LRUCache from Myghty to use a periodic timestamp-based
  166. paradigm so that synchronization is not really needed. the size management
  167. is inexact.
  168. """
  169. class _Item(object):
  170. def __init__(self, key, value):
  171. self.key = key
  172. self.value = value
  173. self.timestamp = time_func()
  174. def __repr__(self):
  175. return repr(self.value)
  176. def __init__(self, capacity, threshold=.5):
  177. self.capacity = capacity
  178. self.threshold = threshold
  179. def __getitem__(self, key):
  180. item = dict.__getitem__(self, key)
  181. item.timestamp = time_func()
  182. return item.value
  183. def values(self):
  184. return [i.value for i in dict.values(self)]
  185. def setdefault(self, key, value):
  186. if key in self:
  187. return self[key]
  188. else:
  189. self[key] = value
  190. return value
  191. def __setitem__(self, key, value):
  192. item = dict.get(self, key)
  193. if item is None:
  194. item = self._Item(key, value)
  195. dict.__setitem__(self, key, item)
  196. else:
  197. item.value = value
  198. self._manage_size()
  199. def _manage_size(self):
  200. while len(self) > self.capacity + self.capacity * self.threshold:
  201. bytime = sorted(dict.values(self),
  202. key=operator.attrgetter('timestamp'), reverse=True)
  203. for item in bytime[self.capacity:]:
  204. try:
  205. del self[item.key]
  206. except KeyError:
  207. # if we couldn't find a key, most likely some other thread
  208. # broke in on us. loop around and try again
  209. break
  210. # Regexp to match python magic encoding line
  211. _PYTHON_MAGIC_COMMENT_re = re.compile(
  212. r'[ \t\f]* \# .* coding[=:][ \t]*([-\w.]+)',
  213. re.VERBOSE)
  214. def parse_encoding(fp):
  215. """Deduce the encoding of a Python source file (binary mode) from magic
  216. comment.
  217. It does this in the same way as the `Python interpreter`__
  218. .. __: http://docs.python.org/ref/encodings.html
  219. The ``fp`` argument should be a seekable file object in binary mode.
  220. """
  221. pos = fp.tell()
  222. fp.seek(0)
  223. try:
  224. line1 = fp.readline()
  225. has_bom = line1.startswith(codecs.BOM_UTF8)
  226. if has_bom:
  227. line1 = line1[len(codecs.BOM_UTF8):]
  228. m = _PYTHON_MAGIC_COMMENT_re.match(line1.decode('ascii', 'ignore'))
  229. if not m:
  230. try:
  231. import parser
  232. parser.suite(line1.decode('ascii', 'ignore'))
  233. except (ImportError, SyntaxError):
  234. # Either it's a real syntax error, in which case the source
  235. # is not valid python source, or line2 is a continuation of
  236. # line1, in which case we don't want to scan line2 for a magic
  237. # comment.
  238. pass
  239. else:
  240. line2 = fp.readline()
  241. m = _PYTHON_MAGIC_COMMENT_re.match(
  242. line2.decode('ascii', 'ignore'))
  243. if has_bom:
  244. if m:
  245. raise SyntaxError, \
  246. "python refuses to compile code with both a UTF8" \
  247. " byte-order-mark and a magic encoding comment"
  248. return 'utf_8'
  249. elif m:
  250. return m.group(1)
  251. else:
  252. return None
  253. finally:
  254. fp.seek(pos)
  255. def sorted_dict_repr(d):
  256. """repr() a dictionary with the keys in order.
  257. Used by the lexer unit test to compare parse trees based on strings.
  258. """
  259. keys = d.keys()
  260. keys.sort()
  261. return "{" + ", ".join(["%r: %r" % (k, d[k]) for k in keys]) + "}"
  262. def restore__ast(_ast):
  263. """Attempt to restore the required classes to the _ast module if it
  264. appears to be missing them
  265. """
  266. if hasattr(_ast, 'AST'):
  267. return
  268. _ast.PyCF_ONLY_AST = 2 << 9
  269. m = compile("""\
  270. def foo(): pass
  271. class Bar(object): pass
  272. if False: pass
  273. baz = 'mako'
  274. 1 + 2 - 3 * 4 / 5
  275. 6 // 7 % 8 << 9 >> 10
  276. 11 & 12 ^ 13 | 14
  277. 15 and 16 or 17
  278. -baz + (not +18) - ~17
  279. baz and 'foo' or 'bar'
  280. (mako is baz == baz) is not baz != mako
  281. mako > baz < mako >= baz <= mako
  282. mako in baz not in mako""", '<unknown>', 'exec', _ast.PyCF_ONLY_AST)
  283. _ast.Module = type(m)
  284. for cls in _ast.Module.__mro__:
  285. if cls.__name__ == 'mod':
  286. _ast.mod = cls
  287. elif cls.__name__ == 'AST':
  288. _ast.AST = cls
  289. _ast.FunctionDef = type(m.body[0])
  290. _ast.ClassDef = type(m.body[1])
  291. _ast.If = type(m.body[2])
  292. _ast.Name = type(m.body[3].targets[0])
  293. _ast.Store = type(m.body[3].targets[0].ctx)
  294. _ast.Str = type(m.body[3].value)
  295. _ast.Sub = type(m.body[4].value.op)
  296. _ast.Add = type(m.body[4].value.left.op)
  297. _ast.Div = type(m.body[4].value.right.op)
  298. _ast.Mult = type(m.body[4].value.right.left.op)
  299. _ast.RShift = type(m.body[5].value.op)
  300. _ast.LShift = type(m.body[5].value.left.op)
  301. _ast.Mod = type(m.body[5].value.left.left.op)
  302. _ast.FloorDiv = type(m.body[5].value.left.left.left.op)
  303. _ast.BitOr = type(m.body[6].value.op)
  304. _ast.BitXor = type(m.body[6].value.left.op)
  305. _ast.BitAnd = type(m.body[6].value.left.left.op)
  306. _ast.Or = type(m.body[7].value.op)
  307. _ast.And = type(m.body[7].value.values[0].op)
  308. _ast.Invert = type(m.body[8].value.right.op)
  309. _ast.Not = type(m.body[8].value.left.right.op)
  310. _ast.UAdd = type(m.body[8].value.left.right.operand.op)
  311. _ast.USub = type(m.body[8].value.left.left.op)
  312. _ast.Or = type(m.body[9].value.op)
  313. _ast.And = type(m.body[9].value.values[0].op)
  314. _ast.IsNot = type(m.body[10].value.ops[0])
  315. _ast.NotEq = type(m.body[10].value.ops[1])
  316. _ast.Is = type(m.body[10].value.left.ops[0])
  317. _ast.Eq = type(m.body[10].value.left.ops[1])
  318. _ast.Gt = type(m.body[11].value.ops[0])
  319. _ast.Lt = type(m.body[11].value.ops[1])
  320. _ast.GtE = type(m.body[11].value.ops[2])
  321. _ast.LtE = type(m.body[11].value.ops[3])
  322. _ast.In = type(m.body[12].value.ops[0])
  323. _ast.NotIn = type(m.body[12].value.ops[1])
  324. try:
  325. from inspect import CO_VARKEYWORDS, CO_VARARGS
  326. def inspect_func_args(fn):
  327. co = fn.func_code
  328. nargs = co.co_argcount
  329. names = co.co_varnames
  330. args = list(names[:nargs])
  331. varargs = None
  332. if co.co_flags & CO_VARARGS:
  333. varargs = co.co_varnames[nargs]
  334. nargs = nargs + 1
  335. varkw = None
  336. if co.co_flags & CO_VARKEYWORDS:
  337. varkw = co.co_varnames[nargs]
  338. return args, varargs, varkw, fn.func_defaults
  339. except ImportError:
  340. import inspect
  341. def inspect_func_args(fn):
  342. return inspect.getargspec(fn)
  343. def read_file(path, mode='rb'):
  344. fp = open(path, mode)
  345. try:
  346. data = fp.read()
  347. return data
  348. finally:
  349. fp.close()
  350. def load_module(module_id, path):
  351. fp = open(path, 'rb')
  352. try:
  353. return imp.load_source(module_id, path, fp)
  354. finally:
  355. fp.close()