_tempita.py 36 KB

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