Skip to main content

Making a CLI Application by wrapping

Project description

wrapp: Making a CLI Application by wrapping

INSTALL

pip install wrapp

USAGE

TL;DR

  1. Create your Python script under a few rules. To do so, start with wrapp.new.

    wrapp.new > YOURS.py
    
  2. Edit YOURS.py as you like.

  3. 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


logger = getLogger(__name__)


def add_arguments(parser):
    ...


def main(args):
    ...

Starting with this template, add program options in add_arguments(parser).
The type of parser is assumed as argparse.ArgumentParser class.

And main(args) function is the entry point. When you run wrapp YOURS.py, the program arguments are parsed as defined in add_arguments(parser) and stored in the variable named args. Then all program arguments and options are output via logger. Finally, the main(args) is called.

As shown above, wrapp assumes your Python file contains add_arguments(parser) and main(args). logger is optional. Also logger can be replaced its name as _LOG or LOG. For logger, it's OK to use any other 3rd-party logging modules like loguru.

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 ....

FEATURES

  • No dependencies. wrapp only depends on Python standard libraries.

  • One file. If you don't link 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 wrapp YOURS.

LICENSE

MIT License.

BACKGROUNDS

As I wrote tons of Python CLI applications, I noticed that,

  • argparse is the best practice to add my program command options.
  • logging is 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wrapp-0.2.0.tar.gz (4.8 kB view details)

Uploaded Source

Built Distribution

wrapp-0.2.0-py3-none-any.whl (4.7 kB view details)

Uploaded Python 3

File details

Details for the file wrapp-0.2.0.tar.gz.

File metadata

  • Download URL: wrapp-0.2.0.tar.gz
  • Upload date:
  • Size: 4.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.8.10 Linux/5.4.0-104-generic

File hashes

Hashes for wrapp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1d299be1d654ff6a2038ccb73cb4516ab1a05d3064088e3083c05f001e846f54
MD5 a15eed945f16b2c1483396a4f64c98e3
BLAKE2b-256 0bf72849f8bdcb7042a63e1d9ad6f9300f1446529c66cdec9c3c385362f9d803

See more details on using hashes here.

File details

Details for the file wrapp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: wrapp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 4.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.6 CPython/3.8.10 Linux/5.4.0-104-generic

File hashes

Hashes for wrapp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1936475c17ae21363249456d3e16084ee3bea5af58cea67c7f06bfefc88c7fe5
MD5 d95adabcb7e372cac1ffc7c8e34aeb73
BLAKE2b-256 5775627e45acd55d33ef45c56e4b207192031f1391d71e905abfe3d2135748dd

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page