Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions Lib/test/test_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2863,13 +2863,29 @@ def test_formatter_parser(self):
def parse(format):
return list(_string.formatter_parser(format))

formatter = next(_string.formatter_parser("test"))
self.assertEqual(formatter.n_fields, 4)
self.assertEqual(formatter.n_unnamed_fields, 0)
self.assertEqual(formatter.n_sequence_fields, 4)
self.assertNotEqual(formatter.__class__, tuple)
self.assertIsInstance(formatter, tuple)
self.assertEqual(formatter.__class__.__name__, "FormatterItem")

formatter = parse("prefix {2!s}xxx{0:^+10.3f}{obj.attr!s} {z[0]!s:10}")
self.assertEqual(formatter, [
expected_formatter = [
('prefix ', '2', '', 's'),
('xxx', '0', '^+10.3f', None),
('', 'obj.attr', '', 's'),
(' ', 'z[0]', '10', 's'),
])
]

self.assertEqual(formatter, expected_formatter)

for result, expected in zip(formatter, expected_formatter):
self.assertEqual(result.literal_text, expected[0])
self.assertEqual(result.field_name, expected[1])
self.assertEqual(result.format_spec, expected[2])
self.assertEqual(result.conversion, expected[3])

formatter = parse("prefix {} suffix")
self.assertEqual(formatter, [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Use named tuple (structseq object) in string.Formatter.parse iterator
response.
50 changes: 41 additions & 9 deletions Objects/stringlib/unicode_format.h
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,27 @@ formatteriter_dealloc(formatteriterobject *it)
format_spec is the string after the ':'. mibht be None
conversion is either None, or the string after the '!'
*/

static PyStructSequence_Field formatter_iter_result_fields[] = {
{"literal_text", "Span of literal text."},
{"field_name", "Specifies the object whose value is to be formatted."},
{"format_spec", "Contains a specification of how the value \
should be presented."},
{"conversion", "The conversion to be used. One of: ‘s’ (str),\
‘r’ (repr) and ‘a’ (ascii)."},
{NULL}
};

static PyTypeObject FormatterIterResultType;

static PyStructSequence_Desc formatter_iter_result_desc = {
"string.FormatterItem",
NULL,
formatter_iter_result_fields,
4
};


static PyObject *
formatteriter_next(formatteriterobject *it)
{
Expand All @@ -1013,23 +1034,23 @@ formatteriter_next(formatteriterobject *it)
PyObject *field_name_str = NULL;
PyObject *format_spec_str = NULL;
PyObject *conversion_str = NULL;
PyObject *tuple = NULL;
PyObject *res;

literal_str = SubString_new_object(&literal);
if (literal_str == NULL)
goto done;
goto error;

field_name_str = SubString_new_object(&field_name);
if (field_name_str == NULL)
goto done;
goto error;

/* if field_name is non-zero length, return a string for
format_spec (even if zero length), else return None */
format_spec_str = (field_present ?
SubString_new_object_or_empty :
SubString_new_object)(&format_spec);
if (format_spec_str == NULL)
goto done;
goto error;

/* if the conversion is not specified, return a None,
otherwise create a one length string with the conversion
Expand All @@ -1042,16 +1063,27 @@ formatteriter_next(formatteriterobject *it)
conversion_str = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND,
&conversion, 1);
if (conversion_str == NULL)
goto done;
goto error;

tuple = PyTuple_Pack(4, literal_str, field_name_str, format_spec_str,
conversion_str);
done:
Py_INCREF((PyObject *) &FormatterIterResultType);
res = PyStructSequence_New(&FormatterIterResultType);

if (res == NULL)
goto error;

PyStructSequence_SET_ITEM(res, 0, literal_str);
PyStructSequence_SET_ITEM(res, 1, field_name_str);
PyStructSequence_SET_ITEM(res, 2, format_spec_str);
PyStructSequence_SET_ITEM(res, 3, conversion_str);

return res;

error:
Py_XDECREF(literal_str);
Py_XDECREF(field_name_str);
Py_XDECREF(format_spec_str);
Py_XDECREF(conversion_str);
return tuple;
return NULL;
}
}

Expand Down
1 change: 1 addition & 0 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -15696,6 +15696,7 @@ static struct PyModuleDef _string_module = {
PyMODINIT_FUNC
PyInit__string(void)
{
PyStructSequence_InitType(&FormatterIterResultType, &formatter_iter_result_desc);
return PyModule_Create(&_string_module);
}

Expand Down