Making a CLI Application by wrapping
Project description
wrapp: Making a CLI Application by wrapping
wrapp helps you to make a CLI application without boilerplate of logging & argparse.
INSTALL
pip install wrapp
USAGE
TL;DR
-
Create your Python script under a few rules. To do so, start with
wrapp.new.wrapp.new > YOURS.py -
Edit
YOURS.pyas you like. -
Then you can run your Python script as an CLI app.
wrapp YOURS.py
That's it. Let's enjoy !
Create your Python script under a few rules
By using wrapp.new,
wrapp.new > YOURS.py
you can get a template Python file named YOURS.py.
wrapp.new outputs template code at stdout.
$ cat YOURS.py
#!/usr/bin/env python3
from logging import getLogger
LOG = getLogger(f'__main__.{__name__}')
def add_arguments(parser):
group = parser.add_argument_group(__name__)
...
def main(args):
...
# code below is an option.
# if you want to run it as an normal Python script
# (`python THIS_SCRIPT.py`), uncomment it.
# if __name__ == '__main__':
# import wrapp
# wrapp.main(add_arguments, main)
This template has 1 global variable and 2 functions; LOG,
add_arguments(), main().
LOG is the logger in this file.
add_arguments() is the function to set program arguments.
add_arguments() takes 1 argument; parser which is assumed as
an instance of argparse.ArgumentParser.
However, I don't use a type hint now in the template
because of redusing import statements.
add_arguments() is also available recusive calling.
See also tests/template.py and tests/sub/template2.py.
main() function is the entry point.
When you run wrapp YOURS.py,
-
The program arguments are parsed as defined in
add_arguments()and stored in the variable namedargs. -
All program arguments and options are output to console.
-
Finally, the
main(args)is called.
As shown above, wrapp assumes your Python file contains add_arguments(parser) and main(args).
Run your Python script as an CLI app
Assume your Python script is YOURS.py.
wrapp YOURS.py --your-options ...
That is, just replace python to wrapp.
Then you can keep your script simple:
if __name__ == '__main__':is not needed.- Also you don't need any noisy modules such as
argparse,from argparse import ...,from logging import ....
"I want to run it as python my_script.py"
If you want to run your code as an usual Python way, just uncomment last 3 lines of the template.
Then you can run like
python my_script.py --some-option ...
Debugging
When you want to debug your script, run the code like this.
python3 -m pdb -m wrapp YOURS.py --your-options ...
Then the debugging mode (pdb) will be started.
FEATURES
-
No dependencies. wrapp only depends on Python standard libraries.
-
One file. If you don't need to install other packages at all, just copy
src/wrapp/wrapp.py.$ cp PATH/TO/wrapp_repo/src/wrapp/wrapp.py ./wrapp $ chmod u+x wrapp $ ./wrapp.new > YOURS.py $ ./wrapp YOURS.py -
It's like python-fire. But for wrapp, you don't need to import any other module in your Python code.
-
It's trivial but you also run your script without the extension;
wrapp YOURS.
LICENSE
MIT License.
BACKGROUNDS
As I wrote tons of Python CLI applications, I noticed that,
argparseis the best practice to add my program command options.loggingis not bad if I modify something (format, ...).- But I noticed that there are many similar lines in my applications. And they make my code more dirty.
Here is my application code pattern. Please note that there is nothing infomative.
#!/usr/bin/env python3
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
from logging import getLogger
from pathlib import Path
import logging.config
LOG = getLogger(__name__)
def add_arguments(parser):
parser.add_argument(
'in_file', type=Path,
help='An input file.')
parser.add_argument(
'--out-dir', '-d', type=Path, default=None,
help='A directory.')
def _main(args):
LOG.debug('debug')
LOG.info('info')
LOG.warning('warning')
LOG.error('error')
LOG.critical('critical')
...
def _parse_args():
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-i', '--input-files', nargs='*', help='input files.')
args = parser.parse_args()
logging.config.fileConfig('logging.conf')
for k,v in vars(args).items():
LOG.info('{}= {}'.format(k, v))
return args
def _print_args(args):
for k, v in vars(args).items():
LOG.info(f'{k}= {v}')
if __name__ == '__main__':
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
add_arguments(parser)
args = parser.parse_args()
logging.config.fileConfig('logging.conf')
_print_args(args)
_main(args)
So I decided to separate it to 2 files; one is the contents only and the other is a wrappter to make any Python files an CLI app.
Finally, I can make the above code much more simple,
#!/usr/bin/env python3
from logging import getLogger
from pathlib import Path
LOG = getLogger(__name__)
def add_arguments(parser):
parser.add_argument(
'in_file', type=Path,
help='An input file.')
parser.add_argument(
'--out-dir', '-d', type=Path, default=None,
help='A directory.')
def main(args):
LOG.debug('debug')
LOG.info('info')
LOG.warning('warning')
LOG.error('error')
LOG.critical('critical')
...
It's similar to python-fire.
But when I used the fire, I have to insert from fire import Fire and Fire(your_func). I'd like to remove even such a few code.
Then I'm completly free from noisy modules / code !
Project details
Release history Release notifications | RSS feed
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
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wrapp-0.7.0.tar.gz.
File metadata
- Download URL: wrapp-0.7.0.tar.gz
- Upload date:
- Size: 4.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.6.1 CPython/3.11.5 Linux/6.1.55-1-MANJARO
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fba41562161cf60e0b6c3813444d72bfe54cec6c8f914092ddb615194f45cc2
|
|
| MD5 |
733c9c84c80da94c09c25df2a94e4f52
|
|
| BLAKE2b-256 |
fc849adf05351a94667e8dc9959f9716632a64e29553c780a5da49dcc32d8b69
|
File details
Details for the file wrapp-0.7.0-py3-none-any.whl.
File metadata
- Download URL: wrapp-0.7.0-py3-none-any.whl
- Upload date:
- Size: 5.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.6.1 CPython/3.11.5 Linux/6.1.55-1-MANJARO
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a89ba44488ece89b79610e01c9d71b68282beb1fad1670ff68967b637201799c
|
|
| MD5 |
8370b1871ecec0c56ff6f860abec7ebf
|
|
| BLAKE2b-256 |
dda302e050e208f11485d49df6bbcee26b234c23514695922cae21ac352643bd
|