首页 > 解决方案 > make Python3 script as a CLI

问题描述

I have a single python3 script which has the following structure. I wish to make this code available as a CLI utility (and not a python3 module) via pip. The reason it not being a python3 module is because the logic is very straight forward and I see no benefit refactoring the code into smaller python files to make it a module.

Code deflection.py

def func1():
 """some useful function here"""


def main(args):
""" My MAIN Logic here!!"""


def parse_args():
"""Parse Arguments if Passed else use configuration file"""

    parser = argparse.ArgumentParser(description='what the CLI should do.')


    parser.add_argument('--ip', type=str, required=False, help='descp@1')
    # Add more arguments (trimmed for code brevity)

    return parser.parse_args()


if __name__ == '__main__':
    args = parse_args()
    CONF = dict() # create a dict for reading a `conf.json` file from `/etc/` folder

    with open(CONF_PATH) as cFile:
        _conf = json.load(cFile)
        CONF = _conf['Key_Of_Interest']

   # Check Argument conditions
    if condition_1:
        print('Starting Script in Default Mode. Reading Conf File conf.json')
        try:
            main(...) # pass all the default args here

        except KeyboardInterrupt as e:
            # if CTRL C pressed safe exit
            sys.exit(0)

    elif condition_2:
        # if one particular argument wasn't mentioned, stop script
        sys.exit(1)
    else:
        print('Starting Script with Custom Arguments.')
        try:
            main(..) # custom args to main function
            
        except KeyboardInterrupt as e:
            # safe exit if CTRL C pressed
            sys.exit(0)

I am following the Python-Packaging Tutorial which does mention CLI for python modules.

Current Directory Structure

.
|-- bin
|   `-- deflection
|-- deflection
|   |-- deflection.py
|   `-- __init__.py
|-- MANIFEST.in
|-- README.rst
`-- setup.py

setup.py

from setuptools import setup

def readme():
    with open('README.rst') as f:
        return f.read()

setup(name='deflection',
      version='0.1',
      description='Extract Micro-Epsilon OptoNCDT values and store into InfluxDB',
      long_description=readme(),
      url='https://mypersonalgitlabLink.com/awesomeCLIProject',
      author='Monty Python',
      author_email='Monty@python.org',
      license='GPLv3',
      packages=['deflection'],
      scripts=['bin/deflection']
      install_requires=[
            'influxdb-python'
      ],
      zip_safe=False)

At this point I am not sure what should be written in bin/deflection file?

#!/usr/bin/env python3
from .deflection import main # NOT SURE Here! because main() requires arguments

I can decide simply upon chmod +x deflection.py but I have a dependency of influxdb-python which I wish to ship via pip i.e. when one does

`pip3 install deflection`

the users can directly do $ deflection --arg1='test' and use the script.

How do I achieve this without using click or any other helper modules and stick to core pip?

标签: pythonpython-3.xpipcommand-line-interface

解决方案


At this point I am not sure what should be written in bin/deflection file?

Nothing. You shouldn't ship the executable inside the bin folder of your source tree. The executable will be created upon installation.

I suggest you to use flit and pyproject.toml. It will greatly simplifies your project. First add a pyproject.toml file (instead of setup.py):

[build-system]
requires = ['flit']
build-backend = 'flit.buildapi'

[tool.flit.metadata]
module = 'deflection'
requires-python = '>=3'
description-file = 'README.rst'
requires = ['influxdb-python']

[tool.flit.scripts]
deflection = 'deflection.deflection:main'

Then upload your code to PyPI with flit publish.


推荐阅读