Skip to content

Releases: swansonk14/typed-argument-parser

Added Support for Configuration Files

27 Nov 16:43
Compare
Choose a tag to compare

Configuration files may now be loaded along with arguments with the optional flag config_files: List[str]. This addresses #25, thanks to @arbellea.

For example, if you have the config file my_config.txt

--arg1 1
--arg2 two

then you can write

from tap import Tap

class Args(Tap):
    arg1: int
    arg2: str

args = Args(config_files=['my_config']).parse_args()

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.

Subparsers and configure

07 Oct 19:01
9430e12
Compare
Choose a tag to compare

Subparsers

Tap now supports subparsers.

To add a subparser, override the configure method and call self.add_subparser. Optionally, to specify keyword arguments (e.g., help) to the subparser collection, call self.add_subparsers. For example,

class SubparserA(Tap):
    bar: int  # bar help

class SubparserB(Tap):
    baz: Literal['X', 'Y', 'Z']  # baz help

class Args(Tap):
    foo: bool = False  # foo help

    def configure(self):
        self.add_subparsers(help='sub-command help')
        self.add_subparser('a', SubparserA, help='a help')
        self.add_subparser('b', SubparserB, help='b help')

Configure

Tap has a new method called configure which is called at the end of initialization. Two uses of configure are add_argument (previously called in add_arguments, which has now been deprecated) and add_subparser. For example,

class SubparserA(Tap):
    bar: int

class Args(Tap):
    foo: bool = False

    def configure(self):
        self.add_argument('--foo', '-f')
        self.add_subparser('a', SubparserA)

Improved Handling of Unpicklable Attributes

23 Jul 17:15
Compare
Choose a tag to compare

Changed saving and loading to better handle unpicklable attributes

Save now has the skip_unpicklable flag that when set to True skips unpicklable attributes and when loaded produces an UnpicklableObject placeholder for that attribute, indicating that the attribute must be set specially. The signature of save is now:

save(self, path: str, with_reproducibility: bool = True, skip_unpicklable: bool = False) -> None

Support for Native Multiline Help Strings

20 Jul 03:23
3a3e8a1
Compare
Choose a tag to compare

Support for Native Multiline Help Strings

Previously, Tap made it possible to specify the help string for an argument using a single line comment. Now, Tap also supports specifying the help string with a multiline comment below the class variable for the argument. If both a single line comment and a multiline comment are provided, the two are concatenated with a space.

# main.py
from tap import Tap


class Args(Tap):
    arg: bool = False  # This is the one-line summary.
    """
    This is the multiline explanation.
    """


args = Args().parse_args()
usage: main.py [--arg1] [-h]

optional arguments:
  --arg                 (bool, default=False) This is the one-line summary. This
                        is the multiline explanation.
  -h, --help            show this help message and exit

as_dict bug fix

16 Jul 04:36
954cc83
Compare
Choose a tag to compare

as_dict bug fix

The Tap method as_dict failed to include certain attributes, such as properties, when they exist in a super class Tap and not in the sub class Tap. For example, consider the following:

from tap import Tap


class SuperPropertyTap(Tap):
    a: str

    @property
    def pi(self):
        return 3.14


class SubPropertyTap(SuperPropertyTap):
    b: int = 1


super_args = SuperPropertyTap().parse_args()
print(super_args.as_dict())  # includes pi=3.14

sub_args = SubPropertyTap().parse_args()
print(sub_args.as_dict())  # does NOT include pi=3.14 but should

In this example, the super class Tap does include the property pi in its as_dict but the sub class Tap does not. This has now been fixed so that both include the property pi in their as_dict.

Improved error handling and other improvements

14 Jul 04:15
95fc833
Compare
Choose a tag to compare

Improved error handling

We have implemented a number of improvements to error handling and reporting as well as a few other minor changes.

  • Better error handling for older versions of git.

  • Previously, Tap correctly crashed when a Literal arg was passed an argument that was not a valid choice, but it threw a KeyError that was difficult to interpret. Now Tap allows the argparse error to surface when an incorrect choice is provided.

  • Tap used to attempt to cast default values for Set and Tuple to sets and tuples, crashing if the cast was unsuccessful. Now Tap only attempts to cast lists and leaves other default values unchanged, in line with typical argparse functionality.

Other improvements

  • Added a with_reproducibility flag to the save method to allow users to decide whether to save reproducibility information.

  • Previously, the Tap from_dict and load methods returned None but now return self. This enables the following streamlined workflow:

from tap import Tap

class Args(Tap):
    arg: int

args = Args().from_dict({'arg': 10})
  • Tap now has a __version__ attribute, which can be checked as follows:
import tap
print(tap.__version__)  # '1.5.1'

Support for actions, improved argument saving, and other fixes

20 Jun 18:55
c33afaf
Compare
Choose a tag to compare

Added support for action=

In argparse, it is possible to specify actions that modify how the parsed arguments are used. For example, action='append' appends the provided arguments to an existing list. Actions are specified as parameters in calls to the self.add_argument function within the user's override of the add_arguments method. A complete example is as follows:

from tap import Tap
from typing import List

class Args(Tap):
    arg: List[int] = [1, 2]

    def add_arguments(self):
        self.add_argument('--arg', action='append')


args = Args().parse_args('--arg 3 --arg 4'.split())
print(args.arg)  # [1, 2, 3, 4]

We added support for all actions defined by argparse: count, const, append_const, append, extend, store_true, store_false, store_const, and version. However, we don't guarantee consistent behavior with argparse for custom actions.

Improved Argument Saving

The as_dict method has been modified to return not just parsed arguments but also properties and other attributes set by the user. Since save uses as_dict internally, the same modification applies to save. Thus, the new as_dict and save will return a superset of the attributes it returned previously. For example:

from tap import Tap

class Args(Tap):
    arg: int = 2

    def __init__(self):
        super(Args, self).__init__()
        self._prop = 'hi'

    @property
    def prop(self):
        return self._prop

args = Args().parse_args()
print(args.as_dict())  # previous version: {'arg': 2}, new version: {'arg': 2, 'prop': 'hi'}

Fixes

  1. Fixed an issue to ensure that dest= works properly and as_dict correctly dumps all parameters

  2. Fixed reliance on source code parsing to enable editing of Tap code without affecting currently running programs

  3. Fixed an issue to prevent class methods from being included as parsed class variables

Fix to has_git

22 Apr 18:57
641d3d6
Compare
Choose a tag to compare

Previously, has_git only checked whether git was installed on the system. Now, it also checks whether the current working directory is inside a git repo to prevent errors where the code is not inside a git repo.

Built saving, loading, and deepcopying into Tap objects

13 Apr 04:42
6d940a6
Compare
Choose a tag to compare

Several improvements and additions to saving, loading, and deepcopying Tap objects.

  1. save: Improved JSON encoding to enable saving of arbitrary Python objects with pickle strings inside the JSON file. Additionally, added native JSON support for tuples and sets.
  2. load: Implemented a load function which can load args from a JSON file (e.g. the JSON file created by save).
  3. from_dict: Implemented a from_dict function which can load args from a dictionary.
  4. deepcopy: Fixed several issues to enable deepcopying of Tap objects.

Support for Tuples, bool boxed types, and empty boxed types

30 Mar 04:19
ea7388e
Compare
Choose a tag to compare

New support for Tuples, for example:

  • Tuple
  • Tuple[int]
  • Tuple[int, str, float, bool, str]
  • Tuple[int, ...]

New support for bool boxed types, for example:

  • Optional[bool]
  • List[bool]
  • Set[bool]
  • Tuple[bool]

New support for empty boxed types, which are equivalent to Type[str], for example:

  • Optional (same as Optional[str])
  • List (same as List[str])
  • Set (same as Set[str])
  • Tuple (same as Tuple[str])