Search code examples
pythonconfigparser

Sourcing different config files


I need to read a certain path from three different possible places in two config files:

  • A global one, /etc/program.conf
  • A local one, ~/.config/program/config

The local one has a [DEFAULT] section and may or may not have a per case specific section, say [case]. I'd like to

  1. Read the path given by the case-specific section of the local config
  2. Absent that, read the path given by the default section of the local config
  3. Absent that, read the path given by the global config
  4. Absent that (!), provide a default path

I'm using configparser in Python. This is actually not a difficult problem, but the solution I've come up with strikes me as inelegant and clunky. As this is, I think, a fairly common situation, I thought I'd ask more experienced programmers for better solutions.

The code I have is this:

def retrieve_download_path(feed):
    download_path = os.path.expanduser('~/Downloads')
    config = configparser.ConfigParser()
    if os.path.isfile(CONFIG_FILENAME_GLOBAL):
        config.read(CONFIG_FILENAME_GLOBAL)
        if config.has_option('DEFAULT','Download directory'):
            download_path = os.path.expanduser(config['DEFAULT']['Download directory'])
    if os.path.isfile(CONFIG_FILENAME_USER):
        config.read(CONFIG_FILENAME_USER)
        if config.has_option(feed,'Download directory'):
            download_path = os.path.expanduser(config[feed]['Download directory'])
        elif config.has_option('DEFAULT','Download directory'):
            download_path = os.path.expanduser(config['DEFAULT']['Download directory'])
    return download_path

How may I improve this? What's the usual way of sourcing different config files?


Solution

  • configparser seems to provide support for what you're trying to implement, specifically multiple config files and a DEFAULT section.

    Does this do what you want?

    def retrieve_download_path(feed):
        # Read the config files.
        config = configparser.ConfigParser()
        config.read((CONFIG_FILENAME_GLOBAL, CONFIG_FILENAME_USER))
    
        # Resolve the section (configparser doesn't fallback to DEFAULT if the entire section is missing).
        section = feed if config.has_section(feed) else config.default_section
    
        # Extract the download path.
        download_path = config.get(section, 'Download directory', fallback='~/Downloads')
    
        # Expand the user directory.
        return os.path.expanduser(download_path)
    

    The only difference I see is that will allow (and consult) a DEFAULT section in the global config file (which seems desirable).