You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+177-20
Original file line number
Diff line number
Diff line change
@@ -22,9 +22,24 @@ Tap provides the following benefits:
22
22
23
23
See [this poster](https://docs.google.com/presentation/d/1AirN6gpiq4P1L8K003EsXmobVxP3A4AVEIR2KOEQN7Y/edit?usp=sharing), which we presented at [PyCon 2020](https://us.pycon.org/2020/), for a presentation of some of the relevant concepts we used to guide the development of Tap.
24
24
25
+
As of version 1.8.0, Tap includes `tapify`, which runs functions or initializes classes with arguments parsed from the command line. We show an example below.
26
+
27
+
```python
28
+
# square.py
29
+
from tap import tapify
30
+
31
+
defsquare(num: float) -> float:
32
+
return num **2
33
+
34
+
if__name__=='__main__':
35
+
print(f'The square of your number is {tapify(square)}.')
36
+
```
37
+
38
+
Running `python square.py --num 2` will print `The square of your number is 4.0.`. Please see [tapify](#tapify) for more details.
39
+
25
40
## Installation
26
41
27
-
Tap requires Python 3.6+
42
+
Tap requires Python 3.7+
28
43
29
44
To install Tap from PyPI run:
30
45
```
@@ -46,31 +61,26 @@ pip install -e .
46
61
*[Tap is Python-native](#tap-is-python-native)
47
62
*[Tap features](#tap-features)
48
63
+[Arguments](#arguments)
49
-
+[Help string](#help-string)
50
-
+[Flexibility of `configure`](#flexibility-of--configure-)
64
+
+[Tap help](#tap-help)
65
+
+[Configuring arguments](#configuring-arguments)
51
66
-[Adding special argument behavior](#adding-special-argument-behavior)
52
67
-[Adding subparsers](#adding-subparsers)
53
68
+[Types](#types)
54
-
-[`str`, `int`, and `float`](#-str----int---and--float-)
55
-
-[`bool`](#-bool-)
56
-
-[`Optional`](#-optional-)
57
-
-[`List`](#-list-)
58
-
-[`Set`](#-set-)
59
-
-[`Tuple`](#-tuple-)
60
-
-[`Literal`](#-literal-)
61
-
-[`Union`](#-union-)
62
-
-[Complex Types](#complex-types)
63
-
+[Argument processing with `process_args`](#argument-processing-with--process-args-)
69
+
+[Argument processing](#argument-processing)
64
70
+[Processing known args](#processing-known-args)
65
71
+[Subclassing](#subclassing)
66
72
+[Printing](#printing)
67
73
+[Reproducibility](#reproducibility)
68
-
-[Reproducibility info](#reproducibility-info)
69
74
+[Saving and loading arguments](#saving-and-loading-arguments)
70
-
-[Save](#save)
71
-
-[Load](#load)
72
-
-[Load from dict](#load-from-dict)
73
75
+[Loading from configuration files](#loading-from-configuration-files)
76
+
*[tapify](#tapify)
77
+
+[Examples](#examples)
78
+
-[Function](#function)
79
+
-[Class](#class)
80
+
-[Dataclass](#dataclass)
81
+
+[tapify help](#tapify-help)
82
+
+[Command line vs explicit arguments](#command-line-vs-explicit-arguments)
83
+
+[Known args](#known-args)
74
84
75
85
## Tap is Python-native
76
86
@@ -143,7 +153,7 @@ class MyTap(Tap):
143
153
default_arg: str='default value'
144
154
```
145
155
146
-
### Help string
156
+
### Tap help
147
157
148
158
Single line and/or multiline comments which appear after the argument are automatically parsed into the help string provided when running `python main.py -h`. The type and default values of arguments are also provided in the help string.
149
159
@@ -172,7 +182,7 @@ optional arguments:
172
182
-h, --help show this help message and exit
173
183
```
174
184
175
-
### Flexibility of `configure`
185
+
### Configuring arguments
176
186
To specify behavior beyond what can be specified using arguments as class variables, override the `configure` method.
177
187
`configure` provides access to advanced argument parsing features such as `add_argument` and `add_subparser`.
178
188
Since Tap is a wrapper around argparse, Tap provides all of the same functionality.
@@ -329,7 +339,7 @@ print(f'{args.aged_person.name} is {args.aged_person.age}') # Tapper is 27
329
339
```
330
340
331
341
332
-
### Argument processing with `process_args`
342
+
### Argument processing
333
343
334
344
With complex argument parsing, arguments often end up having interdependencies. This means that it may be necessary to disallow certain combinations of arguments or to modify some arguments based on other arguments.
to get the resulting `args = {'arg1': 21, 'arg2': 'two three four'}`
566
576
567
577
The legacy parsing behavior of using standard string split can be re-enabled by passing `legacy_config_parsing=True` to `parse_args`.
578
+
579
+
## tapify
580
+
581
+
`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.
582
+
583
+
### Examples
584
+
585
+
#### Function
586
+
587
+
```python
588
+
# square_function.py
589
+
from tap import tapify
590
+
591
+
defsquare(num: float) -> float:
592
+
"""Square a number.
593
+
594
+
:param num: The number to square.
595
+
"""
596
+
return num **2
597
+
598
+
if__name__=='__main__':
599
+
squared = tapify(square)
600
+
print(f'The square of your number is {squared}.')
601
+
```
602
+
603
+
Running `python square_function.py --num 5` prints `The square of your number is 25.0.`.
604
+
605
+
#### Class
606
+
607
+
```python
608
+
# square_class.py
609
+
from tap import tapify
610
+
611
+
classSquarer:
612
+
def__init__(self, num: float) -> None:
613
+
"""Initialize the Squarer with a number to square.
614
+
615
+
:param num: The number to square.
616
+
"""
617
+
self.num = num
618
+
619
+
defget_square(self) -> float:
620
+
"""Get the square of the number."""
621
+
returnself.num **2
622
+
623
+
if__name__=='__main__':
624
+
squarer = tapify(Squarer)
625
+
print(f'The square of your number is {squarer.get_square()}.')
626
+
```
627
+
628
+
Running `python square_class.py --num 2` prints `The square of your number is 4.0.`.
629
+
630
+
#### Dataclass
631
+
632
+
```python
633
+
# square_dataclass.py
634
+
from dataclasses import dataclass
635
+
636
+
from tap import tapify
637
+
638
+
@dataclass
639
+
classSquarer:
640
+
"""Squarer with a number to square.
641
+
642
+
:param num: The number to square.
643
+
"""
644
+
num: float
645
+
646
+
defget_square(self) -> float:
647
+
"""Get the square of the number."""
648
+
returnself.num **2
649
+
650
+
if__name__=='__main__':
651
+
squarer = tapify(Squarer)
652
+
print(f'The square of your number is {squarer.get_square()}.')
653
+
```
654
+
655
+
Running `python square_dataclass.py --num -1` prints `The square of your number is 1.0.`.
656
+
657
+
### tapify help
658
+
659
+
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:
660
+
661
+
```
662
+
usage: square_function.py [-h] --num NUM
663
+
664
+
Square a number.
665
+
666
+
options:
667
+
-h, --help show this help message and exit
668
+
--num NUM (float, required) The number to square.
669
+
```
670
+
671
+
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.
672
+
673
+
### Command line vs explicit arguments
674
+
675
+
`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.
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.)
696
+
697
+
### Known args
698
+
699
+
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.
700
+
701
+
```python
702
+
# person.py
703
+
from tap import tapify
704
+
705
+
defprint_name(name: str) -> None:
706
+
"""Print a person's name.
707
+
708
+
:param name: A person's name.
709
+
"""
710
+
print(f'My name is {name}.')
711
+
712
+
defprint_age(age: int) -> None:
713
+
"""Print a person's age.
714
+
715
+
:param name: A person's age.
716
+
"""
717
+
print(f'My age is {age}.')
718
+
719
+
if__name__=='__main__':
720
+
tapify(print_name, known_only=True)
721
+
tapify(print_age, known_only=True)
722
+
```
723
+
724
+
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.
0 commit comments