annotate genshi/template/interpolation.py @ 902:09cc3627654c experimental-inline

Sync `experimental/inline` branch with [source:trunk@1126].
author cmlenz
date Fri, 23 Apr 2010 21:08:26 +0000
parents 1837f39efd6f
children
rev   line source
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
1 # -*- coding: utf-8 -*-
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
2 #
902
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
3 # Copyright (C) 2007-2009 Edgewall Software
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
4 # All rights reserved.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
5 #
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
6 # This software is licensed as described in the file COPYING, which
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
7 # you should have received as part of this distribution. The terms
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
8 # are also available at http://genshi.edgewall.org/wiki/License.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
9 #
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
10 # This software consists of voluntary contributions made by many
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
11 # individuals. For the exact contribution history, see the revision
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
12 # history and logs, available at http://genshi.edgewall.org/log/.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
13
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
14 """String interpolation routines, i.e. the splitting up a given text into some
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
15 parts that are literal strings, and others that are Python expressions.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
16 """
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
17
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
18 from itertools import chain
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
19 import os
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
20 import re
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
21 from tokenize import PseudoToken
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
22
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
23 from genshi.core import TEXT
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
24 from genshi.template.base import TemplateSyntaxError, EXPR
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
25 from genshi.template.eval import Expression
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
26
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
27 __all__ = ['interpolate']
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
28 __docformat__ = 'restructuredtext en'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
29
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
30 NAMESTART = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
31 NAMECHARS = NAMESTART + '.0123456789'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
32 PREFIX = '$'
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
33
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
34 token_re = re.compile('%s|%s(?s)' % (
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
35 r'[uU]?[rR]?("""|\'\'\')((?<!\\)\\\1|.)*?\1',
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
36 PseudoToken
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
37 ))
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
38
902
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
39
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
40 def interpolate(text, filepath=None, lineno=-1, offset=0, lookup='strict'):
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
41 """Parse the given string and extract expressions.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
42
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
43 This function is a generator that yields `TEXT` events for literal strings,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
44 and `EXPR` events for expressions, depending on the results of parsing the
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
45 string.
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
46
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
47 >>> for kind, data, pos in interpolate("hey ${foo}bar"):
902
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
48 ... print('%s %r' % (kind, data))
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
49 TEXT 'hey '
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
50 EXPR Expression('foo')
902
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
51 TEXT 'bar'
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
52
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
53 :param text: the text to parse
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
54 :param filepath: absolute path to the file in which the text was found
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
55 (optional)
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
56 :param lineno: the line number at which the text was found (optional)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
57 :param offset: the column number at which the text starts in the source
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
58 (optional)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
59 :param lookup: the variable lookup mechanism; either "lenient" (the
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
60 default), "strict", or a custom lookup class
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
61 :return: a list of `TEXT` and `EXPR` events
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
62 :raise TemplateSyntaxError: when a syntax error in an expression is
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
63 encountered
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
64 """
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
65 pos = [filepath, lineno, offset]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
66
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
67 textbuf = []
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
68 textpos = None
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
69 for is_expr, chunk in chain(lex(text, pos, filepath), [(True, '')]):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
70 if is_expr:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
71 if textbuf:
902
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
72 yield TEXT, ''.join(textbuf), textpos
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
73 del textbuf[:]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
74 textpos = None
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
75 if chunk:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
76 try:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
77 expr = Expression(chunk.strip(), pos[0], pos[1],
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
78 lookup=lookup)
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
79 yield EXPR, expr, tuple(pos)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
80 except SyntaxError, err:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
81 raise TemplateSyntaxError(err, filepath, pos[1],
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
82 pos[2] + (err.offset or 0))
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
83 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
84 textbuf.append(chunk)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
85 if textpos is None:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
86 textpos = tuple(pos)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
87
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
88 if '\n' in chunk:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
89 lines = chunk.splitlines()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
90 pos[1] += len(lines) - 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
91 pos[2] += len(lines[-1])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
92 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
93 pos[2] += len(chunk)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
94
902
09cc3627654c Sync `experimental/inline` branch with [source:trunk@1126].
cmlenz
parents: 820
diff changeset
95
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
96 def lex(text, textpos, filepath):
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
97 offset = pos = 0
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
98 end = len(text)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
99 escaped = False
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
100
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
101 while 1:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
102 if escaped:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
103 offset = text.find(PREFIX, offset + 2)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
104 escaped = False
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
105 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
106 offset = text.find(PREFIX, pos)
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
107 if offset < 0 or offset == end - 1:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
108 break
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
109 next = text[offset + 1]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
110
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
111 if next == '{':
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
112 if offset > pos:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
113 yield False, text[pos:offset]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
114 pos = offset + 2
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
115 level = 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
116 while level:
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
117 match = token_re.match(text, pos)
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
118 if match is None:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
119 raise TemplateSyntaxError('invalid syntax', filepath,
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
120 *textpos[1:])
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
121 pos = match.end()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
122 tstart, tend = match.regs[3]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
123 token = text[tstart:tend]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
124 if token == '{':
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
125 level += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
126 elif token == '}':
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
127 level -= 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
128 yield True, text[offset + 2:pos - 1]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
129
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
130 elif next in NAMESTART:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
131 if offset > pos:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
132 yield False, text[pos:offset]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
133 pos = offset
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
134 pos += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
135 while pos < end:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
136 char = text[pos]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
137 if char not in NAMECHARS:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
138 break
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
139 pos += 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
140 yield True, text[offset + 1:pos].strip()
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
141
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
142 elif not escaped and next == PREFIX:
820
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
143 if offset > pos:
1837f39efd6f Sync (old) experimental inline branch with trunk@1027.
cmlenz
parents: 500
diff changeset
144 yield False, text[pos:offset]
500
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
145 escaped = True
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
146 pos = offset + 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
147
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
148 else:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
149 yield False, text[pos:offset + 1]
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
150 pos = offset + 1
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
151
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
152 if pos < end:
0742f421caba Merged revisions 487-603 via svnmerge from
cmlenz
parents:
diff changeset
153 yield False, text[pos:]
Copyright (C) 2012-2017 Edgewall Software