Skip to content

gh-132661: Add default value (of "") for Interpolation.expression #136441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 10, 2025
44 changes: 28 additions & 16 deletions Lib/test/test_string/_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,45 @@


class TStringBaseCase:
def assertInterpolationEqual(self, i, exp):
"""Test Interpolation equality.

The *i* argument must be an Interpolation instance.

The *exp* argument must be a tuple of the form
(value, expression, conversion, format_spec) where the final three
items may be omitted and are assumed to be '', None and '' respectively.
"""
if len(exp) == 4:
actual = (i.value, i.expression, i.conversion, i.format_spec)
self.assertEqual(actual, exp)
elif len(exp) == 3:
self.assertEqual((i.value, i.expression, i.conversion), exp)
self.assertEqual(i.format_spec, "")
elif len(exp) == 2:
self.assertEqual((i.value, i.expression), exp)
self.assertEqual(i.conversion, None)
self.assertEqual(i.format_spec, "")
elif len(exp) == 1:
self.assertEqual((i.value,), exp)
self.assertEqual(i.expression, "")
self.assertEqual(i.conversion, None)
self.assertEqual(i.format_spec, "")

def assertTStringEqual(self, t, strings, interpolations):
"""Test template string literal equality.

The *strings* argument must be a tuple of strings equal to *t.strings*.

The *interpolations* argument must be a sequence of tuples which are
compared against *t.interpolations*. Each tuple consists of
(value, expression, conversion, format_spec), though the final two
items may be omitted, and are assumed to be None and '' respectively.
compared against *t.interpolations*. Each tuple must match the form
described in the `assertInterpolationEqual` method.
"""
self.assertEqual(t.strings, strings)
self.assertEqual(len(t.interpolations), len(interpolations))

for i, exp in zip(t.interpolations, interpolations, strict=True):
if len(exp) == 4:
actual = (i.value, i.expression, i.conversion, i.format_spec)
self.assertEqual(actual, exp)
continue

if len(exp) == 3:
self.assertEqual((i.value, i.expression, i.conversion), exp)
self.assertEqual(i.format_spec, '')
continue

self.assertEqual((i.value, i.expression), exp)
self.assertEqual(i.format_spec, '')
self.assertIsNone(i.conversion)
self.assertInterpolationEqual(i, exp)


def convert(value, conversion):
Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_string/test_templatelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ def test_basic_creation(self):
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, ''))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``Interpolation.expression`` now has a default, the empty string.
23 changes: 14 additions & 9 deletions Objects/clinic/interpolationobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Objects/interpolationobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ typedef struct {
Interpolation.__new__ as interpolation_new

value: object
expression: object(subclass_of='&PyUnicode_Type')
expression: object(subclass_of='&PyUnicode_Type', c_default='&_Py_STR(empty)') = ""
conversion: object(converter='_conversion_converter') = None
format_spec: object(subclass_of='&PyUnicode_Type', c_default='&_Py_STR(empty)') = ""
[clinic start generated code]*/
Expand All @@ -63,7 +63,7 @@ static PyObject *
interpolation_new_impl(PyTypeObject *type, PyObject *value,
PyObject *expression, PyObject *conversion,
PyObject *format_spec)
/*[clinic end generated code: output=6488e288765bc1a9 input=d91711024068528c]*/
/*[clinic end generated code: output=6488e288765bc1a9 input=fc5c285c1dd23d36]*/
{
interpolationobject *self = PyObject_GC_New(interpolationobject, type);
if (!self) {
Expand Down
Loading