I have a config file with the following contents.
[Default]
file_list = ['dataset1/*.wav', 'dataset2/*.wav', 'dataset3/*.wav', 
'dataset4/*.wav']
which is a line break that most of the time works in Python. I parse it with this
import configargparse
p = configargparse.ArgParser()
p.add('-c', '--my-config', required=True, is_config_file=True, help='config file path')
p.add('--file_list', action="append", required=False, help='path to genome file')
args = p.parse_args()
by making the appropriate call
python file.py --my-config=config.ini
The problem is (not surprisingly):
file.py: error: unrecognized arguments: --'dataset4/*.wav'] true
I assume this happens because it expects a new arg in the config file. I also tried different line continuation methods.
How can I input multiple line lists using configargparse? If I can't, what is a minimal alternative solution to config file list inputs?
I came across the same problem. I decided to modify the default parser a bit and create my parser which supports multiple lines. I only added a few lines of code. It looks something like this:
import configargparse
from collections import OrderedDict
import re
class LongLineConfigFileParser(configargparse.ConfigFileParser):
    """Based on a simplified subset of INI and YAML formats. Here is the
    supported syntax:
        # this is a comment
        ; this is also a comment (.ini style)
        ---            # lines that start with --- are ignored (yaml style)
        -------------------
        [section]      # .ini-style section names are treated as comments
        # how to specify a key-value pair (all of these are equivalent):
        name value     # key is case sensitive: "Name" isn't "name"
        name = value   # (.ini style)  (white space is ignored, so name = value same as name=value)
        name: value    # (yaml style)
        --name value   # (argparse style)
        # how to set a flag arg (eg. arg which has action="store_true")
        --name
        name
        name = True    # "True" and "true" are the same
        # how to specify a list arg (eg. arg which has action="append")
        fruit = [apple, orange, lemon]
        indexes = [1, 12, 35 , 40]
        # how to break a long line into multiple lines:
        fruit = [apple, \
        orage, \
        lemon]
    """
    def parse(self, stream):
        """Parses the keys + values from a config file."""
        items = OrderedDict()
        pre_line = '' # Used to support multiple lines
        for i, line in enumerate(stream):
            line = pre_line + line
            line = line.strip()
            if not line or line[0] in ["#", ";", "["] or line.startswith("---"):
                continue
            # Used to support multiple lines
            if line.endswith('\\'):
                pre_line = line.replace('\\', '').strip()
                continue
            else:
                pre_line = ''
            white_space = "\\s*"
            key = r"(?P<key>[^:=;#\s]+?)"
            value = white_space+r"[:=\s]"+white_space+"(?P<value>.+?)"
            comment = white_space+"(?P<comment>\\s[;#].*)?"
            key_only_match = re.match("^" + key + comment + "$", line)
            if key_only_match:
                key = key_only_match.group("key")
                items[key] = "true"
                continue
            key_value_match = re.match("^"+key+value+comment+"$", line)
            if key_value_match:
                key = key_value_match.group("key")
                value = key_value_match.group("value")
                if value.startswith("[") and value.endswith("]"):
                    # handle special case of lists
                    value = [elem.strip() for elem in value[1:-1].split(",")]
                items[key] = value
                continue
            raise configargparse.ConfigFileParserException("Unexpected line {} in {}: {}".format(i,
                getattr(stream, 'name', 'stream'), line))
        return items
To use it you only need to add config_file_parser_class=LongLineConfigFileParser when calling the ArgParser:
parser = configargparse.ArgParser(default_config_files=['DefaultParams.txt'],
                                  config_file_parser_class=LongLineConfigFileParser)
Hope this helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With