pythoncommand-lineargparse

How to incorporate argparse into a python function with two arguments


I am trying to figure out how to incorporate argparse into a python function I have created that accepts two arguments, so that it is executable in the command line.

For example in this function below:

def function(arg1, arg2):
        print(arg1 * arg2)

How could I implement argparse to be able to execute the following in the command line:

% python3 pythonscript.py function arg1 arg2

I have tried to use argparse, but I have only found tutorials for how to use it on python scripts and not functions.


Solution

  • To run function you have to load script - and this script has to get arguments and use it to execute expected function with expected values.

    To get arguments you can use sys.argv, argparse and it will need to recognize function's name and run it. Other modules - like click, google/python-fire, invoke - can make it simpler because they can recognize function automatically and execute it.

    For the beginning I show example with sys.argv

    import sys
    
    """
    % python3 script.py mul 1 2
    % python3 script.py add 1 2
    """
    
    def mul(arg1, arg2):
        return arg1 * arg2 
    
    def add(arg1, arg2):
        return arg1 + arg2 
    
    # --- main ---
    
    if len(sys.argv) < 4:
        print("Usage: python3 script.py function arg1 arg2")
        exit(1)
        
    name = sys.argv[1]
    val1 = int(sys.argv[2])
    val2 = int(sys.argv[3])
    
    if name == "mul":
        result = mul(val1, val2)
        print(result)
    elif name == "add":
        result = add(val1, val2)
        print(result)
    else:
        print("wrong function's name")
    

    And the same with dictionary (instead of many if/else) to execute function:

    import sys
    
    """
    % python3 script.py mul 1 2
    % python3 script.py add 1 2
    """
    
    def mul(arg1, arg2):
        return arg1 * arg2 
    
    def add(arg1, arg2):
        return arg1 + arg2 
    
    # --- main ---
    
    if len(sys.argv) < 4:
        print("Usage: python3 script.py function arg1 arg2")
        exit(1)
        
    name = sys.argv[1]
    val1 = int(sys.argv[2])
    val2 = int(sys.argv[3])
    
    functions = {
        "mul": mul,
        "add": add,
    }
    
    if name in functions:
        result = functions[name](val1, val2)
        print(result)
    else:
        print("wrong function's name")
    

    And simular for argparse.

    argparse may use options which may allow to send more complex parameters - like skip parameters to use default values, etc. - so it is more useful than sys.argv

    I added option --debug to display extra information

    import argparse
    
    """
    % python3 script.py --help
    % python3 script.py mul 1 2
    % python3 script.py add 1 2
    % python3 script.py -D mul 1 2
    % python3 script.py -D add 1 2
    % python3 script.py --debug mul 1 2
    % python3 script.py --debug add 1 2
    """
    
    def mul(arg1, arg2):
        return arg1 * arg2 
    
    def add(arg1, arg2):
        return arg1 + arg2 
    
    # --- main ---
    
    import argparse
    
    parser = argparse.ArgumentParser()
    
    parser.add_argument('name')
    parser.add_argument('val1')
    parser.add_argument('val2')
    
    parser.add_argument('-D', '--debug', action='store_true', help='[default: %(default)s]')
    
    args = parser.parse_args()
    
    if args.debug:
       print("args:", args)
    
    name = args.name
    val1 = int(args.val1)
    val2 = int(args.val1)
    
    functions = {
        "mul": mul,
        "add": add,
    }
    
    if name in functions:
        if args.debug:
            print("executing:", functions[name], "with", val1, val2)
        result = functions[name](val1, val2)
        print(result)
    else:
        print("wrong function's name")
    

    With click it can be simpler but it needs to add decorators.

    #!/usr/bin/env python3
    
    import click
    
    """
    % python3 script.py mul 1 2
    % python3 script.py add 1 2
    """
    
    @click.group()
    def cli():
        pass
        
    @click.command()
    @click.argument('arg1', type=click.INT)
    @click.argument('arg2', type=click.INT)
    def mul(arg1, arg2):
        print(arg1 * arg2)
    
    @click.command()
    @click.argument('arg1', type=click.INT)
    @click.argument('arg2', type=click.INT)
    def add(arg1, arg2):
        print(arg1 + arg2)
    
    cli.add_command(mul)
    cli.add_command(add)
    
    # --- main ---
    
    cli()
    

    The same with fire can be even simpler

    import fire
    
    """
    % python3 script.py mul 1 2
    % python3 script.py add 1 2
    """
    
    class Calculator:
    
        def mul(self, arg1, arg2):
            return arg1 * arg2
    
        def add(self, arg1, arg2):
            return arg1 + arg2
    
    # --- main ---
    
    fire.Fire(Calculator)