_tempita.py 39 KB

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