Tapify
`tapify` makes it possible to run functions or initialize objects via command line arguments. This is inspired by Google's [Python Fire](https://github.com/google/python-fire), but `tapify` also automatically casts command line arguments to the appropriate types based on the type hints. Under the hood, `tapify` implicitly creates a Tap object and uses it to parse the command line arguments, which it then uses to run the function or initialize the class. We show a few examples below.
Examples
Function
python
square_function.py
from tap import tapify
def square(num: float) -> float:
"""Square a number.
:param num: The number to square.
"""
return num ** 2
if __name__ == '__main__':
squared = tapify(square)
print(f'The square of your number is {squared}.')
Running `python square_function.py --num 5` prints `The square of your number is 25.0.`.
Class
python
square_class.py
from tap import tapify
class Squarer:
def __init__(self, num: float) -> None:
"""Initialize the Squarer with a number to square.
:param num: The number to square.
"""
self.num = num
def get_square(self) -> float:
"""Get the square of the number."""
return self.num ** 2
if __name__ == '__main__':
squarer = tapify(Squarer)
print(f'The square of your number is {squarer.get_square()}.')
Running `python square_class.py --num 2` prints `The square of your number is 4.0.`.
Dataclass
python
square_dataclass.py
from dataclasses import dataclass
from tap import tapify
dataclass
class Squarer:
"""Squarer with a number to square.
:param num: The number to square.
"""
num: float
def get_square(self) -> float:
"""Get the square of the number."""
return self.num ** 2
if __name__ == '__main__':
squarer = tapify(Squarer)
print(f'The square of your number is {squarer.get_square()}.')
Running `python square_dataclass.py --num -1` prints `The square of your number is 1.0.`.
Help
The help string on the command line is set based on the docstring for the function or class. For example, running `python square_function.py -h` will print:
usage: square_function.py [-h] --num NUM
Square a number.
options:
-h, --help show this help message and exit
--num NUM (float, required) The number to square.
Note that for classes, if there is a docstring in the `__init__` method, then `tapify` sets the help string description to that docstring. Otherwise, it uses the docstring from the top of the class.
Command line vs explicit arguments
`tapify` can simultaneously use both arguments passed from the command line and arguments passed in explicitly in the `tapify` call. Arguments provided in the `tapify` call override function defaults, and arguments provided via the command line override both arguments provided in the `tapify` call and function defaults. We show an example below.
python
add.py
from tap import tapify
def add(num_1: float, num_2: float = 0.0, num_3: float = 0.0) -> float:
"""Add numbers.
:param num_1: The first number.
:param num_2: The second number.
:param num_3: The third number.
"""
return num_1 + num_2 + num_3
if __name__ == '__main__':
added = tapify(add, num_2=2.2, num_3=4.1)
print(f'The sum of your numbers is {added}.')
Running `python add.py --num_1 1.0 --num_2 0.9` prints `The sum of your numbers is 6.0.`. (Note that `add` took `num_1 = 1.0` and `num_2 = 0.9` from the command line and `num_3=4.1` from the `tapify` call due to the order of precedence.)
Known args
Calling `tapify` with `known_only=True` allows `tapify` to ignore additional arguments from the command line that are not needed for the function or class. If `known_only=False` (the default), then `tapify` will raise an error when additional arguments are provided. We show an example below where `known_only=True` might be useful for running multiple `tapify` calls.
python
person.py
from tap import tapify
def print_name(name: str) -> None:
"""Print a person's name.
:param name: A person's name.
"""
print(f'My name is {name}.')
def print_age(age: int) -> None:
"""Print a person's age.
:param name: A person's age.
"""
print(f'My age is {age}.')
if __name__ == '__main__':
tapify(print_name, known_only=True)
tapify(print_age, known_only=True)
Running `python person.py --name Jesse --age 1` prints `My name is Jesse.` followed by `My age is 1.`. Without `known_only=True`, the `tapify` calls would raise an error due to the extra argument.
Other Changes
https://github.com/swansonk14/typed-argument-parser/pull/76 Add description support for Tap based on the `__doc__` attribute.
https://github.com/swansonk14/typed-argument-parser/pull/81 Fix help text around positional arguments (resolves https://github.com/swansonk14/typed-argument-parser/issues/79).
https://github.com/swansonk14/typed-argument-parser/pull/82 Add README warning about unpickling untrusted data (resolves https://github.com/swansonk14/typed-argument-parser/issues/73).
https://github.com/swansonk14/typed-argument-parser/pull/83 Fix handling of decorated classes (resolves https://github.com/swansonk14/typed-argument-parser/issues/80).
https://github.com/swansonk14/typed-argument-parser/pull/91 Add support for single-quoted documentation (resolves https://github.com/swansonk14/typed-argument-parser/issues/84).
https://github.com/swansonk14/typed-argument-parser/pull/96 Add support for Python 3.11.