summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/sre.py9
-rw-r--r--Lib/sre_constants.py3
-rw-r--r--Lib/sre_parse.py34
-rw-r--r--Lib/string.py140
-rw-r--r--Lib/test/test_pep292.py84
5 files changed, 205 insertions, 65 deletions
diff --git a/Lib/sre.py b/Lib/sre.py
index bb4bc16..8bf0fad 100644
--- a/Lib/sre.py
+++ b/Lib/sre.py
@@ -105,9 +105,6 @@ __all__ = [ "match", "search", "sub", "subn", "split", "findall",
__version__ = "2.2.1"
-# this module works under 1.5.2 and later. don't use string methods
-import string
-
# flags
I = IGNORECASE = sre_compile.SRE_FLAG_IGNORECASE # ignore case
L = LOCALE = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale
@@ -201,7 +198,7 @@ def escape(pattern):
s[i] = "\\000"
else:
s[i] = "\\" + c
- return _join(s, pattern)
+ return pattern[:0].join(s)
# --------------------------------------------------------------------
# internals
@@ -213,10 +210,6 @@ _pattern_type = type(sre_compile.compile("", 0))
_MAXCACHE = 100
-def _join(seq, sep):
- # internal: join into string having the same type as sep
- return string.join(seq, sep[:0])
-
def _compile(*key):
# internal: compile pattern
cachekey = (type(key[0]),) + key
diff --git a/Lib/sre_constants.py b/Lib/sre_constants.py
index 002b195..1863f48 100644
--- a/Lib/sre_constants.py
+++ b/Lib/sre_constants.py
@@ -217,12 +217,11 @@ SRE_INFO_LITERAL = 2 # entire pattern is literal (given by prefix)
SRE_INFO_CHARSET = 4 # pattern starts with character from given set
if __name__ == "__main__":
- import string
def dump(f, d, prefix):
items = d.items()
items.sort(key=lambda a: a[1])
for k, v in items:
- f.write("#define %s_%s %s\n" % (prefix, string.upper(k), v))
+ f.write("#define %s_%s %s\n" % (prefix, k.upper(), v))
f = open("sre_constants.h", "w")
f.write("""\
/*
diff --git a/Lib/sre_parse.py b/Lib/sre_parse.py
index 94d526d..5c4298a 100644
--- a/Lib/sre_parse.py
+++ b/Lib/sre_parse.py
@@ -12,8 +12,7 @@
# XXX: show string offset and offending character for all errors
-# this module works under 1.5.2 and later. don't use string methods
-import string, sys
+import sys
from sre_constants import *
@@ -63,13 +62,6 @@ FLAGS = {
"u": SRE_FLAG_UNICODE,
}
-# figure out best way to convert hex/octal numbers to integers
-try:
- int("10", 8)
- atoi = int # 2.0 and later
-except TypeError:
- atoi = string.atoi # 1.5.2
-
class Pattern:
# master pattern object. keeps track of global attributes
def __init__(self):
@@ -233,7 +225,7 @@ def isname(name):
def _group(escape, groups):
# check if the escape string represents a valid group
try:
- gid = atoi(escape[1:])
+ gid = int(escape[1:])
if gid and gid < groups:
return gid
except ValueError:
@@ -256,13 +248,13 @@ def _class_escape(source, escape):
escape = escape[2:]
if len(escape) != 2:
raise error, "bogus escape: %s" % repr("\\" + escape)
- return LITERAL, atoi(escape, 16) & 0xff
+ return LITERAL, int(escape, 16) & 0xff
elif escape[1:2] in OCTDIGITS:
# octal escape (up to three digits)
while source.next in OCTDIGITS and len(escape) < 5:
escape = escape + source.get()
escape = escape[1:]
- return LITERAL, atoi(escape, 8) & 0xff
+ return LITERAL, int(escape, 8) & 0xff
if len(escape) == 2:
return LITERAL, ord(escape[1])
except ValueError:
@@ -284,12 +276,12 @@ def _escape(source, escape, state):
escape = escape + source.get()
if len(escape) != 4:
raise ValueError
- return LITERAL, atoi(escape[2:], 16) & 0xff
+ return LITERAL, int(escape[2:], 16) & 0xff
elif escape[1:2] == "0":
# octal escape
while source.next in OCTDIGITS and len(escape) < 4:
escape = escape + source.get()
- return LITERAL, atoi(escape[1:], 8) & 0xff
+ return LITERAL, int(escape[1:], 8) & 0xff
elif escape[1:2] in DIGITS:
# octal escape *or* decimal group reference (sigh)
if source.next in DIGITS:
@@ -298,7 +290,7 @@ def _escape(source, escape, state):
source.next in OCTDIGITS):
# got three octal digits; this is an octal escape
escape = escape + source.get()
- return LITERAL, atoi(escape[1:], 8) & 0xff
+ return LITERAL, int(escape[1:], 8) & 0xff
# got at least one decimal digit; this is a group reference
group = _group(escape, state.groups)
if group:
@@ -503,9 +495,9 @@ def _parse(source, state):
source.seek(here)
continue
if lo:
- min = atoi(lo)
+ min = int(lo)
if hi:
- max = atoi(hi)
+ max = int(hi)
if max < min:
raise error, "bad repeat interval"
else:
@@ -617,7 +609,7 @@ def _parse(source, state):
raise error, "unknown group name"
else:
try:
- condgroup = atoi(condname)
+ condgroup = int(condname)
except ValueError:
raise error, "bad character in group name"
else:
@@ -730,7 +722,7 @@ def parse_template(source, pattern):
if not name:
raise error, "bad group name"
try:
- index = atoi(name)
+ index = int(name)
except ValueError:
if not isname(name):
raise error, "bad character in group name"
@@ -754,7 +746,7 @@ def parse_template(source, pattern):
break
if not code:
this = this[1:]
- code = LITERAL, makechar(atoi(this[-6:], 8) & 0xff)
+ code = LITERAL, makechar(int(this[-6:], 8) & 0xff)
if code[0] is LITERAL:
literal(code[1])
else:
@@ -793,4 +785,4 @@ def expand_template(template, match):
raise IndexError
except IndexError:
raise error, "empty group"
- return string.join(literals, sep)
+ return sep.join(literals)
diff --git a/Lib/string.py b/Lib/string.py
index bc10c20..d166f38 100644
--- a/Lib/string.py
+++ b/Lib/string.py
@@ -35,10 +35,116 @@ printable = digits + letters + punctuation + whitespace
# Case conversion helpers
# Use str to convert Unicode literal in case of -U
+# Note that Cookie.py bogusly uses _idmap :(
l = map(chr, xrange(256))
_idmap = str('').join(l)
del l
+# Functions which aren't available as string methods.
+
+# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
+# See also regsub.capwords().
+def capwords(s, sep=None):
+ """capwords(s, [sep]) -> string
+
+ Split the argument into words using split, capitalize each
+ word using capitalize, and join the capitalized words using
+ join. Note that this replaces runs of whitespace characters by
+ a single space.
+
+ """
+ return (sep or ' ').join([x.capitalize() for x in s.split(sep)])
+
+
+# Construct a translation string
+_idmapL = None
+def maketrans(fromstr, tostr):
+ """maketrans(frm, to) -> string
+
+ Return a translation table (a string of 256 bytes long)
+ suitable for use in string.translate. The strings frm and to
+ must be of the same length.
+
+ """
+ if len(fromstr) != len(tostr):
+ raise ValueError, "maketrans arguments must have same length"
+ global _idmapL
+ if not _idmapL:
+ _idmapL = map(None, _idmap)
+ L = _idmapL[:]
+ fromstr = map(ord, fromstr)
+ for i in range(len(fromstr)):
+ L[fromstr[i]] = tostr[i]
+ return ''.join(L)
+
+
+
+import re as _re
+
+class Template(unicode):
+ """A string class for supporting $-substitutions."""
+ __slots__ = []
+
+ # Search for $$, $identifier, ${identifier}, and any bare $'s
+ pattern = _re.compile(r"""
+# Match exactly two $'s -- this is the escape sequence
+(?P<escaped>\${2})|
+# Match a $ followed by a Python identifier
+\$(?P<named>[_a-z][_a-z0-9]*)|
+# Match a $ followed by a brace delimited identifier
+\${(?P<braced>[_a-z][_a-z0-9]*)}|
+# Match any other $'s
+(?P<bogus>\$)
+""", _re.IGNORECASE | _re.VERBOSE)
+
+ def __mod__(self, mapping):
+ def convert(mo):
+ groups = mo.groupdict()
+ if groups.get('escaped') is not None:
+ return '$'
+ if groups.get('bogus') is not None:
+ raise ValueError('Invalid placeholder at index %d' %
+ mo.start('bogus'))
+ val = mapping[groups.get('named') or groups.get('braced')]
+ return unicode(val)
+ return self.pattern.sub(convert, self)
+
+
+class SafeTemplate(Template):
+ """A string class for supporting $-substitutions.
+
+ This class is 'safe' in the sense that you will never get KeyErrors if
+ there are placeholders missing from the interpolation dictionary. In that
+ case, you will get the original placeholder in the value string.
+ """
+ __slots__ = []
+
+ def __mod__(self, mapping):
+ def convert(mo):
+ groups = mo.groupdict()
+ if groups.get('escaped') is not None:
+ return '$'
+ if groups.get('bogus') is not None:
+ raise ValueError('Invalid placeholder at index %d' %
+ mo.start('bogus'))
+ named = groups.get('named')
+ if named is not None:
+ try:
+ return unicode(mapping[named])
+ except KeyError:
+ return '$' + named
+ braced = groups.get('braced')
+ try:
+ return unicode(mapping[braced])
+ except KeyError:
+ return '${' + braced + '}'
+ return self.pattern.sub(convert, self)
+
+
+
+# NOTE: Everything below here is deprecated. Use string methods instead.
+# This stuff will go away in Python 3.0.
+
# Backward compatible names for exceptions
index_error = ValueError
atoi_error = ValueError
@@ -336,40 +442,6 @@ def capitalize(s):
"""
return s.capitalize()
-# Capitalize the words in a string, e.g. " aBc dEf " -> "Abc Def".
-# See also regsub.capwords().
-def capwords(s, sep=None):
- """capwords(s, [sep]) -> string
-
- Split the argument into words using split, capitalize each
- word using capitalize, and join the capitalized words using
- join. Note that this replaces runs of whitespace characters by
- a single space.
-
- """
- return join(map(capitalize, s.split(sep)), sep or ' ')
-
-# Construct a translation string
-_idmapL = None
-def maketrans(fromstr, tostr):
- """maketrans(frm, to) -> string
-
- Return a translation table (a string of 256 bytes long)
- suitable for use in string.translate. The strings frm and to
- must be of the same length.
-
- """
- if len(fromstr) != len(tostr):
- raise ValueError, "maketrans arguments must have same length"
- global _idmapL
- if not _idmapL:
- _idmapL = map(None, _idmap)
- L = _idmapL[:]
- fromstr = map(ord, fromstr)
- for i in range(len(fromstr)):
- L[fromstr[i]] = tostr[i]
- return join(L, "")
-
# Substring replacement (global)
def replace(s, old, new, maxsplit=-1):
"""replace (str, old, new[, maxsplit]) -> string
diff --git a/Lib/test/test_pep292.py b/Lib/test/test_pep292.py
new file mode 100644
index 0000000..7eff309
--- /dev/null
+++ b/Lib/test/test_pep292.py
@@ -0,0 +1,84 @@
+# Copyright (C) 2004 Python Software Foundation
+# Author: barry@python.org (Barry Warsaw)
+# License: http://www.opensource.org/licenses/PythonSoftFoundation.php
+
+import unittest
+from string import Template, SafeTemplate
+
+class TestTemplate(unittest.TestCase):
+
+ def test_regular_templates(self):
+ s = Template('$who likes to eat a bag of $what worth $$100')
+ self.assertEqual(s % dict(who='tim', what='ham'),
+ 'tim likes to eat a bag of ham worth $100')
+ self.assertRaises(KeyError, lambda s, d: s % d, s, dict(who='tim'))
+
+ def test_regular_templates_with_braces(self):
+ s = Template('$who likes ${what} for ${meal}')
+ self.assertEqual(s % dict(who='tim', what='ham', meal='dinner'),
+ 'tim likes ham for dinner')
+ self.assertRaises(KeyError, lambda s, d: s % d,
+ s, dict(who='tim', what='ham'))
+
+ def test_escapes(self):
+ eq = self.assertEqual
+ s = Template('$who likes to eat a bag of $$what worth $$100')
+ eq(s % dict(who='tim', what='ham'),
+ 'tim likes to eat a bag of $what worth $100')
+ s = Template('$who likes $$')
+ eq(s % dict(who='tim', what='ham'), 'tim likes $')
+
+ def test_percents(self):
+ s = Template('%(foo)s $foo ${foo}')
+ self.assertEqual(s % dict(foo='baz'), '%(foo)s baz baz')
+ s = SafeTemplate('%(foo)s $foo ${foo}')
+ self.assertEqual(s % dict(foo='baz'), '%(foo)s baz baz')
+
+ def test_stringification(self):
+ s = Template('tim has eaten $count bags of ham today')
+ self.assertEqual(s % dict(count=7),
+ 'tim has eaten 7 bags of ham today')
+ s = SafeTemplate('tim has eaten $count bags of ham today')
+ self.assertEqual(s % dict(count=7),
+ 'tim has eaten 7 bags of ham today')
+ s = SafeTemplate('tim has eaten ${count} bags of ham today')
+ self.assertEqual(s % dict(count=7),
+ 'tim has eaten 7 bags of ham today')
+
+ def test_SafeTemplate(self):
+ eq = self.assertEqual
+ s = SafeTemplate('$who likes ${what} for ${meal}')
+ eq(s % dict(who='tim'),
+ 'tim likes ${what} for ${meal}')
+ eq(s % dict(what='ham'),
+ '$who likes ham for ${meal}')
+ eq(s % dict(what='ham', meal='dinner'),
+ '$who likes ham for dinner')
+ eq(s % dict(who='tim', what='ham'),
+ 'tim likes ham for ${meal}')
+ eq(s % dict(who='tim', what='ham', meal='dinner'),
+ 'tim likes ham for dinner')
+
+ def test_invalid_placeholders(self):
+ raises = self.assertRaises
+ s = Template('$who likes $')
+ raises(ValueError, lambda s, d: s % d, s, dict(who='tim'))
+ s = Template('$who likes ${what)')
+ raises(ValueError, lambda s, d: s % d, s, dict(who='tim'))
+ s = Template('$who likes $100')
+ raises(ValueError, lambda s, d: s % d, s, dict(who='tim'))
+
+
+def suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestTemplate))
+ return suite
+
+
+def test_main():
+ from test import test_support
+ test_support.run_suite(suite())
+
+
+if __name__ == '__main__':
+ unittest.main()