| import pickle | |
| import unittest | |
| from collections.abc import Iterator, Iterable | |
| from string.templatelib import Template, Interpolation, convert | |
| from test.test_string._support import TStringBaseCase, fstring | |
| class TestTemplate(unittest.TestCase, TStringBaseCase): | |
| def test_common(self): | |
| self.assertEqual(type(t'').__name__, 'Template') | |
| self.assertEqual(type(t'').__qualname__, 'Template') | |
| self.assertEqual(type(t'').__module__, 'string.templatelib') | |
| a = 'a' | |
| i = t'{a}'.interpolations[0] | |
| self.assertEqual(type(i).__name__, 'Interpolation') | |
| self.assertEqual(type(i).__qualname__, 'Interpolation') | |
| self.assertEqual(type(i).__module__, 'string.templatelib') | |
| def test_final_types(self): | |
| with self.assertRaisesRegex(TypeError, 'is not an acceptable base type'): | |
| class Sub(Template): ... | |
| with self.assertRaisesRegex(TypeError, 'is not an acceptable base type'): | |
| class Sub(Interpolation): ... | |
| def test_basic_creation(self): | |
| # Simple t-string creation | |
| t = t'Hello, world' | |
| self.assertIsInstance(t, Template) | |
| self.assertTStringEqual(t, ('Hello, world',), ()) | |
| self.assertEqual(fstring(t), 'Hello, world') | |
| # Empty t-string | |
| t = t'' | |
| self.assertTStringEqual(t, ('',), ()) | |
| self.assertEqual(fstring(t), '') | |
| # Multi-line t-string | |
| t = t"""Hello, | |
| world""" | |
| self.assertEqual(t.strings, ('Hello,\nworld',)) | |
| self.assertEqual(len(t.interpolations), 0) | |
| self.assertEqual(fstring(t), 'Hello,\nworld') | |
| def test_interpolation_creation(self): | |
| i = Interpolation('Maria', 'name', 'a', 'fmt') | |
| self.assertInterpolationEqual(i, ('Maria', 'name', 'a', 'fmt')) | |
| i = Interpolation('Maria', 'name', 'a') | |
| self.assertInterpolationEqual(i, ('Maria', 'name', 'a')) | |
| i = Interpolation('Maria', 'name') | |
| self.assertInterpolationEqual(i, ('Maria', 'name')) | |
| i = Interpolation('Maria') | |
| self.assertInterpolationEqual(i, ('Maria',)) | |
| def test_creation_interleaving(self): | |
| # Should add strings on either side | |
| t = Template(Interpolation('Maria', 'name', None, '')) | |
| self.assertTStringEqual(t, ('', ''), [('Maria', 'name')]) | |
| self.assertEqual(fstring(t), 'Maria') | |
| # Should prepend empty string | |
| t = Template(Interpolation('Maria', 'name', None, ''), ' is my name') | |
| self.assertTStringEqual(t, ('', ' is my name'), [('Maria', 'name')]) | |
| self.assertEqual(fstring(t), 'Maria is my name') | |
| # Should append empty string | |
| t = Template('Hello, ', Interpolation('Maria', 'name', None, '')) | |
| self.assertTStringEqual(t, ('Hello, ', ''), [('Maria', 'name')]) | |
| self.assertEqual(fstring(t), 'Hello, Maria') | |
| # Should concatenate strings | |
| t = Template('Hello', ', ', Interpolation('Maria', 'name', None, ''), | |
| '!') | |
| self.assertTStringEqual(t, ('Hello, ', '!'), [('Maria', 'name')]) | |
| self.assertEqual(fstring(t), 'Hello, Maria!') | |
| # Should add strings on either side and in between | |
| t = Template(Interpolation('Maria', 'name', None, ''), | |
| Interpolation('Python', 'language', None, '')) | |
| self.assertTStringEqual( | |
| t, ('', '', ''), [('Maria', 'name'), ('Python', 'language')] | |
| ) | |
| self.assertEqual(fstring(t), 'MariaPython') | |
| def test_template_values(self): | |
| t = t'Hello, world' | |
| self.assertEqual(t.values, ()) | |
| name = "Lys" | |
| t = t'Hello, {name}' | |
| self.assertEqual(t.values, ("Lys",)) | |
| country = "GR" | |
| age = 0 | |
| t = t'Hello, {name}, {age} from {country}' | |
| self.assertEqual(t.values, ("Lys", 0, "GR")) | |
| def test_pickle_template(self): | |
| user = 'test' | |
| for template in ( | |
| t'', | |
| t"No values", | |
| t'With inter {user}', | |
| t'With ! {user!r}', | |
| t'With format {1 / 0.3:.2f}', | |
| Template(), | |
| Template('a'), | |
| Template(Interpolation('Nikita', 'name', None, '')), | |
| Template('a', Interpolation('Nikita', 'name', 'r', '')), | |
| ): | |
| for proto in range(pickle.HIGHEST_PROTOCOL + 1): | |
| with self.subTest(proto=proto, template=template): | |
| pickled = pickle.dumps(template, protocol=proto) | |
| unpickled = pickle.loads(pickled) | |
| self.assertEqual(unpickled.values, template.values) | |
| self.assertEqual(fstring(unpickled), fstring(template)) | |
| def test_pickle_interpolation(self): | |
| for interpolation in ( | |
| Interpolation('Nikita', 'name', None, ''), | |
| Interpolation('Nikita', 'name', 'r', ''), | |
| Interpolation(1/3, 'x', None, '.2f'), | |
| ): | |
| for proto in range(pickle.HIGHEST_PROTOCOL + 1): | |
| with self.subTest(proto=proto, interpolation=interpolation): | |
| pickled = pickle.dumps(interpolation, protocol=proto) | |
| unpickled = pickle.loads(pickled) | |
| self.assertEqual(unpickled.value, interpolation.value) | |
| self.assertEqual(unpickled.expression, interpolation.expression) | |
| self.assertEqual(unpickled.conversion, interpolation.conversion) | |
| self.assertEqual(unpickled.format_spec, interpolation.format_spec) | |
| class TemplateIterTests(unittest.TestCase): | |
| def test_abc(self): | |
| self.assertIsInstance(iter(t''), Iterable) | |
| self.assertIsInstance(iter(t''), Iterator) | |
| def test_final(self): | |
| TemplateIter = type(iter(t'')) | |
| with self.assertRaisesRegex(TypeError, 'is not an acceptable base type'): | |
| class Sub(TemplateIter): ... | |
| def test_iter(self): | |
| x = 1 | |
| res = list(iter(t'abc {x} yz')) | |
| self.assertEqual(res[0], 'abc ') | |
| self.assertIsInstance(res[1], Interpolation) | |
| self.assertEqual(res[1].value, 1) | |
| self.assertEqual(res[1].expression, 'x') | |
| self.assertEqual(res[1].conversion, None) | |
| self.assertEqual(res[1].format_spec, '') | |
| self.assertEqual(res[2], ' yz') | |
| def test_exhausted(self): | |
| # See https://github.com/python/cpython/issues/134119. | |
| template_iter = iter(t"{1}") | |
| self.assertIsInstance(next(template_iter), Interpolation) | |
| self.assertRaises(StopIteration, next, template_iter) | |
| self.assertRaises(StopIteration, next, template_iter) | |
| class TestFunctions(unittest.TestCase): | |
| def test_convert(self): | |
| from fractions import Fraction | |
| for obj in ('Café', None, 3.14, Fraction(1, 2)): | |
| with self.subTest(f'{obj=}'): | |
| self.assertEqual(convert(obj, None), obj) | |
| self.assertEqual(convert(obj, 's'), str(obj)) | |
| self.assertEqual(convert(obj, 'r'), repr(obj)) | |
| self.assertEqual(convert(obj, 'a'), ascii(obj)) | |
| # Invalid conversion specifier | |
| with self.assertRaises(ValueError): | |
| convert(obj, 'z') | |
| with self.assertRaises(ValueError): | |
| convert(obj, 1) | |
| with self.assertRaises(ValueError): | |
| convert(obj, object()) | |
| if __name__ == '__main__': | |
| unittest.main() |