_tempita.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. """
  2. A small templating language
  3. This implements a small templating language. This language implements
  4. if/elif/else, for/continue/break, expressions, and blocks of Python
  5. code. The syntax is::
  6. {{any expression (function calls etc)}}
  7. {{any expression | filter}}
  8. {{for x in y}}...{{endfor}}
  9. {{if x}}x{{elif y}}y{{else}}z{{endif}}
  10. {{py:x=1}}
  11. {{py:
  12. def foo(bar):
  13. return 'baz'
  14. }}
  15. {{default var = default_value}}
  16. {{# comment}}
  17. You use this with the ``Template`` class or the ``sub`` shortcut.
  18. The ``Template`` class takes the template string and the name of
  19. the template (for errors) and a default namespace. Then (like
  20. ``string.Template``) you can call the ``tmpl.substitute(**kw)``
  21. method to make a substitution (or ``tmpl.substitute(a_dict)``).
  22. ``sub(content, **kw)`` substitutes the template immediately. You
  23. can use ``__name='tmpl.html'`` to set the name of the template.
  24. If there are syntax errors ``TemplateError`` will be raised.
  25. """
  26. from __future__ import absolute_import
  27. import re
  28. import sys
  29. import cgi
  30. try:
  31. from urllib import quote as url_quote
  32. except ImportError: # Py3
  33. from urllib.parse import quote as url_quote
  34. import os
  35. import tokenize
  36. from io import StringIO
  37. from ._looper import looper
  38. from .compat3 import bytes, unicode_, basestring_, next, is_unicode, coerce_text
  39. __all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
  40. 'sub_html', 'html', 'bunch']
  41. in_re = re.compile(r'\s+in\s+')
  42. var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
  43. class TemplateError(Exception):
  44. """Exception raised while parsing a template
  45. """
  46. def __init__(self, message, position, name=None):
  47. Exception.__init__(self, message)
  48. self.position = position
  49. self.name = name
  50. def __str__(self):
  51. msg = ' '.join(self.args)
  52. if self.position:
  53. msg = '%s at line %s column %s' % (
  54. msg, self.position[0], self.position[1])
  55. if self.name:
  56. msg += ' in %s' % self.name
  57. return msg
  58. class _TemplateContinue(Exception):
  59. pass
  60. class _TemplateBreak(Exception):
  61. pass
  62. def get_file_template(name, from_template):
  63. path = os.path.join(os.path.dirname(from_template.name), name)
  64. return from_template.__class__.from_filename(
  65. path, namespace=from_template.namespace,
  66. get_template=from_template.get_template)
  67. class Template(object):
  68. default_namespace = {
  69. 'start_braces': '{{',
  70. 'end_braces': '}}',
  71. 'looper': looper,
  72. }
  73. default_encoding = 'utf8'
  74. default_inherit = None
  75. def __init__(self, content, name=None, namespace=None, stacklevel=None,
  76. get_template=None, default_inherit=None, line_offset=0,
  77. delimeters=None):
  78. self.content = content
  79. # set delimeters
  80. if delimeters is None:
  81. delimeters = (self.default_namespace['start_braces'],
  82. self.default_namespace['end_braces'])
  83. else:
  84. #assert len(delimeters) == 2 and all([isinstance(delimeter, basestring)
  85. # for delimeter in delimeters])
  86. self.default_namespace = self.__class__.default_namespace.copy()
  87. self.default_namespace['start_braces'] = delimeters[0]
  88. self.default_namespace['end_braces'] = delimeters[1]
  89. self.delimeters = delimeters
  90. self._unicode = is_unicode(content)
  91. if name is None and stacklevel is not None:
  92. try:
  93. caller = sys._getframe(stacklevel)
  94. except ValueError:
  95. pass
  96. else:
  97. globals = caller.f_globals
  98. lineno = caller.f_lineno
  99. if '__file__' in globals:
  100. name = globals['__file__']
  101. if name.endswith('.pyc') or name.endswith('.pyo'):
  102. name = name[:-1]
  103. elif '__name__' in globals:
  104. name = globals['__name__']
  105. else:
  106. name = '<string>'
  107. if lineno:
  108. name += ':%s' % lineno
  109. self.name = name
  110. self._parsed = parse(content, name=name, line_offset=line_offset, delimeters=self.delimeters)
  111. if namespace is None:
  112. namespace = {}
  113. self.namespace = namespace
  114. self.get_template = get_template
  115. if default_inherit is not None:
  116. self.default_inherit = default_inherit
  117. def from_filename(cls, filename, namespace=None, encoding=None,
  118. default_inherit=None, get_template=get_file_template):
  119. f = open(filename, 'rb')
  120. c = f.read()
  121. f.close()
  122. if encoding:
  123. c = c.decode(encoding)
  124. return cls(content=c, name=filename, namespace=namespace,
  125. default_inherit=default_inherit, get_template=get_template)
  126. from_filename = classmethod(from_filename)
  127. def __repr__(self):
  128. return '<%s %s name=%r>' % (
  129. self.__class__.__name__,
  130. hex(id(self))[2:], self.name)
  131. def substitute(self, *args, **kw):
  132. if args:
  133. if kw:
  134. raise TypeError(
  135. "You can only give positional *or* keyword arguments")
  136. if len(args) > 1:
  137. raise TypeError(
  138. "You can only give one positional argument")
  139. if not hasattr(args[0], 'items'):
  140. raise TypeError(
  141. "If you pass in a single argument, you must pass in a dictionary-like object (with a .items() method); you gave %r"
  142. % (args[0],))
  143. kw = args[0]
  144. ns = kw
  145. ns['__template_name__'] = self.name
  146. if self.namespace:
  147. ns.update(self.namespace)
  148. result, defs, inherit = self._interpret(ns)
  149. if not inherit:
  150. inherit = self.default_inherit
  151. if inherit:
  152. result = self._interpret_inherit(result, defs, inherit, ns)
  153. return result
  154. def _interpret(self, ns):
  155. __traceback_hide__ = True
  156. parts = []
  157. defs = {}
  158. self._interpret_codes(self._parsed, ns, out=parts, defs=defs)
  159. if '__inherit__' in defs:
  160. inherit = defs.pop('__inherit__')
  161. else:
  162. inherit = None
  163. return ''.join(parts), defs, inherit
  164. def _interpret_inherit(self, body, defs, inherit_template, ns):
  165. __traceback_hide__ = True
  166. if not self.get_template:
  167. raise TemplateError(
  168. 'You cannot use inheritance without passing in get_template',
  169. position=None, name=self.name)
  170. templ = self.get_template(inherit_template, self)
  171. self_ = TemplateObject(self.name)
  172. for name, value in defs.items():
  173. setattr(self_, name, value)
  174. self_.body = body
  175. ns = ns.copy()
  176. ns['self'] = self_
  177. return templ.substitute(ns)
  178. def _interpret_codes(self, codes, ns, out, defs):
  179. __traceback_hide__ = True
  180. for item in codes:
  181. if isinstance(item, basestring_):
  182. out.append(item)
  183. else:
  184. self._interpret_code(item, ns, out, defs)
  185. def _interpret_code(self, code, ns, out, defs):
  186. __traceback_hide__ = True
  187. name, pos = code[0], code[1]
  188. if name == 'py':
  189. self._exec(code[2], ns, pos)
  190. elif name == 'continue':
  191. raise _TemplateContinue()
  192. elif name == 'break':
  193. raise _TemplateBreak()
  194. elif name == 'for':
  195. vars, expr, content = code[2], code[3], code[4]
  196. expr = self._eval(expr, ns, pos)
  197. self._interpret_for(vars, expr, content, ns, out, defs)
  198. elif name == 'cond':
  199. parts = code[2:]
  200. self._interpret_if(parts, ns, out, defs)
  201. elif name == 'expr':
  202. parts = code[2].split('|')
  203. base = self._eval(parts[0], ns, pos)
  204. for part in parts[1:]:
  205. func = self._eval(part, ns, pos)
  206. base = func(base)
  207. out.append(self._repr(base, pos))
  208. elif name == 'default':
  209. var, expr = code[2], code[3]
  210. if var not in ns:
  211. result = self._eval(expr, ns, pos)
  212. ns[var] = result
  213. elif name == 'inherit':
  214. expr = code[2]
  215. value = self._eval(expr, ns, pos)
  216. defs['__inherit__'] = value
  217. elif name == 'def':
  218. name = code[2]
  219. signature = code[3]
  220. parts = code[4]
  221. ns[name] = defs[name] = TemplateDef(self, name, signature, body=parts, ns=ns,
  222. pos=pos)
  223. elif name == 'comment':
  224. return
  225. else:
  226. assert 0, "Unknown code: %r" % name
  227. def _interpret_for(self, vars, expr, content, ns, out, defs):
  228. __traceback_hide__ = True
  229. for item in expr:
  230. if len(vars) == 1:
  231. ns[vars[0]] = item
  232. else:
  233. if len(vars) != len(item):
  234. raise ValueError(
  235. 'Need %i items to unpack (got %i items)'
  236. % (len(vars), len(item)))
  237. for name, value in zip(vars, item):
  238. ns[name] = value
  239. try:
  240. self._interpret_codes(content, ns, out, defs)
  241. except _TemplateContinue:
  242. continue
  243. except _TemplateBreak:
  244. break
  245. def _interpret_if(self, parts, ns, out, defs):
  246. __traceback_hide__ = True
  247. # @@: if/else/else gets through
  248. for part in parts:
  249. assert not isinstance(part, basestring_)
  250. name, pos = part[0], part[1]
  251. if name == 'else':
  252. result = True
  253. else:
  254. result = self._eval(part[2], ns, pos)
  255. if result:
  256. self._interpret_codes(part[3], ns, out, defs)
  257. break
  258. def _eval(self, code, ns, pos):
  259. __traceback_hide__ = True
  260. try:
  261. try:
  262. value = eval(code, self.default_namespace, ns)
  263. except SyntaxError as e:
  264. raise SyntaxError(
  265. 'invalid syntax in expression: %s' % code)
  266. return value
  267. except Exception as e:
  268. if getattr(e, 'args', None):
  269. arg0 = e.args[0]
  270. else:
  271. arg0 = coerce_text(e)
  272. e.args = (self._add_line_info(arg0, pos),)
  273. raise
  274. def _exec(self, code, ns, pos):
  275. __traceback_hide__ = True
  276. try:
  277. exec(code, self.default_namespace, ns)
  278. except Exception as e:
  279. if e.args:
  280. e.args = (self._add_line_info(e.args[0], pos),)
  281. else:
  282. e.args = (self._add_line_info(None, pos),)
  283. raise
  284. def _repr(self, value, pos):
  285. __traceback_hide__ = True
  286. try:
  287. if value is None:
  288. return ''
  289. if self._unicode:
  290. try:
  291. value = unicode_(value)
  292. except UnicodeDecodeError:
  293. value = bytes(value)
  294. else:
  295. if not isinstance(value, basestring_):
  296. value = coerce_text(value)
  297. if (is_unicode(value)
  298. and self.default_encoding):
  299. value = value.encode(self.default_encoding)
  300. except Exception as e:
  301. e.args = (self._add_line_info(e.args[0], pos),)
  302. raise
  303. else:
  304. if self._unicode and isinstance(value, bytes):
  305. if not self.default_encoding:
  306. raise UnicodeDecodeError(
  307. 'Cannot decode bytes value %r into unicode '
  308. '(no default_encoding provided)' % value)
  309. try:
  310. value = value.decode(self.default_encoding)
  311. except UnicodeDecodeError as e:
  312. raise UnicodeDecodeError(
  313. e.encoding,
  314. e.object,
  315. e.start,
  316. e.end,
  317. e.reason + ' in string %r' % value)
  318. elif not self._unicode and is_unicode(value):
  319. if not self.default_encoding:
  320. raise UnicodeEncodeError(
  321. 'Cannot encode unicode value %r into bytes '
  322. '(no default_encoding provided)' % value)
  323. value = value.encode(self.default_encoding)
  324. return value
  325. def _add_line_info(self, msg, pos):
  326. msg = "%s at line %s column %s" % (
  327. msg, pos[0], pos[1])
  328. if self.name:
  329. msg += " in file %s" % self.name
  330. return msg
  331. def sub(content, delimeters=None, **kw):
  332. name = kw.get('__name')
  333. tmpl = Template(content, name=name, delimeters=delimeters)
  334. return tmpl.substitute(kw)
  335. def paste_script_template_renderer(content, vars, filename=None):
  336. tmpl = Template(content, name=filename)
  337. return tmpl.substitute(vars)
  338. class bunch(dict):
  339. def __init__(self, **kw):
  340. for name, value in kw.items():
  341. setattr(self, name, value)
  342. def __setattr__(self, name, value):
  343. self[name] = value
  344. def __getattr__(self, name):
  345. try:
  346. return self[name]
  347. except KeyError:
  348. raise AttributeError(name)
  349. def __getitem__(self, key):
  350. if 'default' in self:
  351. try:
  352. return dict.__getitem__(self, key)
  353. except KeyError:
  354. return dict.__getitem__(self, 'default')
  355. else:
  356. return dict.__getitem__(self, key)
  357. def __repr__(self):
  358. return '<%s %s>' % (
  359. self.__class__.__name__,
  360. ' '.join(['%s=%r' % (k, v) for k, v in sorted(self.items())]))
  361. ############################################################
  362. ## HTML Templating
  363. ############################################################
  364. class html(object):
  365. def __init__(self, value):
  366. self.value = value
  367. def __str__(self):
  368. return self.value
  369. def __html__(self):
  370. return self.value
  371. def __repr__(self):
  372. return '<%s %r>' % (
  373. self.__class__.__name__, self.value)
  374. def html_quote(value, force=True):
  375. if not force and hasattr(value, '__html__'):
  376. return value.__html__()
  377. if value is None:
  378. return ''
  379. if not isinstance(value, basestring_):
  380. value = coerce_text(value)
  381. if sys.version >= "3" and isinstance(value, bytes):
  382. value = cgi.escape(value.decode('latin1'), 1)
  383. value = value.encode('latin1')
  384. else:
  385. value = cgi.escape(value, 1)
  386. if sys.version < "3":
  387. if is_unicode(value):
  388. value = value.encode('ascii', 'xmlcharrefreplace')
  389. return value
  390. def url(v):
  391. v = coerce_text(v)
  392. if is_unicode(v):
  393. v = v.encode('utf8')
  394. return url_quote(v)
  395. def attr(**kw):
  396. parts = []
  397. for name, value in sorted(kw.items()):
  398. if value is None:
  399. continue
  400. if name.endswith('_'):
  401. name = name[:-1]
  402. parts.append('%s="%s"' % (html_quote(name), html_quote(value)))
  403. return html(' '.join(parts))
  404. class HTMLTemplate(Template):
  405. default_namespace = Template.default_namespace.copy()
  406. default_namespace.update(dict(
  407. html=html,
  408. attr=attr,
  409. url=url,
  410. html_quote=html_quote,
  411. ))
  412. def _repr(self, value, pos):
  413. if hasattr(value, '__html__'):
  414. value = value.__html__()
  415. quote = False
  416. else:
  417. quote = True
  418. plain = Template._repr(self, value, pos)
  419. if quote:
  420. return html_quote(plain)
  421. else:
  422. return plain
  423. def sub_html(content, **kw):
  424. name = kw.get('__name')
  425. tmpl = HTMLTemplate(content, name=name)
  426. return tmpl.substitute(kw)
  427. class TemplateDef(object):
  428. def __init__(self, template, func_name, func_signature,
  429. body, ns, pos, bound_self=None):
  430. self._template = template
  431. self._func_name = func_name
  432. self._func_signature = func_signature
  433. self._body = body
  434. self._ns = ns
  435. self._pos = pos
  436. self._bound_self = bound_self
  437. def __repr__(self):
  438. return '<tempita function %s(%s) at %s:%s>' % (
  439. self._func_name, self._func_signature,
  440. self._template.name, self._pos)
  441. def __str__(self):
  442. return self()
  443. def __call__(self, *args, **kw):
  444. values = self._parse_signature(args, kw)
  445. ns = self._ns.copy()
  446. ns.update(values)
  447. if self._bound_self is not None:
  448. ns['self'] = self._bound_self
  449. out = []
  450. subdefs = {}
  451. self._template._interpret_codes(self._body, ns, out, subdefs)
  452. return ''.join(out)
  453. def __get__(self, obj, type=None):
  454. if obj is None:
  455. return self
  456. return self.__class__(
  457. self._template, self._func_name, self._func_signature,
  458. self._body, self._ns, self._pos, bound_self=obj)
  459. def _parse_signature(self, args, kw):
  460. values = {}
  461. sig_args, var_args, var_kw, defaults = self._func_signature
  462. extra_kw = {}
  463. for name, value in kw.items():
  464. if not var_kw and name not in sig_args:
  465. raise TypeError(
  466. 'Unexpected argument %s' % name)
  467. if name in sig_args:
  468. values[sig_args] = value
  469. else:
  470. extra_kw[name] = value
  471. args = list(args)
  472. sig_args = list(sig_args)
  473. while args:
  474. while sig_args and sig_args[0] in values:
  475. sig_args.pop(0)
  476. if sig_args:
  477. name = sig_args.pop(0)
  478. values[name] = args.pop(0)
  479. elif var_args:
  480. values[var_args] = tuple(args)
  481. break
  482. else:
  483. raise TypeError(
  484. 'Extra position arguments: %s'
  485. % ', '.join([repr(v) for v in args]))
  486. for name, value_expr in defaults.items():
  487. if name not in values:
  488. values[name] = self._template._eval(
  489. value_expr, self._ns, self._pos)
  490. for name in sig_args:
  491. if name not in values:
  492. raise TypeError(
  493. 'Missing argument: %s' % name)
  494. if var_kw:
  495. values[var_kw] = extra_kw
  496. return values
  497. class TemplateObject(object):
  498. def __init__(self, name):
  499. self.__name = name
  500. self.get = TemplateObjectGetter(self)
  501. def __repr__(self):
  502. return '<%s %s>' % (self.__class__.__name__, self.__name)
  503. class TemplateObjectGetter(object):
  504. def __init__(self, template_obj):
  505. self.__template_obj = template_obj
  506. def __getattr__(self, attr):
  507. return getattr(self.__template_obj, attr, Empty)
  508. def __repr__(self):
  509. return '<%s around %r>' % (self.__class__.__name__, self.__template_obj)
  510. class _Empty(object):
  511. def __call__(self, *args, **kw):
  512. return self
  513. def __str__(self):
  514. return ''
  515. def __repr__(self):
  516. return 'Empty'
  517. def __unicode__(self):
  518. return u''
  519. def __iter__(self):
  520. return iter(())
  521. def __bool__(self):
  522. return False
  523. if sys.version < "3":
  524. __nonzero__ = __bool__
  525. Empty = _Empty()
  526. del _Empty
  527. ############################################################
  528. ## Lexing and Parsing
  529. ############################################################
  530. def lex(s, name=None, trim_whitespace=True, line_offset=0, delimeters=None):
  531. """
  532. Lex a string into chunks:
  533. >>> lex('hey')
  534. ['hey']
  535. >>> lex('hey {{you}}')
  536. ['hey ', ('you', (1, 7))]
  537. >>> lex('hey {{')
  538. Traceback (most recent call last):
  539. ...
  540. TemplateError: No }} to finish last expression at line 1 column 7
  541. >>> lex('hey }}')
  542. Traceback (most recent call last):
  543. ...
  544. TemplateError: }} outside expression at line 1 column 7
  545. >>> lex('hey {{ {{')
  546. Traceback (most recent call last):
  547. ...
  548. TemplateError: {{ inside expression at line 1 column 10
  549. """
  550. if delimeters is None:
  551. delimeters = ( Template.default_namespace['start_braces'],
  552. Template.default_namespace['end_braces'] )
  553. in_expr = False
  554. chunks = []
  555. last = 0
  556. last_pos = (line_offset + 1, 1)
  557. token_re = re.compile(r'%s|%s' % (re.escape(delimeters[0]),
  558. re.escape(delimeters[1])))
  559. for match in token_re.finditer(s):
  560. expr = match.group(0)
  561. pos = find_position(s, match.end(), last, last_pos)
  562. if expr == delimeters[0] and in_expr:
  563. raise TemplateError('%s inside expression' % delimeters[0],
  564. position=pos,
  565. name=name)
  566. elif expr == delimeters[1] and not in_expr:
  567. raise TemplateError('%s outside expression' % delimeters[1],
  568. position=pos,
  569. name=name)
  570. if expr == delimeters[0]:
  571. part = s[last:match.start()]
  572. if part:
  573. chunks.append(part)
  574. in_expr = True
  575. else:
  576. chunks.append((s[last:match.start()], last_pos))
  577. in_expr = False
  578. last = match.end()
  579. last_pos = pos
  580. if in_expr:
  581. raise TemplateError('No %s to finish last expression' % delimeters[1],
  582. name=name, position=last_pos)
  583. part = s[last:]
  584. if part:
  585. chunks.append(part)
  586. if trim_whitespace:
  587. chunks = trim_lex(chunks)
  588. return chunks
  589. statement_re = re.compile(r'^(?:if |elif |for |def |inherit |default |py:)')
  590. single_statements = ['else', 'endif', 'endfor', 'enddef', 'continue', 'break']
  591. trail_whitespace_re = re.compile(r'\n\r?[\t ]*$')
  592. lead_whitespace_re = re.compile(r'^[\t ]*\n')
  593. def trim_lex(tokens):
  594. r"""
  595. Takes a lexed set of tokens, and removes whitespace when there is
  596. a directive on a line by itself:
  597. >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False)
  598. >>> tokens
  599. [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny']
  600. >>> trim_lex(tokens)
  601. [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y']
  602. """
  603. last_trim = None
  604. for i, current in enumerate(tokens):
  605. if isinstance(current, basestring_):
  606. # we don't trim this
  607. continue
  608. item = current[0]
  609. if not statement_re.search(item) and item not in single_statements:
  610. continue
  611. if not i:
  612. prev = ''
  613. else:
  614. prev = tokens[i - 1]
  615. if i + 1 >= len(tokens):
  616. next_chunk = ''
  617. else:
  618. next_chunk = tokens[i + 1]
  619. if (not isinstance(next_chunk, basestring_)
  620. or not isinstance(prev, basestring_)):
  621. continue
  622. prev_ok = not prev or trail_whitespace_re.search(prev)
  623. if i == 1 and not prev.strip():
  624. prev_ok = True
  625. if last_trim is not None and last_trim + 2 == i and not prev.strip():
  626. prev_ok = 'last'
  627. if (prev_ok
  628. and (not next_chunk or lead_whitespace_re.search(next_chunk)
  629. or (i == len(tokens) - 2 and not next_chunk.strip()))):
  630. if prev:
  631. if ((i == 1 and not prev.strip())
  632. or prev_ok == 'last'):
  633. tokens[i - 1] = ''
  634. else:
  635. m = trail_whitespace_re.search(prev)
  636. # +1 to leave the leading \n on:
  637. prev = prev[:m.start() + 1]
  638. tokens[i - 1] = prev
  639. if next_chunk:
  640. last_trim = i
  641. if i == len(tokens) - 2 and not next_chunk.strip():
  642. tokens[i + 1] = ''
  643. else:
  644. m = lead_whitespace_re.search(next_chunk)
  645. next_chunk = next_chunk[m.end():]
  646. tokens[i + 1] = next_chunk
  647. return tokens
  648. def find_position(string, index, last_index, last_pos):
  649. """Given a string and index, return (line, column)"""
  650. lines = string.count('\n', last_index, index)
  651. if lines > 0:
  652. column = index - string.rfind('\n', last_index, index)
  653. else:
  654. column = last_pos[1] + (index - last_index)
  655. return (last_pos[0] + lines, column)
  656. def parse(s, name=None, line_offset=0, delimeters=None):
  657. r"""
  658. Parses a string into a kind of AST
  659. >>> parse('{{x}}')
  660. [('expr', (1, 3), 'x')]
  661. >>> parse('foo')
  662. ['foo']
  663. >>> parse('{{if x}}test{{endif}}')
  664. [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
  665. >>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
  666. ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
  667. >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
  668. [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
  669. >>> parse('{{py:x=1}}')
  670. [('py', (1, 3), 'x=1')]
  671. >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
  672. [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
  673. Some exceptions::
  674. >>> parse('{{continue}}')
  675. Traceback (most recent call last):
  676. ...
  677. TemplateError: continue outside of for loop at line 1 column 3
  678. >>> parse('{{if x}}foo')
  679. Traceback (most recent call last):
  680. ...
  681. TemplateError: No {{endif}} at line 1 column 3
  682. >>> parse('{{else}}')
  683. Traceback (most recent call last):
  684. ...
  685. TemplateError: else outside of an if block at line 1 column 3
  686. >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}')
  687. Traceback (most recent call last):
  688. ...
  689. TemplateError: Unexpected endif at line 1 column 25
  690. >>> parse('{{if}}{{endif}}')
  691. Traceback (most recent call last):
  692. ...
  693. TemplateError: if with no expression at line 1 column 3
  694. >>> parse('{{for x y}}{{endfor}}')
  695. Traceback (most recent call last):
  696. ...
  697. TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
  698. >>> parse('{{py:x=1\ny=2}}')
  699. Traceback (most recent call last):
  700. ...
  701. TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
  702. """
  703. if delimeters is None:
  704. delimeters = ( Template.default_namespace['start_braces'],
  705. Template.default_namespace['end_braces'] )
  706. tokens = lex(s, name=name, line_offset=line_offset, delimeters=delimeters)
  707. result = []
  708. while tokens:
  709. next_chunk, tokens = parse_expr(tokens, name)
  710. result.append(next_chunk)
  711. return result
  712. def parse_expr(tokens, name, context=()):
  713. if isinstance(tokens[0], basestring_):
  714. return tokens[0], tokens[1:]
  715. expr, pos = tokens[0]
  716. expr = expr.strip()
  717. if expr.startswith('py:'):
  718. expr = expr[3:].lstrip(' \t')
  719. if expr.startswith('\n') or expr.startswith('\r'):
  720. expr = expr.lstrip('\r\n')
  721. if '\r' in expr:
  722. expr = expr.replace('\r\n', '\n')
  723. expr = expr.replace('\r', '')
  724. expr += '\n'
  725. else:
  726. if '\n' in expr:
  727. raise TemplateError(
  728. 'Multi-line py blocks must start with a newline',
  729. position=pos, name=name)
  730. return ('py', pos, expr), tokens[1:]
  731. elif expr in ('continue', 'break'):
  732. if 'for' not in context:
  733. raise TemplateError(
  734. 'continue outside of for loop',
  735. position=pos, name=name)
  736. return (expr, pos), tokens[1:]
  737. elif expr.startswith('if '):
  738. return parse_cond(tokens, name, context)
  739. elif (expr.startswith('elif ')
  740. or expr == 'else'):
  741. raise TemplateError(
  742. '%s outside of an if block' % expr.split()[0],
  743. position=pos, name=name)
  744. elif expr in ('if', 'elif', 'for'):
  745. raise TemplateError(
  746. '%s with no expression' % expr,
  747. position=pos, name=name)
  748. elif expr in ('endif', 'endfor', 'enddef'):
  749. raise TemplateError(
  750. 'Unexpected %s' % expr,
  751. position=pos, name=name)
  752. elif expr.startswith('for '):
  753. return parse_for(tokens, name, context)
  754. elif expr.startswith('default '):
  755. return parse_default(tokens, name, context)
  756. elif expr.startswith('inherit '):
  757. return parse_inherit(tokens, name, context)
  758. elif expr.startswith('def '):
  759. return parse_def(tokens, name, context)
  760. elif expr.startswith('#'):
  761. return ('comment', pos, tokens[0][0]), tokens[1:]
  762. return ('expr', pos, tokens[0][0]), tokens[1:]
  763. def parse_cond(tokens, name, context):
  764. start = tokens[0][1]
  765. pieces = []
  766. context = context + ('if',)
  767. while 1:
  768. if not tokens:
  769. raise TemplateError(
  770. 'Missing {{endif}}',
  771. position=start, name=name)
  772. if (isinstance(tokens[0], tuple)
  773. and tokens[0][0] == 'endif'):
  774. return ('cond', start) + tuple(pieces), tokens[1:]
  775. next_chunk, tokens = parse_one_cond(tokens, name, context)
  776. pieces.append(next_chunk)
  777. def parse_one_cond(tokens, name, context):
  778. (first, pos), tokens = tokens[0], tokens[1:]
  779. content = []
  780. if first.endswith(':'):
  781. first = first[:-1]
  782. if first.startswith('if '):
  783. part = ('if', pos, first[3:].lstrip(), content)
  784. elif first.startswith('elif '):
  785. part = ('elif', pos, first[5:].lstrip(), content)
  786. elif first == 'else':
  787. part = ('else', pos, None, content)
  788. else:
  789. assert 0, "Unexpected token %r at %s" % (first, pos)
  790. while 1:
  791. if not tokens:
  792. raise TemplateError(
  793. 'No {{endif}}',
  794. position=pos, name=name)
  795. if (isinstance(tokens[0], tuple)
  796. and (tokens[0][0] == 'endif'
  797. or tokens[0][0].startswith('elif ')
  798. or tokens[0][0] == 'else')):
  799. return part, tokens
  800. next_chunk, tokens = parse_expr(tokens, name, context)
  801. content.append(next_chunk)
  802. def parse_for(tokens, name, context):
  803. first, pos = tokens[0]
  804. tokens = tokens[1:]
  805. context = ('for',) + context
  806. content = []
  807. assert first.startswith('for ')
  808. if first.endswith(':'):
  809. first = first[:-1]
  810. first = first[3:].strip()
  811. match = in_re.search(first)
  812. if not match:
  813. raise TemplateError(
  814. 'Bad for (no "in") in %r' % first,
  815. position=pos, name=name)
  816. vars = first[:match.start()]
  817. if '(' in vars:
  818. raise TemplateError(
  819. 'You cannot have () in the variable section of a for loop (%r)'
  820. % vars, position=pos, name=name)
  821. vars = tuple([
  822. v.strip() for v in first[:match.start()].split(',')
  823. if v.strip()])
  824. expr = first[match.end():]
  825. while 1:
  826. if not tokens:
  827. raise TemplateError(
  828. 'No {{endfor}}',
  829. position=pos, name=name)
  830. if (isinstance(tokens[0], tuple)
  831. and tokens[0][0] == 'endfor'):
  832. return ('for', pos, vars, expr, content), tokens[1:]
  833. next_chunk, tokens = parse_expr(tokens, name, context)
  834. content.append(next_chunk)
  835. def parse_default(tokens, name, context):
  836. first, pos = tokens[0]
  837. assert first.startswith('default ')
  838. first = first.split(None, 1)[1]
  839. parts = first.split('=', 1)
  840. if len(parts) == 1:
  841. raise TemplateError(
  842. "Expression must be {{default var=value}}; no = found in %r" % first,
  843. position=pos, name=name)
  844. var = parts[0].strip()
  845. if ',' in var:
  846. raise TemplateError(
  847. "{{default x, y = ...}} is not supported",
  848. position=pos, name=name)
  849. if not var_re.search(var):
  850. raise TemplateError(
  851. "Not a valid variable name for {{default}}: %r"
  852. % var, position=pos, name=name)
  853. expr = parts[1].strip()
  854. return ('default', pos, var, expr), tokens[1:]
  855. def parse_inherit(tokens, name, context):
  856. first, pos = tokens[0]
  857. assert first.startswith('inherit ')
  858. expr = first.split(None, 1)[1]
  859. return ('inherit', pos, expr), tokens[1:]
  860. def parse_def(tokens, name, context):
  861. first, start = tokens[0]
  862. tokens = tokens[1:]
  863. assert first.startswith('def ')
  864. first = first.split(None, 1)[1]
  865. if first.endswith(':'):
  866. first = first[:-1]
  867. if '(' not in first:
  868. func_name = first
  869. sig = ((), None, None, {})
  870. elif not first.endswith(')'):
  871. raise TemplateError("Function definition doesn't end with ): %s" % first,
  872. position=start, name=name)
  873. else:
  874. first = first[:-1]
  875. func_name, sig_text = first.split('(', 1)
  876. sig = parse_signature(sig_text, name, start)
  877. context = context + ('def',)
  878. content = []
  879. while 1:
  880. if not tokens:
  881. raise TemplateError(
  882. 'Missing {{enddef}}',
  883. position=start, name=name)
  884. if (isinstance(tokens[0], tuple)
  885. and tokens[0][0] == 'enddef'):
  886. return ('def', start, func_name, sig, content), tokens[1:]
  887. next_chunk, tokens = parse_expr(tokens, name, context)
  888. content.append(next_chunk)
  889. def parse_signature(sig_text, name, pos):
  890. tokens = tokenize.generate_tokens(StringIO(sig_text).readline)
  891. sig_args = []
  892. var_arg = None
  893. var_kw = None
  894. defaults = {}
  895. def get_token(pos=False):
  896. try:
  897. tok_type, tok_string, (srow, scol), (erow, ecol), line = next(tokens)
  898. except StopIteration:
  899. return tokenize.ENDMARKER, ''
  900. if pos:
  901. return tok_type, tok_string, (srow, scol), (erow, ecol)
  902. else:
  903. return tok_type, tok_string
  904. while 1:
  905. var_arg_type = None
  906. tok_type, tok_string = get_token()
  907. if tok_type == tokenize.ENDMARKER:
  908. break
  909. if tok_type == tokenize.OP and (tok_string == '*' or tok_string == '**'):
  910. var_arg_type = tok_string
  911. tok_type, tok_string = get_token()
  912. if tok_type != tokenize.NAME:
  913. raise TemplateError('Invalid signature: (%s)' % sig_text,
  914. position=pos, name=name)
  915. var_name = tok_string
  916. tok_type, tok_string = get_token()
  917. if tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','):
  918. if var_arg_type == '*':
  919. var_arg = var_name
  920. elif var_arg_type == '**':
  921. var_kw = var_name
  922. else:
  923. sig_args.append(var_name)
  924. if tok_type == tokenize.ENDMARKER:
  925. break
  926. continue
  927. if var_arg_type is not None:
  928. raise TemplateError('Invalid signature: (%s)' % sig_text,
  929. position=pos, name=name)
  930. if tok_type == tokenize.OP and tok_string == '=':
  931. nest_type = None
  932. unnest_type = None
  933. nest_count = 0
  934. start_pos = end_pos = None
  935. parts = []
  936. while 1:
  937. tok_type, tok_string, s, e = get_token(True)
  938. if start_pos is None:
  939. start_pos = s
  940. end_pos = e
  941. if tok_type == tokenize.ENDMARKER and nest_count:
  942. raise TemplateError('Invalid signature: (%s)' % sig_text,
  943. position=pos, name=name)
  944. if (not nest_count and
  945. (tok_type == tokenize.ENDMARKER or (tok_type == tokenize.OP and tok_string == ','))):
  946. default_expr = isolate_expression(sig_text, start_pos, end_pos)
  947. defaults[var_name] = default_expr
  948. sig_args.append(var_name)
  949. break
  950. parts.append((tok_type, tok_string))
  951. if nest_count and tok_type == tokenize.OP and tok_string == nest_type:
  952. nest_count += 1
  953. elif nest_count and tok_type == tokenize.OP and tok_string == unnest_type:
  954. nest_count -= 1
  955. if not nest_count:
  956. nest_type = unnest_type = None
  957. elif not nest_count and tok_type == tokenize.OP and tok_string in ('(', '[', '{'):
  958. nest_type = tok_string
  959. nest_count = 1
  960. unnest_type = {'(': ')', '[': ']', '{': '}'}[nest_type]
  961. return sig_args, var_arg, var_kw, defaults
  962. def isolate_expression(string, start_pos, end_pos):
  963. srow, scol = start_pos
  964. srow -= 1
  965. erow, ecol = end_pos
  966. erow -= 1
  967. lines = string.splitlines(True)
  968. if srow == erow:
  969. return lines[srow][scol:ecol]
  970. parts = [lines[srow][scol:]]
  971. parts.extend(lines[srow+1:erow])
  972. if erow < len(lines):
  973. # It'll sometimes give (end_row_past_finish, 0)
  974. parts.append(lines[erow][:ecol])
  975. return ''.join(parts)
  976. _fill_command_usage = """\
  977. %prog [OPTIONS] TEMPLATE arg=value
  978. Use py:arg=value to set a Python value; otherwise all values are
  979. strings.
  980. """
  981. def fill_command(args=None):
  982. import sys
  983. import optparse
  984. import pkg_resources
  985. import os
  986. if args is None:
  987. args = sys.argv[1:]
  988. dist = pkg_resources.get_distribution('Paste')
  989. parser = optparse.OptionParser(
  990. version=coerce_text(dist),
  991. usage=_fill_command_usage)
  992. parser.add_option(
  993. '-o', '--output',
  994. dest='output',
  995. metavar="FILENAME",
  996. help="File to write output to (default stdout)")
  997. parser.add_option(
  998. '--html',
  999. dest='use_html',
  1000. action='store_true',
  1001. help="Use HTML style filling (including automatic HTML quoting)")
  1002. parser.add_option(
  1003. '--env',
  1004. dest='use_env',
  1005. action='store_true',
  1006. help="Put the environment in as top-level variables")
  1007. options, args = parser.parse_args(args)
  1008. if len(args) < 1:
  1009. print('You must give a template filename')
  1010. sys.exit(2)
  1011. template_name = args[0]
  1012. args = args[1:]
  1013. vars = {}
  1014. if options.use_env:
  1015. vars.update(os.environ)
  1016. for value in args:
  1017. if '=' not in value:
  1018. print('Bad argument: %r' % value)
  1019. sys.exit(2)
  1020. name, value = value.split('=', 1)
  1021. if name.startswith('py:'):
  1022. name = name[:3]
  1023. value = eval(value)
  1024. vars[name] = value
  1025. if template_name == '-':
  1026. template_content = sys.stdin.read()
  1027. template_name = '<stdin>'
  1028. else:
  1029. f = open(template_name, 'rb')
  1030. template_content = f.read()
  1031. f.close()
  1032. if options.use_html:
  1033. TemplateClass = HTMLTemplate
  1034. else:
  1035. TemplateClass = Template
  1036. template = TemplateClass(template_content, name=template_name)
  1037. result = template.substitute(vars)
  1038. if options.output:
  1039. f = open(options.output, 'wb')
  1040. f.write(result)
  1041. f.close()
  1042. else:
  1043. sys.stdout.write(result)
  1044. if __name__ == '__main__':
  1045. fill_command()