1import unittest 2import string 3from string import Template 4from test import test_support, string_tests 5from UserList import UserList 6 7class StringTest( 8 string_tests.CommonTest, 9 string_tests.MixinStrStringUserStringTest 10 ): 11 12 type2test = str 13 14 def checkequal(self, result, object, methodname, *args): 15 realresult = getattr(string, methodname)(object, *args) 16 self.assertEqual( 17 result, 18 realresult 19 ) 20 21 def checkraises(self, exc, obj, methodname, *args): 22 with self.assertRaises(exc) as cm: 23 getattr(string, methodname)(obj, *args) 24 self.assertNotEqual(cm.exception.args[0], '') 25 26 def checkcall(self, object, methodname, *args): 27 getattr(string, methodname)(object, *args) 28 29 def test_join(self): 30 # These are the same checks as in string_test.ObjectTest.test_join 31 # but the argument order ist different 32 self.checkequal('a b c d', ['a', 'b', 'c', 'd'], 'join', ' ') 33 self.checkequal('abcd', ('a', 'b', 'c', 'd'), 'join', '') 34 self.checkequal('w x y z', string_tests.Sequence(), 'join', ' ') 35 self.checkequal('abc', ('abc',), 'join', 'a') 36 self.checkequal('z', UserList(['z']), 'join', 'a') 37 if test_support.have_unicode: 38 self.checkequal(unicode('a.b.c'), ['a', 'b', 'c'], 'join', unicode('.')) 39 self.checkequal(unicode('a.b.c'), [unicode('a'), 'b', 'c'], 'join', '.') 40 self.checkequal(unicode('a.b.c'), ['a', unicode('b'), 'c'], 'join', '.') 41 self.checkequal(unicode('a.b.c'), ['a', 'b', unicode('c')], 'join', '.') 42 self.checkraises(TypeError, ['a', unicode('b'), 3], 'join', '.') 43 for i in [5, 25, 125]: 44 self.checkequal( 45 ((('a' * i) + '-') * i)[:-1], 46 ['a' * i] * i, 'join', '-') 47 self.checkequal( 48 ((('a' * i) + '-') * i)[:-1], 49 ('a' * i,) * i, 'join', '-') 50 51 self.checkraises(TypeError, string_tests.BadSeq1(), 'join', ' ') 52 self.checkequal('a b c', string_tests.BadSeq2(), 'join', ' ') 53 try: 54 def f(): 55 yield 4 + "" 56 self.fixtype(' ').join(f()) 57 except TypeError, e: 58 if '+' not in str(e): 59 self.fail('join() ate exception message') 60 else: 61 self.fail('exception not raised') 62 63 64class ModuleTest(unittest.TestCase): 65 66 def test_attrs(self): 67 string.whitespace 68 string.lowercase 69 string.uppercase 70 string.letters 71 string.digits 72 string.hexdigits 73 string.octdigits 74 string.punctuation 75 string.printable 76 77 def test_atoi(self): 78 self.assertEqual(string.atoi(" 1 "), 1) 79 self.assertRaises(ValueError, string.atoi, " 1x") 80 self.assertRaises(ValueError, string.atoi, " x1 ") 81 82 def test_atol(self): 83 self.assertEqual(string.atol(" 1 "), 1L) 84 self.assertRaises(ValueError, string.atol, " 1x ") 85 self.assertRaises(ValueError, string.atol, " x1 ") 86 87 def test_atof(self): 88 self.assertAlmostEqual(string.atof(" 1 "), 1.0) 89 self.assertRaises(ValueError, string.atof, " 1x ") 90 self.assertRaises(ValueError, string.atof, " x1 ") 91 92 def test_maketrans(self): 93 transtable = '\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`xyzdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377' 94 95 self.assertEqual(string.maketrans('abc', 'xyz'), transtable) 96 self.assertRaises(ValueError, string.maketrans, 'abc', 'xyzq') 97 98 def test_capwords(self): 99 self.assertEqual(string.capwords('abc def ghi'), 'Abc Def Ghi') 100 self.assertEqual(string.capwords('abc\tdef\nghi'), 'Abc Def Ghi') 101 self.assertEqual(string.capwords('abc\t def \nghi'), 'Abc Def Ghi') 102 self.assertEqual(string.capwords('ABC DEF GHI'), 'Abc Def Ghi') 103 self.assertEqual(string.capwords('ABC-DEF-GHI', '-'), 'Abc-Def-Ghi') 104 self.assertEqual(string.capwords('ABC-def DEF-ghi GHI'), 'Abc-def Def-ghi Ghi') 105 self.assertEqual(string.capwords(' aBc DeF '), 'Abc Def') 106 self.assertEqual(string.capwords('\taBc\tDeF\t'), 'Abc Def') 107 self.assertEqual(string.capwords('\taBc\tDeF\t', '\t'), '\tAbc\tDef\t') 108 109 def test_formatter(self): 110 fmt = string.Formatter() 111 self.assertEqual(fmt.format("foo"), "foo") 112 113 self.assertEqual(fmt.format("foo{0}", "bar"), "foobar") 114 self.assertEqual(fmt.format("foo{1}{0}-{1}", "bar", 6), "foo6bar-6") 115 self.assertEqual(fmt.format("-{arg!r}-", arg='test'), "-'test'-") 116 117 # override get_value ############################################ 118 class NamespaceFormatter(string.Formatter): 119 def __init__(self, namespace={}): 120 string.Formatter.__init__(self) 121 self.namespace = namespace 122 123 def get_value(self, key, args, kwds): 124 if isinstance(key, str): 125 try: 126 # Check explicitly passed arguments first 127 return kwds[key] 128 except KeyError: 129 return self.namespace[key] 130 else: 131 string.Formatter.get_value(key, args, kwds) 132 133 fmt = NamespaceFormatter({'greeting':'hello'}) 134 self.assertEqual(fmt.format("{greeting}, world!"), 'hello, world!') 135 136 137 # override format_field ######################################### 138 class CallFormatter(string.Formatter): 139 def format_field(self, value, format_spec): 140 return format(value(), format_spec) 141 142 fmt = CallFormatter() 143 self.assertEqual(fmt.format('*{0}*', lambda : 'result'), '*result*') 144 145 146 # override convert_field ######################################## 147 class XFormatter(string.Formatter): 148 def convert_field(self, value, conversion): 149 if conversion == 'x': 150 return None 151 return super(XFormatter, self).convert_field(value, conversion) 152 153 fmt = XFormatter() 154 self.assertEqual(fmt.format("{0!r}:{0!x}", 'foo', 'foo'), "'foo':None") 155 156 157 # override parse ################################################ 158 class BarFormatter(string.Formatter): 159 # returns an iterable that contains tuples of the form: 160 # (literal_text, field_name, format_spec, conversion) 161 def parse(self, format_string): 162 for field in format_string.split('|'): 163 if field[0] == '+': 164 # it's markup 165 field_name, _, format_spec = field[1:].partition(':') 166 yield '', field_name, format_spec, None 167 else: 168 yield field, None, None, None 169 170 fmt = BarFormatter() 171 self.assertEqual(fmt.format('*|+0:^10s|*', 'foo'), '* foo *') 172 173 # test all parameters used 174 class CheckAllUsedFormatter(string.Formatter): 175 def check_unused_args(self, used_args, args, kwargs): 176 # Track which arguments actually got used 177 unused_args = set(kwargs.keys()) 178 unused_args.update(range(0, len(args))) 179 180 for arg in used_args: 181 unused_args.remove(arg) 182 183 if unused_args: 184 raise ValueError("unused arguments") 185 186 fmt = CheckAllUsedFormatter() 187 self.assertEqual(fmt.format("{0}", 10), "10") 188 self.assertEqual(fmt.format("{0}{i}", 10, i=100), "10100") 189 self.assertEqual(fmt.format("{0}{i}{1}", 10, 20, i=100), "1010020") 190 self.assertRaises(ValueError, fmt.format, "{0}{i}{1}", 10, 20, i=100, j=0) 191 self.assertRaises(ValueError, fmt.format, "{0}", 10, 20) 192 self.assertRaises(ValueError, fmt.format, "{0}", 10, 20, i=100) 193 self.assertRaises(ValueError, fmt.format, "{i}", 10, 20, i=100) 194 195 # Alternate formatting is not supported 196 self.assertRaises(ValueError, format, '', '#') 197 self.assertRaises(ValueError, format, '', '#20') 198 199 def test_format_keyword_arguments(self): 200 fmt = string.Formatter() 201 self.assertEqual(fmt.format("-{arg}-", arg='test'), '-test-') 202 self.assertRaises(KeyError, fmt.format, "-{arg}-") 203 self.assertEqual(fmt.format("-{self}-", self='test'), '-test-') 204 self.assertRaises(KeyError, fmt.format, "-{self}-") 205 self.assertEqual(fmt.format("-{format_string}-", format_string='test'), 206 '-test-') 207 self.assertRaises(KeyError, fmt.format, "-{format_string}-") 208 self.assertEqual(fmt.format(arg='test', format_string="-{arg}-"), 209 '-test-') 210 211class BytesAliasTest(unittest.TestCase): 212 213 def test_builtin(self): 214 self.assertTrue(str is bytes) 215 216 def test_syntax(self): 217 self.assertEqual(b"spam", "spam") 218 self.assertEqual(br"egg\foo", "egg\\foo") 219 self.assertTrue(type(b""), str) 220 self.assertTrue(type(br""), str) 221 222 223# Template tests (formerly housed in test_pep292.py) 224 225class Bag: 226 pass 227 228class Mapping: 229 def __getitem__(self, name): 230 obj = self 231 for part in name.split('.'): 232 try: 233 obj = getattr(obj, part) 234 except AttributeError: 235 raise KeyError(name) 236 return obj 237 238 239class TestTemplate(unittest.TestCase): 240 def test_regular_templates(self): 241 s = Template('$who likes to eat a bag of $what worth $$100') 242 self.assertEqual(s.substitute(dict(who='tim', what='ham')), 243 'tim likes to eat a bag of ham worth $100') 244 self.assertRaises(KeyError, s.substitute, dict(who='tim')) 245 self.assertRaises(TypeError, Template.substitute) 246 247 def test_regular_templates_with_braces(self): 248 s = Template('$who likes ${what} for ${meal}') 249 d = dict(who='tim', what='ham', meal='dinner') 250 self.assertEqual(s.substitute(d), 'tim likes ham for dinner') 251 self.assertRaises(KeyError, s.substitute, 252 dict(who='tim', what='ham')) 253 254 def test_escapes(self): 255 eq = self.assertEqual 256 s = Template('$who likes to eat a bag of $$what worth $$100') 257 eq(s.substitute(dict(who='tim', what='ham')), 258 'tim likes to eat a bag of $what worth $100') 259 s = Template('$who likes $$') 260 eq(s.substitute(dict(who='tim', what='ham')), 'tim likes $') 261 262 def test_percents(self): 263 eq = self.assertEqual 264 s = Template('%(foo)s $foo ${foo}') 265 d = dict(foo='baz') 266 eq(s.substitute(d), '%(foo)s baz baz') 267 eq(s.safe_substitute(d), '%(foo)s baz baz') 268 269 def test_stringification(self): 270 eq = self.assertEqual 271 s = Template('tim has eaten $count bags of ham today') 272 d = dict(count=7) 273 eq(s.substitute(d), 'tim has eaten 7 bags of ham today') 274 eq(s.safe_substitute(d), 'tim has eaten 7 bags of ham today') 275 s = Template('tim has eaten ${count} bags of ham today') 276 eq(s.substitute(d), 'tim has eaten 7 bags of ham today') 277 278 def test_tupleargs(self): 279 eq = self.assertEqual 280 s = Template('$who ate ${meal}') 281 d = dict(who=('tim', 'fred'), meal=('ham', 'kung pao')) 282 eq(s.substitute(d), "('tim', 'fred') ate ('ham', 'kung pao')") 283 eq(s.safe_substitute(d), "('tim', 'fred') ate ('ham', 'kung pao')") 284 285 def test_SafeTemplate(self): 286 eq = self.assertEqual 287 s = Template('$who likes ${what} for ${meal}') 288 eq(s.safe_substitute(dict(who='tim')), 'tim likes ${what} for ${meal}') 289 eq(s.safe_substitute(dict(what='ham')), '$who likes ham for ${meal}') 290 eq(s.safe_substitute(dict(what='ham', meal='dinner')), 291 '$who likes ham for dinner') 292 eq(s.safe_substitute(dict(who='tim', what='ham')), 293 'tim likes ham for ${meal}') 294 eq(s.safe_substitute(dict(who='tim', what='ham', meal='dinner')), 295 'tim likes ham for dinner') 296 297 def test_invalid_placeholders(self): 298 raises = self.assertRaises 299 s = Template('$who likes $') 300 raises(ValueError, s.substitute, dict(who='tim')) 301 s = Template('$who likes ${what)') 302 raises(ValueError, s.substitute, dict(who='tim')) 303 s = Template('$who likes $100') 304 raises(ValueError, s.substitute, dict(who='tim')) 305 306 def test_idpattern_override(self): 307 class PathPattern(Template): 308 idpattern = r'[_a-z][._a-z0-9]*' 309 m = Mapping() 310 m.bag = Bag() 311 m.bag.foo = Bag() 312 m.bag.foo.who = 'tim' 313 m.bag.what = 'ham' 314 s = PathPattern('$bag.foo.who likes to eat a bag of $bag.what') 315 self.assertEqual(s.substitute(m), 'tim likes to eat a bag of ham') 316 317 def test_pattern_override(self): 318 class MyPattern(Template): 319 pattern = r""" 320 (?P<escaped>@{2}) | 321 @(?P<named>[_a-z][._a-z0-9]*) | 322 @{(?P<braced>[_a-z][._a-z0-9]*)} | 323 (?P<invalid>@) 324 """ 325 m = Mapping() 326 m.bag = Bag() 327 m.bag.foo = Bag() 328 m.bag.foo.who = 'tim' 329 m.bag.what = 'ham' 330 s = MyPattern('@bag.foo.who likes to eat a bag of @bag.what') 331 self.assertEqual(s.substitute(m), 'tim likes to eat a bag of ham') 332 333 class BadPattern(Template): 334 pattern = r""" 335 (?P<badname>.*) | 336 (?P<escaped>@{2}) | 337 @(?P<named>[_a-z][._a-z0-9]*) | 338 @{(?P<braced>[_a-z][._a-z0-9]*)} | 339 (?P<invalid>@) | 340 """ 341 s = BadPattern('@bag.foo.who likes to eat a bag of @bag.what') 342 self.assertRaises(ValueError, s.substitute, {}) 343 self.assertRaises(ValueError, s.safe_substitute, {}) 344 345 def test_braced_override(self): 346 class MyTemplate(Template): 347 pattern = r""" 348 \$(?: 349 (?P<escaped>$) | 350 (?P<named>[_a-z][_a-z0-9]*) | 351 @@(?P<braced>[_a-z][_a-z0-9]*)@@ | 352 (?P<invalid>) | 353 ) 354 """ 355 356 tmpl = 'PyCon in $@@location@@' 357 t = MyTemplate(tmpl) 358 self.assertRaises(KeyError, t.substitute, {}) 359 val = t.substitute({'location': 'Cleveland'}) 360 self.assertEqual(val, 'PyCon in Cleveland') 361 362 def test_braced_override_safe(self): 363 class MyTemplate(Template): 364 pattern = r""" 365 \$(?: 366 (?P<escaped>$) | 367 (?P<named>[_a-z][_a-z0-9]*) | 368 @@(?P<braced>[_a-z][_a-z0-9]*)@@ | 369 (?P<invalid>) | 370 ) 371 """ 372 373 tmpl = 'PyCon in $@@location@@' 374 t = MyTemplate(tmpl) 375 self.assertEqual(t.safe_substitute(), tmpl) 376 val = t.safe_substitute({'location': 'Cleveland'}) 377 self.assertEqual(val, 'PyCon in Cleveland') 378 379 def test_unicode_values(self): 380 s = Template('$who likes $what') 381 d = dict(who=u't\xffm', what=u'f\xfe\fed') 382 self.assertEqual(s.substitute(d), u't\xffm likes f\xfe\x0ced') 383 384 def test_keyword_arguments(self): 385 eq = self.assertEqual 386 s = Template('$who likes $what') 387 eq(s.substitute(who='tim', what='ham'), 'tim likes ham') 388 eq(s.substitute(dict(who='tim'), what='ham'), 'tim likes ham') 389 eq(s.substitute(dict(who='fred', what='kung pao'), 390 who='tim', what='ham'), 391 'tim likes ham') 392 s = Template('the mapping is $mapping') 393 eq(s.substitute(dict(foo='none'), mapping='bozo'), 394 'the mapping is bozo') 395 eq(s.substitute(dict(mapping='one'), mapping='two'), 396 'the mapping is two') 397 398 s = Template('the self is $self') 399 eq(s.substitute(self='bozo'), 'the self is bozo') 400 401 def test_keyword_arguments_safe(self): 402 eq = self.assertEqual 403 raises = self.assertRaises 404 s = Template('$who likes $what') 405 eq(s.safe_substitute(who='tim', what='ham'), 'tim likes ham') 406 eq(s.safe_substitute(dict(who='tim'), what='ham'), 'tim likes ham') 407 eq(s.safe_substitute(dict(who='fred', what='kung pao'), 408 who='tim', what='ham'), 409 'tim likes ham') 410 s = Template('the mapping is $mapping') 411 eq(s.safe_substitute(dict(foo='none'), mapping='bozo'), 412 'the mapping is bozo') 413 eq(s.safe_substitute(dict(mapping='one'), mapping='two'), 414 'the mapping is two') 415 d = dict(mapping='one') 416 raises(TypeError, s.substitute, d, {}) 417 raises(TypeError, s.safe_substitute, d, {}) 418 419 s = Template('the self is $self') 420 eq(s.safe_substitute(self='bozo'), 'the self is bozo') 421 422 def test_delimiter_override(self): 423 eq = self.assertEqual 424 raises = self.assertRaises 425 class AmpersandTemplate(Template): 426 delimiter = '&' 427 s = AmpersandTemplate('this &gift is for &{who} &&') 428 eq(s.substitute(gift='bud', who='you'), 'this bud is for you &') 429 raises(KeyError, s.substitute) 430 eq(s.safe_substitute(gift='bud', who='you'), 'this bud is for you &') 431 eq(s.safe_substitute(), 'this &gift is for &{who} &') 432 s = AmpersandTemplate('this &gift is for &{who} &') 433 raises(ValueError, s.substitute, dict(gift='bud', who='you')) 434 eq(s.safe_substitute(), 'this &gift is for &{who} &') 435 436 class PieDelims(Template): 437 delimiter = '@' 438 s = PieDelims('@who likes to eat a bag of @{what} worth $100') 439 self.assertEqual(s.substitute(dict(who='tim', what='ham')), 440 'tim likes to eat a bag of ham worth $100') 441 442 443def test_main(): 444 test_support.run_unittest(StringTest, ModuleTest, BytesAliasTest, TestTemplate) 445 446if __name__ == '__main__': 447 test_main() 448