diff --git a/README.md b/README.md index 2a88242..d9cf094 100644 --- a/README.md +++ b/README.md @@ -587,7 +587,7 @@ args.from_dict({ Note: As with `load`, all required arguments must be present in the dictionary if not already set in the Tap object. All values in the provided dictionary will overwrite values currently in the Tap object. ### Loading from configuration files -Configuration files can be loaded along with arguments with the optional flag `config_files: List[str]`. Arguments passed in from the command line overwrite arguments from the configuration files. Arguments in configuration files that appear later in the list overwrite the arguments in previous configuration files. +Configuration files can be loaded along with arguments with the optional flag `config_files: Iterable[str]`. Arguments passed in from the command line overwrite arguments from the configuration files. Arguments in configuration files that appear later in the list overwrite the arguments in previous configuration files. For example, if you have the config file `my_config.txt` ``` diff --git a/src/tap/tap.py b/src/tap/tap.py index f227f0c..9daa63b 100644 --- a/src/tap/tap.py +++ b/src/tap/tap.py @@ -8,7 +8,7 @@ from pprint import pformat from shlex import quote, split from types import MethodType -from typing import Any, Callable, List, Optional, Sequence, Set, Tuple, TypeVar, Union, get_type_hints +from typing import Any, Callable, Iterable, List, Optional, Sequence, Set, Tuple, TypeVar, Union, get_type_hints from typing_inspect import is_literal_type from tap.utils import ( @@ -53,7 +53,7 @@ def __init__( *args, underscores_to_dashes: bool = False, explicit_bool: bool = False, - config_files: Optional[list[PathLike]] = None, + config_files: Optional[Iterable[PathLike]] = None, **kwargs, ) -> None: """Initializes the Tap instance. @@ -63,7 +63,7 @@ def __init__( :param explicit_bool: Booleans can be specified on the command line as "--arg True" or "--arg False" rather than "--arg". Additionally, booleans can be specified by prefixes of True and False with any capitalization as well as 1 or 0. - :param config_files: A list of paths to configuration files containing the command line arguments + :param config_files: An iterable of paths to configuration files containing the command line arguments (e.g., '--arg1 a1 --arg2 a2'). Arguments passed in from the command line overwrite arguments from the configuration files. Arguments in configuration files that appear later in the list overwrite the arguments in previous configuration files. @@ -689,13 +689,13 @@ def load( return self - def _load_from_config_files(self, config_files: Optional[list[str]]) -> list[str]: - """Loads arguments from a list of configuration files containing command line arguments. + def _load_from_config_files(self, config_files: Optional[Iterable[PathLike]]) -> list[str]: + """Loads arguments from an iterable of configuration files containing command line arguments. - :param config_files: A list of paths to configuration files containing the command line arguments + :param config_files: An iterable of paths to configuration files containing the command line arguments (e.g., '--arg1 a1 --arg2 a2'). Arguments passed in from the command line overwrite arguments from the configuration files. Arguments in configuration files - that appear later in the list overwrite the arguments in previous configuration files. + that appear later in the iterable overwrite the arguments in previous configuration files. :return: A list of the contents of each config file in order of increasing precedence (highest last). """ args_from_config = [] diff --git a/tests/test_load_config_files.py b/tests/test_load_config_files.py index 9046b66..740a731 100644 --- a/tests/test_load_config_files.py +++ b/tests/test_load_config_files.py @@ -1,6 +1,6 @@ import os import sys -from tempfile import TemporaryDirectory +from tempfile import NamedTemporaryFile, TemporaryDirectory import unittest from unittest import TestCase @@ -103,6 +103,25 @@ class MultipleTap(Tap): self.assertEqual(args.a, 1) self.assertEqual(args.b, "two") + def test_config_as_iterator(self) -> None: + class MultipleTap(Tap): + a: int + b: str = "b" + + with TemporaryDirectory() as temp_dir: + fname1, fname2 = os.path.join(temp_dir, "config1.txt"), os.path.join(temp_dir, "config2.txt") + + with open(fname1, "w") as f1, open(fname2, "w") as f2: + f1.write("--b two") + f2.write("--a 1") + + config_iter = (cf for cf in [fname1, fname2]) + + args = MultipleTap(config_files=config_iter).parse_args([]) + + self.assertEqual(args.a, 1) + self.assertEqual(args.b, "two") + def test_multiple_configs_overwriting(self) -> None: class MultipleOverwritingTap(Tap): a: int