def append(self, lineno, line):
self.errors.append((lineno, line))
- self.message += '\n\t[line %2d]: %s' % (lineno, repr(line))
+ self.message += f'\n\t[line {lineno:2d}]: {line!r}'
def combine(self, others):
+ messages = [self.message]
for other in others:
- for error in other.errors:
- self.append(*error)
+ for lineno, line in other.errors:
+ self.errors.append((lineno, line))
+ messages.append(f'\n\t[line {lineno:2d}]: {line!r}')
+ self.message = "".join(messages)
return self
@staticmethod
self.assertEqual(e1.message, e2.message)
self.assertEqual(repr(e1), repr(e2))
+ def test_combine_error_linear_complexity(self):
+ # Ensure that ParsingError.combine() has linear complexity.
+ # See https://github.com/python/cpython/issues/148370.
+ n = 50000
+ s = '[*]\n' + (err_line := '=\n') * n
+ p = configparser.ConfigParser(strict=False)
+ with self.assertRaises(configparser.ParsingError) as cm:
+ p.read_string(s)
+ errlines = cm.exception.message.splitlines()
+ self.assertEqual(len(errlines), n + 1)
+ self.assertStartsWith(errlines[0], "Source contains parsing errors: ")
+ self.assertEqual(errlines[42], f"\t[line {43:2d}]: {err_line!r}")
+
def test_nosectionerror(self):
import pickle
e1 = configparser.NoSectionError('section')