You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
configparser: reading an invalid file triggers ParsingError *and* mutations #95546
I expect reading to be an all-or-nothing operation -- if the file contains a syntax error it shouldn't modify the ConfigParser object with half of the file's contents
# a non-fatal parsing error occurred. set up the# exception but keep going. the exception will be# raised at the end of the file and will contain a# list of all bogus lines
Apparently, the ParsingError is considered non-fatal so it continues. If you use:
cfg.read_string('[foo]\nx = 1\n...\ny = 2')
y can also be retrieved.
I don't feel raising the error after the fact makes much sense either but it is done with the idea that you are shown all the lines that are wrong instead of having to run the config as many times are there are errors.
Furthermore, if you catch configparser.Error (the intention is to skip invalid config files) and then attempt to use the ConfigParser instance, you can get really weird errors. In this example, read raises DuplicateOptionError from the 2nd section, but attempting to get a value from the first section fails in the interpolation code, because somehow the value has been stored as a list instead of a string!?
>>> import configparser
>>> cp = configparser.ConfigParser()
>>> cp.read_string('[a]\nx=1\n[b]\ny=1\ny=2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.12/configparser.py", line 710, in read_string
self.read_file(sfile, source)
File "/usr/lib/python3.12/configparser.py", line 705, in read_file
self._read(f, source)
File "/usr/lib/python3.12/configparser.py", line 1074, in _read
raise DuplicateOptionError(sectname, optname,
configparser.DuplicateOptionError: While reading from '<string>' [line 5]: option 'y' in section 'b' already exists
>>> cp.get('a', 'x')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.12/configparser.py", line 777, in get
return self._interpolation.before_get(self, section, option, value,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/configparser.py", line 367, in before_get
self._interpolate_some(parser, option, L, value, section, defaults, 1)
File "/usr/lib/python3.12/configparser.py", line 384, in _interpolate_some
p = rest.find("%")
^^^^^^^^^
AttributeError: 'list' object has no attribute 'find'
Reproduced with Python 3.10 and 3.12.
P.S. Disabling interpolation can read the value from the 1st section but it's a list, not a str:
The behaviour in my previous comment is because ConfigParser._read doesn't call _join_multiline_values when it raises DuplicateSectionError or DuplicateOptionError (but it does for ParsingError):
# if any parsing errors occurred, raise an exception
ife:
raisee
Maybe this should go in a finally block? Or modify the method so that DuplicateSectionError and DuplicateOptionError aren't raised immediately, like the existing handling of ParsingErrors?
Activity
PurityLake commentedon Aug 2, 2022
Apparently, the ParsingError is considered non-fatal so it continues. If you use:
ycan also be retrieved.I don't feel raising the error after the fact makes much sense either but it is done with the idea that you are shown all the lines that are wrong instead of having to run the config as many times are there are errors.
drothlis commentedon Mar 18, 2024
Furthermore, if you catch
configparser.Error(the intention is to skip invalid config files) and then attempt to use the ConfigParser instance, you can get really weird errors. In this example,readraises DuplicateOptionError from the 2nd section, but attempting togeta value from the first section fails in the interpolation code, because somehow the value has been stored as a list instead of a string!?Reproduced with Python 3.10 and 3.12.
P.S. Disabling interpolation can read the value from the 1st section but it's a list, not a str:
drothlis commentedon Mar 18, 2024
The behaviour in my previous comment is because
ConfigParser._readdoesn't call_join_multiline_valueswhen it raises DuplicateSectionError or DuplicateOptionError (but it does for ParsingError):cpython/Lib/configparser.py
Lines 1059 to 1062 in 43c9d61
Maybe this should go in a
finallyblock? Or modify the method so that DuplicateSectionError and DuplicateOptionError aren't raised immediately, like the existing handling of ParsingErrors?drothlis commentedon Mar 18, 2024
I have raised #116957 for the bug I described in my 2 previous comments, which is about Duplicate{Section,Option}Error rather than ParsingError.