annotate corebio/_future/_string.py @ 7:8d676bbd1f2d

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