__init__.py 39 KB

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