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 getters not available on SectionProxy #62359
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee='https://github.com/ambv'closed_at=<Date2014-09-15.09:10:57.031>created_at=<Date2013-06-07.17:43:50.063>labels= ['type-feature', 'library']
title='ConfigParser getters not available on SectionProxy'updated_at=<Date2014-09-15.09:10:57.021>user='https://github.com/jbvsmo'
The configparser.RawConfigParser class implements some get methods:
get, getint, getfloat, getboolean
but if any of these get overridden on a subclass(with other arguments) or new ones are added (e.g. getlist), there's no way a SectionProxy instance will be able to use them.
classDemoParser(ConfigParser):
defgetlist(self, section, option):
returnself.get(section, option).split()
parser=DemoParser()
parser.read(some_file)
# These 2 lines should be equivalent, like "getint", but the# second doesn't work because of the SectionProxy instanceparser.getlist('some_section', 'foo')
parser['some_section'].getlist('foo')
Reading the code, for SectionProxy, it redefines all the get* methods from RawConfigParser, and that looks pretty bad...
A more elegant approach would be to fetch the function on the parser instance and bound to the section name with lambda or functools.partial... Something like:
There are several reasons why get*() methods are redefined on the section proxy. First of all, explicit is better than implicit. Secondly, the order of arguments is different: parser.get() has the fallback argument as the last (and keyword-only), whereas parser['section'].get() behaves like a mapping. You can do parser['section'].get('key', 'some-fallback-value') and parser['section'].get('no-such-key') returns None instead of raising NoOptionError.
This makes it difficult to automagically support parser get*() methods on the section proxy. This is why I decided to adapt a different mechanism: register a converter and a getter is automatically available:
This ensures that you can easily add new converters in subclasses or single instances and that the parser-level API and section-level API work like they should. This also makes implementing custom getters easier since there's no logic involved besides the conversion. And if you happen to need custom logic anyway, you can register a converter that is a callable class.
The reason I didn't commit that patch before was that I wasn't sure whether making this change wouldn't create any unexpected backwards incompatibility.
In fact, if I committed the patch as is, it would. I solved this by leaving getint, getfloat and getboolean on the parser class and keeping _get in use.
Activity
jbvsmo commentedon Jun 7, 2013
The configparser.RawConfigParser class implements some
getmethods:get, getint, getfloat, getboolean
but if any of these get overridden on a subclass(with other arguments) or new ones are added (e.g. getlist), there's no way a SectionProxy instance will be able to use them.
Reading the code, for SectionProxy, it redefines all the get* methods from RawConfigParser, and that looks pretty bad...
A more elegant approach would be to fetch the function on the parser instance and bound to the section name with
lambdaorfunctools.partial... Something like:ambv commentedon Jun 7, 2013
This is a reasonable feature request. Overriding __getattr__ doesn't look like the best solution, though. Let me think this over.
jbvsmo commentedon Jun 8, 2013
Another idea would be to allow the proxy class to be selectable, but this would require the user to do much more coding for this simple thing...
I believe a proxy should be dynamic enough to avoid having to duplicate every function definition.
ambv commentedon Jun 25, 2013
There are several reasons why
get*()methods are redefined on the section proxy. First of all, explicit is better than implicit. Secondly, the order of arguments is different:parser.get()has the fallback argument as the last (and keyword-only), whereasparser['section'].get()behaves like a mapping. You can doparser['section'].get('key', 'some-fallback-value')andparser['section'].get('no-such-key')returns None instead of raisingNoOptionError.This makes it difficult to automagically support parser
get*()methods on the section proxy. This is why I decided to adapt a different mechanism: register a converter and a getter is automatically available:>>> cp = ConfigParser() >>> cp.converters['list'] = lambda value: value.strip().split() >>> cp.getlist('section', 'l') ['a', 'b', 'c'] >>> cp['section'].getlist('l') ['a', 'b', 'c'] >>> cp.getdict('section', 'd') Traceback (most recent call last): ... AttributeError: 'ConfigParser' object has no attribute 'getdict' >>> cp['section'].getdict('d') Traceback (most recent call last): ... AttributeError: 'ConfigParser' object has no attribute 'getdict'This ensures that you can easily add new converters in subclasses or single instances and that the parser-level API and section-level API work like they should. This also makes implementing custom getters easier since there's no logic involved besides the conversion. And if you happen to need custom logic anyway, you can register a converter that is a callable class.
jbvsmo commentedon Jul 17, 2013
Was the patch accepted yet? Looks good to me
jbvsmo commentedon Apr 17, 2014
ping?
ambv commentedon Sep 15, 2014
The reason I didn't commit that patch before was that I wasn't sure whether making this change wouldn't create any unexpected backwards incompatibility.
In fact, if I committed the patch as is, it would. I solved this by leaving getint, getfloat and getboolean on the parser class and keeping _get in use.
ambv commentedon Sep 15, 2014
The new implementation also automatically covers get*() methods added on subclasses, no need to use converters= in that case.
python-dev commentedon Sep 15, 2014
New changeset 2c46a4ded259 by Łukasz Langa in branch 'default':
Closes bpo-18159: ConfigParser getters not available on SectionProxy
https://hg.python.org/cpython/rev/2c46a4ded259
New changeset 5eb95d41ee43 by Łukasz Langa in branch 'default':
Closes bpo-18159: ConfigParser getters not available on SectionProxy
https://hg.python.org/cpython/rev/5eb95d41ee43