Add options to click commands based on inspecting functions
Project description
click-inspect
Add options to click commands based on inspecting functions
Installation
Usage
Suppose an application containing an API function for which we would like to expose a command line interface. That function expects one or two arguments with internal data types and a bunch of configuration options. For example:
def display_data(data: List[Tuple[int, int]],
*,
size: int, symbol: str = 'x', empty: str = ' ') -> str:
"""Display the given data points in a 2D ASCII grid.
Args:
data (list of (int, int)): The data points as x- and y-tuples.
size (int): Size of the grid in both dimensions.
symbol (str): Symbol for displaying data points.
empty (str): Symbol for displaying empty space.
Returns:
str: The string containing the grid.
"""
grid = [[empty]*size for _ in range(size)]
for x, y in data:
grid[y][x] = symbol
top = bottom = ('+', *'-'*size, '+')
grid = (top, *(('|', *row, '|') for row in grid), bottom)
return '\n'.join(map(''.join, grid))
Here the type of the first argument, data
, is an internal aspect of the application, but the remaining arguments are generic options.
Now we want to create a click interface for using this function from the command line. Specifically we want it to work on JSON files of the following format:
{"data": [[1, 1], [2, 4], [3, 3]]}
So the only thing our command needs to do is to read the JSON file and convert the content in a way that it is compatible with what display_data
expects:
import json
import click
@click.command()
@click.argument('file')
def display(file):
with open(file) as fh:
data = json.load(fh)['data']
data = [[int(x) for x in row] for row in data]
print(display_data(data))
if __name__ == '__main__':
display()
Then we can run the program in the following way:
$ python example.py test.json
+-----+
| |
| x |
| |
| x |
| x |
+-----+
Now this only uses the default configuration of the display_data
function and we also want to expose these optional parameters to the command line interface. We can do so by adding a few options:
@click.command()
@click.argument('file')
@click.option('--size', default=5, help='Size of the grid in both dimensions.')
@click.option('--symbol', default='x', help='Symbol for displaying data points.')
@click.option('--empty', default=' ', help='Symbol for displaying empty space.')
def display(file, size, symbol, empty):
with open(file) as fh:
data = json.load(fh)['data']
data = [[int(x) for x in row] for row in data]
print(display_data(data, size=size, symbol=symbol, empty=empty))
But that's a lot of code duplication. We duplicated the parameter names, the default values and the help text from the docstring.
Also if we decide to add a new parameter to display_data
we need to update the command as well.
This is where click-inspect
comes in handy. Using the add_options_from
decorator we can simply add all optional parameters from display_data
to the display
command without code duplication:
from click_inspect import add_options_from
@click.command()
@click.argument('file')
@add_options_from(display_data)
def display(file, **kwargs):
with open(file) as fh:
data = json.load(fh)['data']
data = [[int(x) for x in row] for row in data]
print(display_data(data, **kwargs))
Customization
The add_options_from
decorator supports various keyword parameters which can be used for
customizing the way options are created from parameters. Please refer to the docstring
of add_options_from
for more information. In the following some possibilities are shown:
# This adds only the `size` and `empty` parameters as options:
@add_options_from(display_data, include={'size', 'empty'})
# This has a similar effect by excluding the `symbol` parameter:
@add_options_from(display_data, exclude={'symbol'})
# This specifies custom option-names for some of the parameters:
@add_options_from(display_data, names={'size': ['-s', '--size'], 'empty': ['-e', '--empty']})
# This overrides the default value for the `symbol` parameter:
@add_options_from(display_data, custom={'symbol': {'default': '#'}})
Docstring styles
click-inspect
supports inspecting reST-style docstrings, as well as Google- and Numpy-style docstrings via sphinx.ext.napoleon
.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for click_inspect-0.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dfb5d4cd0c08ac5ef3488e3c5447a6139a63db1d913910b2399fcee5ae8de4e1 |
|
MD5 | 12b6ba1d28b7ae64e6f88b8a3848403e |
|
BLAKE2b-256 | 794e2eaa28dfa6d87e0b1c35041b7505f34ec67f04f4af68b2b710301e069be4 |