Skip to content

ConfigParser has_section() documentation is oblique and not clear #132478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
pacohope opened this issue Apr 13, 2025 · 8 comments
Closed

ConfigParser has_section() documentation is oblique and not clear #132478

pacohope opened this issue Apr 13, 2025 · 8 comments
Labels
docs Documentation in the Doc dir pending The issue will be closed if no feedback is provided

Comments

@pacohope
Copy link

Documentation

The documentation on has_section() currently says:

Indicates whether the named section is present in the configuration. The default section is not acknowledged.

First, it doesn't give indication of the method's return type (boolean), it's just implied. Secondly "is not acknowledged" is an unhelpful and oblique way of saying "returns False". Documentation should say what code does do, not what it doesn't. My recommendation for clearer documentation:

Returns True if the named section is present in the configuration. Returns False if the named section is not present in the configuration. Returns False if section is 'default'. Returns False if default_section was set on initialization, and section is the same as the value of default_section.

I was surprised at the behaviour of has_section() when I use default_section on initialization. After investigating I see that some of this is expected behaviour. I recommend adding the sentence "Returns False if section is 'default'" to the documentation, because that seems to be true, whether I specified default_section or not. If this is expected behaviour, then the docs should be updated.

The code snippet below produces the following output. Test 3 is the one that surprises me. It doesn't seem consistent with the documentation because in Test 3, default is not the name of the default section. All the other cases make sense and seem consistent with the documentation:

Test 1: default_section='section1' and no section named [default] present
  has_section1: False, has_section2: True, has_default: False

Test 2: default_section not defined and no section named [default] present
  has_section1: True, has_section2: True, has_default: False

Test 3: default_section='section1' and [default] section also present
  has_section1: False, has_section2: True, has_default: False

Test 4: default_section not defined and [default] section is present
  has_section1: True, has_section2: True, has_default: False

code snippet

from configparser import ConfigParser, ExtendedInterpolation

configstring = """
[section1]
testkey = True

[section2]
demokey = True
"""

print("Test 1: default_section='section1' and no section named [default] present")
config = ConfigParser(default_section='section1', interpolation=ExtendedInterpolation())
config.read_string(configstring)
print("  has_section1: {}, has_section2: {}, has_default: {}\n".format(config.has_section('section1'),
  config.has_section('section2'),
  config.has_section('default')))

print("Test 2: default_section not defined and no section named [default] present")
del config
config = ConfigParser(interpolation=ExtendedInterpolation())
config.read_string(configstring)
print("  has_section1: {}, has_section2: {}, has_default: {}\n".format(config.has_section('section1'),
  config.has_section('section2'),
  config.has_section('default')))

configstring = """
[section1]
testkey = True

[section2]
demokey = True
"""
print("Test 3: default_section='section1' and [default] section also present")
config = ConfigParser(default_section='section1', interpolation=ExtendedInterpolation())
config.read_string(configstring)
print("  has_section1: {}, has_section2: {}, has_default: {}\n".format(config.has_section('section1'),
  config.has_section('section2'),
  config.has_section('default')))

print("Test 4: default_section not defined and [default] section is present")
del config
config = ConfigParser(interpolation=ExtendedInterpolation())
config.read_string(configstring)
print("  has_section1: {}, has_section2: {}, has_default: {}\n".format(config.has_section('section1'),
  config.has_section('section2'),
  config.has_section('default')))
@pacohope pacohope added the docs Documentation in the Doc dir label Apr 13, 2025
@donBarbos
Copy link
Contributor

donBarbos commented Apr 13, 2025

Thank you for opening the issue, it looks like you are indeed right, your version seems more accurate.
I reproduced the behavior of 3.9-3.14, including the main branch, and the result was identical.

Do you want to send PR?

@picnixz
Copy link
Member

picnixz commented Apr 13, 2025

cc @jaraco

@picnixz
Copy link
Member

picnixz commented Apr 13, 2025

First, it doesn't give indication of the method's return type (boolean),

In general, when we say "indicate whether", it's something that can be used in a if-context.

Secondly "is not acknowledged" is an unhelpful and oblique way of saying "returns False".

I wouldn't say it's not helpful. It's another way to say that it's being ignored. In the 3rd example, default_section='section1' indicates that the default section is "section1". When we do has_section("section1") we want to konw whether we have a section named "section1" but that is not the default section. Since this is not the case, it returns false.

@picnixz
Copy link
Member

picnixz commented Apr 13, 2025

To be precise:

It doesn't seem consistent with the documentation because in Test 3, default is not the name of the default section. All the other cases make sense and seem consistent with the documentation:

Actually, that's right, but still, there is no section named "default" in the parsed string or am I wrong? the only sections that exist are "section1" and "section2" and since section1 is being defined as the name of the default section, it's ignored. So the only section that can be found is "section2" and "has_section" returns true for this one.

Maybe what you find unclear is the fact that "default section" does not mean the section named "default" but the section defined to be the default one (note that the docs emphasize "default section" and not just "default")

@picnixz picnixz added the pending The issue will be closed if no feedback is provided label Apr 14, 2025
@vadmium
Copy link
Member

vadmium commented Apr 15, 2025

Agreed that the current wording is painful to use.

Returns False if section is 'default'.

I don’t think this is the case at all. I would remove that sentence.

>>> c = ConfigParser()
>>> c.read_string('[default]\n')
>>> c.has_section('default')
True

Returns False if default_section was set on initialization, and section is the same as the value of default_section.

I haven’t studied the implementation, but it seems more accurate to say something like “Returns False if section only names a section that was recognized as a special default section.”

>>> c = ConfigParser(default_section='initial default')
>>> c.default_section = 'new default'
>>> c.read_string('''
... [initial default]
... [new default]
... ''')
>>> c.has_section('initial default')
True
>>> c.has_section('new default')
False

@pacohope
Copy link
Author

First, it doesn't give indication of the method's return type (boolean),

In general, when we say "indicate whether", it's something that can be used in a if-context.

Secondly "is not acknowledged" is an unhelpful and oblique way of saying "returns False".

I wouldn't say it's not helpful. It's another way to say that it's being ignored.

Python is a programming language used the world over by millions and millions of developers. A huge number of those developers do not speak English as a first language. Some don't speak much English at all, and rely on the volunteer translations or machine translation of the English documentation to read it. Phrases that seem clear to a native English speaker (like "is not acknowledged") are not equally obvious to a non-native speaker. I think the job of documentation is to be direct, clear, and boring. Colourful language hurts more than it helps.

I will make one last argument and then give up.

Consider the Spanish language translation of that phrase: No se permite default section. It means "The default section is not allowed." The Brazilian Portuguese translation says "A seção "padrão não é reconhecida", which seems to mean "The "default" section is not recognized." The Chinese translation of the phrase renders this as "default section 不包含在内。", and Google translate says that means "The default section is not included." None of these translations sounds accurate. I wanted to use the French translation as an example, but the translators haven't gotten that far. French speakers have to wrestle with the English on that phrase. If the English version said something super boring like "returns False...," I'm sure the translations would have been much better. There's no argument in favour of oblique phrasing in technical documentation, and there are lots of arguments against.

@pacohope
Copy link
Author

Welp. I get to be embarrassed. My supposed demo code has a bug and my understanding of the code was wrong, too. My comment on the second configstring said it had a [default] section, but it doesn't.

I appreciate @vadmium 's example because it is super tight: the absolute minimum amount of code to get at the issue. And that's how I figured out all my misunderstandings.

  1. The documentation clearly says By default, section names are case sensitive but keys are not. Let's set aside whether that is a good design. It is what it is, and it is documented.
  2. The documentation clearly says the default section is "normally named DEFAULT"
  3. All my tests assumed section names were case insensitive, so I was testing with [default] when I should have tested with [DEFAULT].

So I still think the English version of the documentation should be clearer, which still fits the title of the issue. Where I thought I had identified inconsistent behaviour, however, I was wrong. If you run my tests (or @vadmium 's) with the right case on the section names, everything comes out exactly as it should.

I'm sorry I spun up a bug report on a non-bug. PEBKAC

@AA-Turner
Copy link
Member

@pacohope feel free to use this issue to submit a PR to reword the relevant section.

A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation in the Doc dir pending The issue will be closed if no feedback is provided
Projects
Status: Todo
Development

No branches or pull requests

5 participants