MrByte
MrByte

Reputation: 107

argparse function arguments

I am trying to use argparse to create my script with parameters but I am not being able to.

The name of my script is pipeline and it has some options arguments like -b, -c, -i and -r.

If you call the script ./pipeline -b should give an error asking for a git repository path but I am not being able to do this.

from git import Repo
import os
import sys
import subprocess
import argparse

class Ci:

    def build(self,args):
        cloned_repo = Repo.clone_from(args)
        print("clonning repository " + args)
        cloned_repo

        dir = git.split('/')(-1)

        if os.path.isdir(dir):
            print("repository cloned successfully")
        else:
            print("error to clone repository")


if __name__ == '__main__':

    parser = argparse.ArgumentParser()

    parser.add_argument('-b','-build',action='store_true', help='execute mvn clean install')
    parser.add_argument('-c','-compress',action='store_true',help='zip a directory recursively')
    parser.add_argument('-i','-integration',action='store_true',help='execute mvn verify')
    parser.add_argument('-r','-release',action='store_true',help='execute build,integration and compress respectively')
    args = parser.parse_args()

    if args.b:
        a = Ci()
        a.build()

    if len(sys.argv) < 2:
        parser.print_help()
        sys.exit(1)

I can't make this sub-parameter work and I can't find a way to pass this parameter to my build function.

e.g:

./pipeline -b

Output: error missins git path
./pipeline -b https://git/repo
Output: clonning repo

and the string "https://git/repo" has to be passed as the argument to my build function:

How can I make it work?

Upvotes: 2

Views: 2172

Answers (3)

Peruz
Peruz

Reputation: 433

I agree with @hpaulj (why isn't an accepted answer?). I guess you found your problem, i.e., store_true does not take argument, then follow hpaulj indications.

In addition, I opened the question because of its title, I was expecting something different such as the following. I wanted to find a way to pass the argparse arguments to a function and possibly modify them with the function arguments. Here is the solution I wrote in case others come looking for this. It may need to be adjusted to account for positional arguments, I also highlight the possible use of vars(args) to get a dictionary from the argparse arguments to compare dict-to-dict with the args_dict:

def get_options(args_dict: dict):
    """ get options from command-line,
        update with function args_dict if needed """
    args = get_cmd()  # this is the function taking cmd-line arguments 
    for key, val in args_dict.items():
        if not hasattr(args, key):
            raise AttributeError('unrecognized option: ', key)
        else:
            setattr(args, key, val)
    return(args)

Upvotes: 1

hpaulj
hpaulj

Reputation: 231738

Reducing your code to:

import argparse

class Ci:

    def build(self,args):
        print("clonning repository " + args)

if __name__ == '__main__':

    parser = argparse.ArgumentParser()

    parser.add_argument('-b','-build',action='store_true', help='execute mvn clean install')
    parser.add_argument('-c','-compress',action='store_true',help='zip a directory recursively')
    parser.add_argument('-i','-integration',action='store_true',help='execute mvn verify')
    parser.add_argument('-r','-release',action='store_true',help='execute build,integration and compress respectively')
    args = parser.parse_args()
    print(args)

    if args.b:
        a = Ci()
        a.build()

I get:

1313:~/mypy$ python3 stack49408644.py -b
Namespace(b=True, c=False, i=False, r=False)
Traceback (most recent call last):
  File "stack49408644.py", line 22, in <module>
    a.build()
TypeError: build() missing 1 required positional argument: 'args'

The parser runs fine, seeing args.b to True. But the call to build is wrong. It does not match the method's definition.

Providing a 'directory' doesn't help either, because -b is True/False

1313:~/mypy$ python3 stack49408644.py -b foo
usage: stack49408644.py [-h] [-b] [-c] [-i] [-r]
stack49408644.py: error: unrecognized arguments: foo

You need to either change -b to take an value, or add another argument that takes a value.

@AntiMatterDynamite showed how to change -b. Instead let's add:

parser.add_argument('adir', help='a directory for build')

and change the build call

    a.build(args.adir)

Now the value is passed on to the method:

1322:~/mypy$ python3 stack49408644.py -b
usage: stack49408644.py [-h] [-b] [-c] [-i] [-r] adir
stack49408644.py: error: the following arguments are required: adir
1322:~/mypy$ python3 stack49408644.py -b foo
Namespace(adir='foo', b=True, c=False, i=False, r=False)
clonning repository foo

Instead redefining -b:

parser.add_argument('-b','-build', help='execute mvn clean install')

if args.b is not None:
    a = Ci()
    a.build(args.b)

test runs:

1322:~/mypy$ python3 stack49408644.py -b
usage: stack49408644.py [-h] [-b B] [-c] [-i] [-r]
stack49408644.py: error: argument -b/-build: expected one argument
1324:~/mypy$ python3 stack49408644.py -b foo
Namespace(b='foo', c=False, i=False, r=False)
clonning repository foo

So your parser needs to accept a value. And you need to pass that value on to your code. You seem to have read enough of the argparse docs to get things like print_help and store_true, but missed the simpler use of store (default) or positional. Were you trying to do something more sophisticated?

Upvotes: 1

AntiMatterDynamite
AntiMatterDynamite

Reputation: 1512

first a note about convention: usually the longer option name is preceded by two hyphens like this '--build'

second, 'store_true' is the action you perform with '-b', which means argparse doesnt expect an argument after it, it just sets the args.build variable to True (and if the argument wasn't there it would set it to False)

try removing the action='store_true' and then it will default to storing the next value it finds in the argument list into args.build

Upvotes: 3

Related Questions