Documentation
Lazyparser is a small module that automates the creation of command-line interfaces. For this purpose, it uses rich_click.
Basic usage
Without docstring
Let's say you have a function print_word
that prints two words. To
create a command line interface, you can simply type this in a file
example.py
import lazyparser as lp
@lp.parse
def print_word(a, b):
print(a)
print(b)
if __name__ == "__main__":
print_word()
Then you can display the help of example.py
by typing:
python example.py --help # to display the help of your program
This will print the following message :
Usage: example.py --b STRING --a STRING
╭─ Optional arguments ─────────────────────────────────╮
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────╯
╭─ Required arguments ─────────────────────────────────╮
│ * --a -a TEXT param a [required] │
│ * --b -b TEXT param b [required] │
╰──────────────────────────────────────────────────────╯
If there is no docstring in the decorated print_word
function, the
type of every parameters is set to str
. In addition, the full names
of the parser arguments (defined with --
) correspond to the
parameter names of the decorated function. The short names (called
with -
) are computed on the fly and correspond to the first letter of
the related parameter. For each parameter in the decorated function, a basic help message is auto-generated, though this default message provides minimal information about what each parameter actually does. To customize how the help
message will be displayed, you can write a docstring in the decorated
function.
With docstring
Lazyparser automates the creation of command-line interfaces by taking advantage of the docstring in the decorated function and the type of the parameters indicated in the function definition. By default, lazyparser parses the docstring in PyCharm (A Python IDE) format.
Example: (file example.py
)
import lazyparser as lp
@lp.parse
def multiplication(a: float, b: float):
"""Multiply a by b
:param a: a number a
:param b: a number b
"""
print(a * b)
if __name__ == "__main__":
multiplication()
Then, you can display the help of example.py
by typing:
$ python example.py -h # to display the help of your program
Usage: example.py --b FLOAT --a FLOAT
Multiply a by b
╭─ Optional arguments ─────────────────────────────────╮
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────╯
╭─ Required arguments ─────────────────────────────────╮
│ * --a -a FLOAT a number a [required] │
│ * --b -b FLOAT a number b [required] │
╰──────────────────────────────────────────────────────╯
Optional arguments
In the previous example, you can see that --a and --b are required arguments. To make an argument optional, you can give it a default value in the function definition. For example, if you want to make the argument --b optional, you can define it as follows:
# same as above
@lp.parse
def multiplication(a: float, b: float = 5):
"""Multiply a by b
:param a: a number a
:param b: a number b
"""
print(a * b)
# same as above
$ python example.py --help
Usage: example.py --a FLOAT [--b FLOAT]
Multiply a by b
╭─ Optional arguments ─────────────────────────────────╮
│ --help -h Show this message and exit. │
│ --b -b FLOAT a number b [default: 5] │
╰──────────────────────────────────────────────────────╯
╭─ Required arguments ─────────────────────────────────╮
│ * --a -a FLOAT a number a [required] │
╰──────────────────────────────────────────────────────╯
standalone mode
By default the standalone mode is enabled, this means that nothing can be executed after the call of the decorated function, for example this code won't print anything after "starting":
import lazyparser as lp
@lp.parse
def multiplication(a: float, b: float):
"""Multiply a by b
:param a: a number a
:param b: a number b
"""
print("starting")
return a * b
if __name__ == "__main__":
v = multiplication() # nothing executed after this
print(v)
$ python example.py -a 5 -b 10
starting
To make the code continue, you can disable the click standalone mode by using the sandalone(False)
decorator
Example:
import lazyparser as lp
@lp.standalone(False)
@lp.parse
def multiplication(a: float, b: float):
"""Multiply a by b
:param a: a number a
:param b: a number b
"""
print("starting")
return a * b
if __name__ == "__main__":
v = multiplication() # noting executed after this
print(v)
$ python example.py -a 5 -b 10
starting
50.0
Customize the docstring environment
If you are not a fan of Pycharm docstrings, you can set your own
docstring environment by using the decorator docstrings
the decorator docstrings
can takes up to 4 arguments :
delim1
: the string preceding the definition of a parameter. :param is the default value. This parameter can be an empty docstring if nothing precedes the parameter name in the docstring of the decorated function.delim2
: the string that comes right after the name of the parameter. It MUST be defined and can't be an empty string or a space, tabulation, etc... It's default value is:
header
: the header preceding the argument names. By default, corresponds to an empty string.tab
: the number of spaces at the beginning of each line in the docstring. By default, it is equal to 4.
Note
the text set before parameters definition (or the parameters definition header) is considered as being a part of the description of the function.
Here is an example of how to use docstrings
# code in example.py file
import lazyparser as lp
@lp.docstrings(delim1='', delim2=':', header="Arguments:")
@lp.parse
def multiplication(a: float, b: float):
"""
Multiply a by b
Arguments:
a : a number a
b : a number b
"""
print(a * b)
if __name__ == "__main__":
multiplication()
Type of parameters
Lazyparser can handle different types of parameters (defined in the function definition):
int
float
bool
str
: default type if nothing is specified in the function definition.tuple
: A tuple object used to handle multiple values.
tuple
type must have at least one subtype defined in the function definition.
For example, if we want to define a tuple with one integer, we can set the type tuple[int]
Example of tuple
usage :
import lazyparser as lp
@lp.docstrings(delim1="", delim2=":", header="Arguments:")
@lp.parse
def print_value(a: tuple[int]):
"""
Display the parameter a
:param a: The argument a
"""
print(f"a = {a}")
if __name__ == "__main__":
print_value()
Defining a tuple with an elipsis as the second type tuple[int, ...]
allows you to give as many data as you by repeating -a
in the command line interface. Here is an example:
# same as above
def print_value(a: tuple[int, ...]):
# same as above
$ python example.py -a 1 -a 2 -a 3 -a 20
a = (1, 2, 3, 20)
Click types
You can use custom click types (see this page instead of the simple ones that you give in the function signature. For example if you want to use the custom type click.IntRange(0, 10)
, you can do so in the lazyparser.parse
function using the following syntax:
@lazyparser.parse(param=click.IntRange(0, 10))
where param
is the name of the parameter you want to use the custom type for.
Note
the type of param given in the function signature should be int
in this case otherwise you will get an warning telling you that the click type will be applied.
Example:
import lazyparser as lp
@lp.parse(values=lp.click.IntRange(0, 10))
def print_value(values : int):
"""
Print an input number between 0 and 10
"""
print("Your number is", values)
if __name__ == "__main__":
print_value()
$ python example.py -v 15
Usage: example.py [OPTIONS]
Try 'example.py --help' for help
╭─ Error ────────────────────────────────────────────────────────────╮
│ Invalid value for '--values' / '-v': 15 is not in the range │
│ 0<=x<=10. │
╰────────────────────────────────────────────────────────────────────╯
$ python example.py -v 8
Your number is 8
Boolean flag
Sometimes, you only want to call an argument without giving it a value when calling your program. This applies automatically and only for Booleanvalues
Here is an example :
import lazyparser as lp
@lp.parse
def flag_func(a: bool = False):
"""
Give the value of the flag
:param a: the boolean flag
"""
print(f"value of a: {a}")
if __name__ == "__main__":
flag_func()
$ python example.py -a
value of a: True
$ python example.py
value of a: False
Create an epilog
To add an epilog in the help of the parser simply use the decorator
epilog
. This function must be called before the decorator parse
.
@lp.epilog("my epilog")
@lp.parse
...
Argument groups
By default, Lazyparser creates two groups of arguments:
Optional arguments
Required arguments
But, you may want to create argument groups with custom names. This can
be done with the decorator groups
that takes a group name and a list of
options defined in the group. The order of groups given in the groups decorator will be the same as the order of group displayed in the help message.
This function must be called before the decorator parse
.
Example
Below, in an file named example.py
. You can see a function that prints
the name and the first name of a user and also multiply two numbers:
import lazyparser as lp
@lp.groups(help=["help"], Numbers=["x", "y"], User=["first_name", "name"])
@lp.parse
def multiply(first_name: str, name: str, x: float, y: float):
"""Say hello name fist_name and multiply x by y.
:param first_name: your first name
:param name: your name
:param x: a number x
:param y: a number y
"""
print(f"Hello {first_name} {name} !")
print(f"{x} x {y} = {x * y}")
if __name__ == "__main__":
multiply()
If you run:
python example.py -h
It displays:
Usage:
example.py
--y FLOAT --x FLOAT --name TEXT --first_name TEXT
Say hello name fist_name and multiply x by y.
╭─ help ───────────────────────────────────────────────╮
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────╯
╭─ Numbers ────────────────────────────────────────────╮
│ * --x -x FLOAT a number x [required] │
│ * --y -y FLOAT a number y [required] │
╰──────────────────────────────────────────────────────╯
╭─ User ───────────────────────────────────────────────╮
│ * --first_name -f TEXT your first name │
│ [required] │
│ * --name -n TEXT your name [required] │
╰──────────────────────────────────────────────────────╯
Version option
In order to have a option to display the version you can use the version
decoartor.
Example
import lazyparser as lp
@lp.version("1.0")
@lp.parse
def multiplication(a: float, b: float):
"""
Multiply a by b
:param a : a number a
:param b : a number b
"""
print(a * b)
if __name__ == "__main__":
multiplication()
If you run:
$ python example.py -h
Usage: example.py --b FLOAT --a FLOAT
Multiply a by b
╭─ Optional arguments ─────────────────────────────────╮
│ --help -h Show this message and exit. │
│ --version Show the version and exit. │
╰──────────────────────────────────────────────────────╯
╭─ Required arguments ─────────────────────────────────╮
│ * --a -a FLOAT a number a [required] │
│ * --b -b FLOAT a number b [required] │
╰──────────────────────────────────────────────────────╯
$ python example.py --version
example.py, version 1.0
Warning
Your function cannot contain a parameter named version
anymore.
Using multiple decorators
You can use multiple decorators like lp.version
, lp.standalone
, lp.groups
and lp.docstrings
in any order with the exception of the lp.parse
decorator which should be the first one to decorate your function.
import lazyparser as lp
@lp.docstrings(delim1="-", delim2=":", header="@Args") # In any order (expect the first)
@lp.groups(values=["a", "b"], Help=["help"]) # In any order (expect the first)
@lp.version("1.0") # In any order (expect the first)
@lp.standalone(True) # In any order (expect the first)
@lp.parse # must be the first decorator
def multiplication(a: float, b: float):
"""
Multiply a by b
@Args
- a : a number a
- b : a number b
"""
print(a * b)
if __name__ == "__main__":
multiplication()