OLD | NEW |
| (Empty) |
1 """A copy of the string Template class from python 2.4, included | |
2 for compatibility with python 2.3. | |
3 """ | |
4 | |
5 import re as _re | |
6 | |
7 class _multimap: | |
8 """Helper class for combining multiple mappings. | |
9 | |
10 Used by .{safe_,}substitute() to combine the mapping and keyword | |
11 arguments. | |
12 """ | |
13 def __init__(self, primary, secondary): | |
14 self._primary = primary | |
15 self._secondary = secondary | |
16 | |
17 def __getitem__(self, key): | |
18 try: | |
19 return self._primary[key] | |
20 except KeyError: | |
21 return self._secondary[key] | |
22 | |
23 | |
24 class _TemplateMetaclass(type): | |
25 pattern = r""" | |
26 %(delim)s(?: | |
27 (?P<escaped>%(delim)s) | # Escape sequence of two delimiters | |
28 (?P<named>%(id)s) | # delimiter and a Python identifier | |
29 {(?P<braced>%(id)s)} | # delimiter and a braced identifier | |
30 (?P<invalid>) # Other ill-formed delimiter exprs | |
31 ) | |
32 """ | |
33 | |
34 def __init__(cls, name, bases, dct): | |
35 super(_TemplateMetaclass, cls).__init__(name, bases, dct) | |
36 if 'pattern' in dct: | |
37 pattern = cls.pattern | |
38 else: | |
39 pattern = _TemplateMetaclass.pattern % { | |
40 'delim' : _re.escape(cls.delimiter), | |
41 'id' : cls.idpattern, | |
42 } | |
43 cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE) | |
44 | |
45 | |
46 class Template: | |
47 """A string class for supporting $-substitutions.""" | |
48 __metaclass__ = _TemplateMetaclass | |
49 | |
50 delimiter = '$' | |
51 idpattern = r'[_a-z][_a-z0-9]*' | |
52 | |
53 def __init__(self, template): | |
54 self.template = template | |
55 | |
56 # Search for $$, $identifier, ${identifier}, and any bare $'s | |
57 | |
58 def _invalid(self, mo): | |
59 i = mo.start('invalid') | |
60 lines = self.template[:i].splitlines(True) | |
61 if not lines: | |
62 colno = 1 | |
63 lineno = 1 | |
64 else: | |
65 colno = i - len(''.join(lines[:-1])) | |
66 lineno = len(lines) | |
67 raise ValueError('Invalid placeholder in string: line %d, col %d' % | |
68 (lineno, colno)) | |
69 | |
70 def substitute(self, *args, **kws): | |
71 if len(args) > 1: | |
72 raise TypeError('Too many positional arguments') | |
73 if not args: | |
74 mapping = kws | |
75 elif kws: | |
76 mapping = _multimap(kws, args[0]) | |
77 else: | |
78 mapping = args[0] | |
79 # Helper function for .sub() | |
80 def convert(mo): | |
81 # Check the most common path first. | |
82 named = mo.group('named') or mo.group('braced') | |
83 if named is not None: | |
84 val = mapping[named] | |
85 # We use this idiom instead of str() because the latter will | |
86 # fail if val is a Unicode containing non-ASCII characters. | |
87 return '%s' % val | |
88 if mo.group('escaped') is not None: | |
89 return self.delimiter | |
90 if mo.group('invalid') is not None: | |
91 self._invalid(mo) | |
92 raise ValueError('Unrecognized named group in pattern', | |
93 self.pattern) | |
94 return self.pattern.sub(convert, self.template) | |
95 | |
96 def safe_substitute(self, *args, **kws): | |
97 if len(args) > 1: | |
98 raise TypeError('Too many positional arguments') | |
99 if not args: | |
100 mapping = kws | |
101 elif kws: | |
102 mapping = _multimap(kws, args[0]) | |
103 else: | |
104 mapping = args[0] | |
105 # Helper function for .sub() | |
106 def convert(mo): | |
107 named = mo.group('named') | |
108 if named is not None: | |
109 try: | |
110 # We use this idiom instead of str() because the latter | |
111 # will fail if val is a Unicode containing non-ASCII | |
112 return '%s' % mapping[named] | |
113 except KeyError: | |
114 return self.delimiter + named | |
115 braced = mo.group('braced') | |
116 if braced is not None: | |
117 try: | |
118 return '%s' % mapping[braced] | |
119 except KeyError: | |
120 return self.delimiter + '{' + braced + '}' | |
121 if mo.group('escaped') is not None: | |
122 return self.delimiter | |
123 if mo.group('invalid') is not None: | |
124 return self.delimiter | |
125 raise ValueError('Unrecognized named group in pattern', | |
126 self.pattern) | |
127 return self.pattern.sub(convert, self.template) | |
128 | |
129 | |
OLD | NEW |