mirror of
https://github.com/python/cpython.git
synced 2025-09-18 14:40:43 +00:00
Changed some ValueError's to KeyError and IndexError.
Corrected code for invalid conversion specifier. Added tests to verify. Modified string.Formatter to correctly expand format_spec's, and added a limit to recursion depth. Added _vformat() method to support both of these.
This commit is contained in:
parent
0af17617c5
commit
11529195ca
3 changed files with 31 additions and 25 deletions
|
@ -202,6 +202,13 @@ class Formatter:
|
||||||
|
|
||||||
def vformat(self, format_string, args, kwargs):
|
def vformat(self, format_string, args, kwargs):
|
||||||
used_args = set()
|
used_args = set()
|
||||||
|
result = self._vformat(format_string, args, kwargs, used_args, 2)
|
||||||
|
self.check_unused_args(used_args, args, kwargs)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _vformat(self, format_string, args, kwargs, used_args, recursion_depth):
|
||||||
|
if recursion_depth < 0:
|
||||||
|
raise ValueError('Max string recursion exceeded')
|
||||||
result = []
|
result = []
|
||||||
for literal_text, field_name, format_spec, conversion in \
|
for literal_text, field_name, format_spec, conversion in \
|
||||||
self.parse(format_string):
|
self.parse(format_string):
|
||||||
|
@ -223,10 +230,13 @@ class Formatter:
|
||||||
# do any conversion on the resulting object
|
# do any conversion on the resulting object
|
||||||
obj = self.convert_field(obj, conversion)
|
obj = self.convert_field(obj, conversion)
|
||||||
|
|
||||||
|
# expand the format spec, if needed
|
||||||
|
format_spec = self._vformat(format_spec, args, kwargs,
|
||||||
|
used_args, recursion_depth-1)
|
||||||
|
|
||||||
# format the object and append to the result
|
# format the object and append to the result
|
||||||
result.append(self.format_field(obj, format_spec))
|
result.append(self.format_field(obj, format_spec))
|
||||||
|
|
||||||
self.check_unused_args(used_args, args, kwargs)
|
|
||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
@ -251,9 +261,9 @@ class Formatter:
|
||||||
return repr(value)
|
return repr(value)
|
||||||
elif conversion == 's':
|
elif conversion == 's':
|
||||||
return str(value)
|
return str(value)
|
||||||
else:
|
elif conversion is None:
|
||||||
assert conversion is None
|
|
||||||
return value
|
return value
|
||||||
|
raise ValueError("Unknown converion specifier {0!s}".format(conversion))
|
||||||
|
|
||||||
|
|
||||||
# returns an iterable that contains tuples of the form:
|
# returns an iterable that contains tuples of the form:
|
||||||
|
|
|
@ -542,29 +542,30 @@ class UnicodeTest(
|
||||||
self.assertRaises(ValueError, 'a}'.format)
|
self.assertRaises(ValueError, 'a}'.format)
|
||||||
self.assertRaises(ValueError, '{a'.format)
|
self.assertRaises(ValueError, '{a'.format)
|
||||||
self.assertRaises(ValueError, '}a'.format)
|
self.assertRaises(ValueError, '}a'.format)
|
||||||
self.assertRaises(ValueError, '{0}'.format)
|
self.assertRaises(IndexError, '{0}'.format)
|
||||||
self.assertRaises(ValueError, '{1}'.format, 'abc')
|
self.assertRaises(IndexError, '{1}'.format, 'abc')
|
||||||
self.assertRaises(ValueError, '{x}'.format)
|
self.assertRaises(KeyError, '{x}'.format)
|
||||||
self.assertRaises(ValueError, "}{".format)
|
self.assertRaises(ValueError, "}{".format)
|
||||||
self.assertRaises(ValueError, "{".format)
|
self.assertRaises(ValueError, "{".format)
|
||||||
self.assertRaises(ValueError, "}".format)
|
self.assertRaises(ValueError, "}".format)
|
||||||
self.assertRaises(ValueError, "abc{0:{}".format)
|
self.assertRaises(ValueError, "abc{0:{}".format)
|
||||||
self.assertRaises(ValueError, "{0".format)
|
self.assertRaises(ValueError, "{0".format)
|
||||||
self.assertRaises(ValueError, "{0.}".format)
|
self.assertRaises(IndexError, "{0.}".format)
|
||||||
self.assertRaises(ValueError, "{0[}".format)
|
self.assertRaises(ValueError, "{0.}".format, 0)
|
||||||
|
self.assertRaises(IndexError, "{0[}".format)
|
||||||
self.assertRaises(ValueError, "{0[}".format, [])
|
self.assertRaises(ValueError, "{0[}".format, [])
|
||||||
self.assertRaises(ValueError, "{0]}".format)
|
self.assertRaises(KeyError, "{0]}".format)
|
||||||
self.assertRaises(ValueError, "{0.[]}".format)
|
self.assertRaises(ValueError, "{0.[]}".format, 0)
|
||||||
self.assertRaises(ValueError, "{0..foo}".format, 0)
|
self.assertRaises(ValueError, "{0..foo}".format, 0)
|
||||||
self.assertRaises(ValueError, "{0[0}".format)
|
self.assertRaises(ValueError, "{0[0}".format, 0)
|
||||||
self.assertRaises(ValueError, "{0[0:foo}".format)
|
self.assertRaises(ValueError, "{0[0:foo}".format, 0)
|
||||||
self.assertRaises(ValueError, "{c]}".format)
|
self.assertRaises(KeyError, "{c]}".format)
|
||||||
self.assertRaises(ValueError, "{{ {{{0}}".format)
|
self.assertRaises(ValueError, "{{ {{{0}}".format, 0)
|
||||||
self.assertRaises(ValueError, "{0}}".format)
|
self.assertRaises(ValueError, "{0}}".format, 0)
|
||||||
self.assertRaises(ValueError, "{foo}".format, bar=3)
|
self.assertRaises(KeyError, "{foo}".format, bar=3)
|
||||||
self.assertRaises(ValueError, "{0!x}".format, 3)
|
self.assertRaises(ValueError, "{0!x}".format, 3)
|
||||||
self.assertRaises(ValueError, "{0!}".format)
|
self.assertRaises(ValueError, "{0!}".format, 0)
|
||||||
self.assertRaises(ValueError, "{0!rs}".format)
|
self.assertRaises(ValueError, "{0!rs}".format, 0)
|
||||||
self.assertRaises(ValueError, "{!}".format)
|
self.assertRaises(ValueError, "{!}".format)
|
||||||
self.assertRaises(ValueError, "{:}".format)
|
self.assertRaises(ValueError, "{:}".format)
|
||||||
self.assertRaises(ValueError, "{:s}".format)
|
self.assertRaises(ValueError, "{:s}".format)
|
||||||
|
|
|
@ -414,8 +414,7 @@ get_field_object(SubString *input, PyObject *args, PyObject *kwargs)
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
if ((kwargs == NULL) || (obj = PyDict_GetItem(kwargs, key)) == NULL) {
|
if ((kwargs == NULL) || (obj = PyDict_GetItem(kwargs, key)) == NULL) {
|
||||||
PyErr_SetString(PyExc_ValueError, "Keyword argument not found "
|
PyErr_SetObject(PyExc_KeyError, key);
|
||||||
"in format string");
|
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -425,13 +424,9 @@ get_field_object(SubString *input, PyObject *args, PyObject *kwargs)
|
||||||
else {
|
else {
|
||||||
/* look up in args */
|
/* look up in args */
|
||||||
obj = PySequence_GetItem(args, index);
|
obj = PySequence_GetItem(args, index);
|
||||||
if (obj == NULL) {
|
if (obj == NULL)
|
||||||
/* translate IndexError to a ValueError */
|
|
||||||
PyErr_SetString(PyExc_ValueError, "Not enough positional arguments "
|
|
||||||
"in format string");
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* iterate over the rest of the field_name */
|
/* iterate over the rest of the field_name */
|
||||||
while ((ok = FieldNameIterator_next(&rest, &is_attribute, &index,
|
while ((ok = FieldNameIterator_next(&rest, &is_attribute, &index,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue