Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/relastle/glacier
:snowflake: Building Python CLI using docstrings and typehints :snake:
https://github.com/relastle/glacier
asyncio cli command-line-tool docstring library productivity python python-cli python3
Last synced: 21 days ago
JSON representation
:snowflake: Building Python CLI using docstrings and typehints :snake:
- Host: GitHub
- URL: https://github.com/relastle/glacier
- Owner: relastle
- License: mit
- Created: 2020-08-23T15:57:42.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2023-06-16T00:04:56.000Z (over 1 year ago)
- Last Synced: 2024-12-27T00:08:20.443Z (28 days ago)
- Topics: asyncio, cli, command-line-tool, docstring, library, productivity, python, python-cli, python3
- Language: Python
- Homepage: https://github.com/relastle/glacier
- Size: 72.3 KB
- Stars: 95
- Watchers: 3
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
![image](https://user-images.githubusercontent.com/6816040/91929753-0fe7bf00-ed1a-11ea-8c95-793e2a20fd07.png)
# glacier
glacier is a python CLI building library for minimalists.
* [glacier](#glacier)
* [Installation](#installation)
* [Quick start](#quick-start)
* [Basic Usage](#basic-usage)
* [CLI without subcommand](#cli-without-subcommand)
* [CLI with subcommands](#cli-with-subcommands)
* [Pass a list of functions](#pass-a-list-of-functions)
* [Pass a dictionary of functions](#pass-a-dictionary-of-functions)
* [Async entrypoint support](#async-entrypoint-support)
* [Positional argument](#positional-argument)
* [Options](#options)
* [Default value for optional argument](#default-value-for-optional-argument)
* [Help with docstring](#help-with-docstring)
* [Google Style](#google-style)
* [Numpy Style](#numpy-style)
* [reStructuredText Style](#restructuredtext-style)
* [Supported types](#supported-types)
* [Note](#note)
* [Philosophy](#apple-philosophy)
* [Warnings](#construction-warnings)
* [Related works](#related-works)
* [LICENSE](#license)## Installation
```python
pip install glacier
```## Quick start
You only have to call `glacier` against the entrypoint function.
```python
from glacier import glacierdef main(name: str, verbose: bool = False) -> None:
passif __name__ == '__main__':
glacier(main)
```Then, you can see help 🍰.
![quick start help](https://user-images.githubusercontent.com/6816040/92337363-fd87cf80-f0e3-11ea-8902-d0488fbd8547.png)
## Basic Usage
### CLI without subcommand
If you just call `glacier` to a function, it will invoke it as stand-alone CLI
(like the example in [Quick start](https://github.com/relastle/glacier#quick-start)).### CLI with subcommands
You can easily construct CLI with subcommands in the following two ways.
#### Pass a list of functions
```python
from glacier import glacierdef run(name: str, verbose: bool = False) -> None:
""" Run """
passdef build(name: str, verbose: bool = False) -> None:
""" Build """
passdef test(name: str, verbose: bool = False) -> None:
""" Test """
returnif __name__ == '__main__':
glacier([run, build, test])
```If you passes a lift of function, glacier constructs the CLI with subcommands whose names are the same as the declared function names.
In this example, the subcommans will be `run`, `build`, and `test`.![sub commands help](https://user-images.githubusercontent.com/6816040/92397064-108cb500-f161-11ea-9cb2-0f0a1c4da2f5.png)
#### Pass a dictionary of functions
You can easily give the different name as the subcommand name from any declared name of the function.
Just give a dictionary (key will be a subcommand name).```python
from glacier import glacierdef f1(name: str, verbose: bool = False) -> None:
passdef f2(name: str, verbose: bool = False) -> None:
passdef f3(name: str, verbose: bool = False) -> None:
passif __name__ == '__main__':
glacier({
'run': f1,
'build': f2,
'test': f3,
})
```This works exactly the same as the previous example.
This interface makes it very easy to build a simple CLI tool from an existing project.
### Async entrypoint support
You sometimes want your async function to be a CLI entrypoint.
Only you have to do is just passing the async function as if it were `sync` function.The example below combine two async functions and a sync function into CLI
with nested subcommand structure.```python
from glacier import glacierasync def main() -> None:
returndef sub_1() -> None:
returnasync def sub_2() -> None:
returnif __name__ == '__main__':
glacier({
'main': main,
'sub': [
sub_1,
sub_2,
],
})
```### Positional argument
If the name of function argument is underscore-prefiexed, it is understood as positional argument.
```python
from glacier import glacierdef all_positional(_a: str, _b: str, _c: str) -> None:
print(_a)
print(_b)
print(_c)if __name__ == '__main__':
glacier(all_positional)
```The above example is invoked as follows
```bash
```### Options
All other (non-underscore-prefixed) arguments are understood as options.
```python
from glacier import glacierdef all_options(a: str, b: str, c: str) -> None:
print(a)
print(b)
print(c)if __name__ == '__main__':
glacier(all_options)
```The above example is invoked as follows
```bash
--a --b --c
```### Default value for optional argument
If you set the default value for function argument, it also defines the default value for CLI option.
```python
from glacier import glacierdef default(verbose: bool = False) -> None:
print(verbose)if __name__ == '__main__':
glacier(default)
```The above example is invoked as follows
```bash
# Just call without flag (`False` will be printed)
```or
```bash
--verbose # Call with flag (`True` will be printed)
```### Help with docstring
Help message for options or command itself can be provided with python docstring.
Following style of doctrings are supported
- [Google Style](https://github.com/relastle/glacier#google-style)
- [Numpy Style](https://github.com/relastle/glacier#numpy-style)
- [reStructuredText Style](https://github.com/relastle/glacier#restructuredtext-style)The functions with docstring below will produce the exact the same help message with fed into `glacier`.
(You don't need to specify which docstring style is used 😄)#### Google Style
```python
def main_google(
_path: str,
name: str,
verbose: bool = False,
) -> None:
"""
This is my simple entry point of CLI.Args:
_path: Positional argument representing the target file path.
name: Name of this operation.
verbose: Verbose output will be shown if set.
"""
print(_path)
print(name)
print(verbose)
return
```#### Numpy Style
```python
def main_numpy(
_path: str,
name: str,
verbose: bool = False,
) -> None:
"""
This is my simple entry point of CLI.Parameters
----------
_path: str
Positional argument representing the target file path.
name: str
Name of this operation.
verbose: bool
Verbose output will be shown if set.
"""
print(_path)
print(name)
print(verbose)
return
```#### reStructuredText Style
```python
def main_restructured_text(
_path: str,
name: str,
verbose: bool = False,
) -> None:
"""
This is my simple entry point of CLI.:param _path: Positional argument representing the target file path.
:param name: Name of this operation.
:param verbose: Verbose output will be shown if set.
"""
print(_path)
print(name)
print(verbose)
return
```### Supported types
- [x] int
- [x] str
- [x] bool
- [x] Enum
- [ ] List[int]
- [ ] List[str]## Note
### :apple: Philosophy
- This library is made for building CLI quickly especially for personal use, so the features provided by it is not rich.
- If you want to build really user-friend CLI or that in production, I suggest that you use [click](https://click.palletsprojects.com/en/7.x/) (actually glacier uses it internally), or other full-stack CLI builing libraries.
### :construction: Warnings
- Please note that any destructive change (backward incompatible) can be done without any announcement.
- This plugin is in a very early stage of development. Feel free to report problems or submit feature requests in [Issues](https://github.com/relastle/glacier/issues).## Related works
- [google/python-fire: Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.](https://github.com/google/python-fire)
- [tiangolo/typer: Typer, build great CLIs. Easy to code. Based on Python type hints.](https://github.com/tiangolo/typer)## [LICENSE](./LICENSE)
MIT