1

I have the following arguments which are to be parsed using argparse

  • input_dir (string: Mandatory)
  • output_dir (string: Mandatory)
  • file_path (string: Mandatory)
  • supported_file_extensions (comma separated string - Optional)
  • ignore_tests (boolean - Optional)

If either comma separated string and a string are provided for supported_file_extensions and ignore_tests respectively, then I want the value to be set to the argument variable. My set up is as follows

import sys

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        'input_dir', type=str,
        help='Fully qualified directory for the input directory')
    parser.add_argument(
        'file_path', type=str,
        help='Fully  qualified path name for file')
    parser.add_argument(
       'output', type=str, help='Fully qualified output directory path')
    parser.add_argument(
        '-supported_file_extensions',nargs='?', type=str, default=None,
        help='optional comma separated file extensions'
    ) # Should default to False
    parser.add_argument(
        '-ignore_tests', nargs='?', type=bool, default=True
    ) # Should default to True if the argument is passed
    (arguments, _) = parser.parse_known_args(sys.argv[1:])
    print(arguments)

When I pass the following command

 python cloc.py -input_dir /myproject -file_path /myproject/.github/CODEOWNERS -output output.json --supported_file_extensions java,kt --ignore_tests False

I want the value of the arguments.--supported_file_extensions to be equal to java,kt and ignore_tests to equal to False but I get the following values

Namespace(file_path='/myproject/.github/CODEOWNERS', ignore_tests=True, input_dir='/myproject', output='output.json', supported_file_extensions=None)

If I don't pass --ignored_tests in my command line argument, then I want the file to default to False. Similarly, when I pass --ignored_tests, then I want the argument to be set to True.

If I pass --supported_file_extensions java,kt, then I want the argument to be set to java,kt as a string, and not a list.

I have tried going through but I have not had any success.

  1. Python argparse: default value or specified value
  2. python argparse default value for optional argument
  3. Creating command lines with python (argparse)

UPDATE I updated the last two arguments as follows:

parser.add_argument(
        '-supported_file_extensions', type=str,
        help='optional comma separated file extensions'
    )
    parser.add_argument(
        '-ignore_tests', action='store_true',
        help='optional flag to ignore '
    )
    (arguments, _) = parser.parse_known_args(sys.argv[1:])
    print(arguments)

When I run the command as

  python cloc.py -input_dir /myproject -file_path /myproject/.github/CODEOWNERS -output output.json --supported_file_extensions java,kt

The output is as follows

 Namespace(file_path='/myproject/.github/CODEOWNERS', ignore_tests=False, input_dir='/myproject', output='output.json', supported_file_extensions=None)

While the value of ignore_tests is correct, (defaulted to false), the value of supported_file_extensions is None, which is not correct since I had passed java,kt as command line arguments.

When I pass

 python cloc.py -input_dir /myproject -file_path /myproject/.github/CODEOWNERS -output output.json --supported_file_extensions java,kt --ignore_tests 

I get the following output

Namespace(file_path='/myproject/.github/CODEOWNERS', ignore_tests=False, input_dir='/myproject', output='output.json', supported_file_extensions=None)
manoflogan
  • 31
  • 8
  • 2
    Is there some reason the user must pass `True` or `False`? It's a *much* better idea to have them pass the switch, or not, with no value. The `action='store_true'` action will make that "just work", with no need to define `type`, `default`, or `nargs`. You definitely can't use the `bool` constructor, because `bool("True")` and `bool("False")` are both true (`bool` on a string is only false if the string is empty). – ShadowRanger Mar 30 '21 at 19:46
  • '--ignore-test' should be `action='store_true'`. (or 'store_false') Don't use `type=bool`. And make up your mind, are the st 3 args postional of flagged, '--input_dir' – hpaulj Mar 30 '21 at 19:47
  • @ShadowRanger There is no requirement. I want a way to initialise either True or False to `ignore_tests` depending on the command line argument. – manoflogan Mar 30 '21 at 19:56
  • when I run code on Linux without arguments then it shows help message with `-supported_file_extensions` which has single `-` but you run it with double `--`. If I run it with double `--supported_file_extensions` then I get `None` but if I use single `-supported_file_extensions` then it gives correct value. You simply use `-` in wrong way. You should use single `-output` and double `--supported_file_extensions` – furas Mar 30 '21 at 20:24
  • If you define `add_argument('output')` then it expects value without `-output`. If you define with single `-` like `add_argument('-supported_file_extensions')` then you should run it also with single `-` like `-supported_file_extensions value`. If you want to use with double `--` like `--supported_file_extensions value` then you should define with double `--` like `add_argument('--supported_file_extensions')` – furas Mar 30 '21 at 20:31
  • But I want to validate that `file_path`, `input_dir` and `output` are sent. – manoflogan Mar 30 '21 at 20:50

2 Answers2

0

Your arguments are incorrect. You are registering the arguments to the parser as -ignore_tests but specifying it on the command line as --ignore_tests — note the number of preceding dashes. You also do not need to specify -input_dir for the positional arguments, they do nothing.

Normally, both of the above issues would cause your script to crash. The only reason it still runs is because you are using parser.parse_known_args which ignores all arguments it doesn't understand — like --ignore_tests and -input_dir.

The command you should be running is:

python cloc.py /myproject /myproject/.github/CODEOWNERS output.json -supported_file_extensions java,kt -ignore_tests False

Also, as many in the comments have mentioned, do not use type=bool when registering arguments. Instead, use

parser.add_argument('-ignore_tests', action='store_true')

This will set ignore_tests to True when -ignore_tests is present and False otherwise — no need to explicitly specify True or False on the command line.

Ali Samji
  • 479
  • 2
  • 7
0

I think this is a better definition:

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--input_dir',
        help='Fully qualified directory for the input directory')
    parser.add_argument(
        '--file_path',
        help='Fully  qualified path name for file')
    parser.add_argument(
       '--output', help='Fully qualified output directory path')
    parser.add_argument(
        '--supported_file_extensions',
        help='optional comma separated file extensions'
    ) # only use ? if defining default and const
    parser.add_argument(
        '--ignore_tests', action='store_true'
    )
    (arguments, extras) = parser.parse_known_args()
    print(arguments)
    print(extras)

Call with:

python cloc.py --input_dir /myproject --file_path /myproject/.github/CODEOWNERS --output output.json --supported_file_extensions java,kt

Another version:

if name == 'main': parser = argparse.ArgumentParser()

parser.add_argument(
    '--supported_file_extensions',
    help='optional comma separated file extensions')
parser.add_argument(
    '--ignore_tests', action='store_true')
parser.add_argument(
    'input_dir',
    help='Fully qualified directory for the input directory')
parser.add_argument(
    'file_path',
    help='Fully  qualified path name for file')
parser.add_argument(
    'output', help='Fully qualified output directory path')
(arguments, extras) = parser.parse_known_args()
print(arguments)
print(extras)

Call with:

python cloc.py --ignore_tests /myproject /myproject/.github/CODEOWNERS output.json --supported_file_extensions java,kt

The optionals (--) can be in any order, but positionals have to be in the given order. No flags or keywords for the positionals.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • I want to be able to pass the command line keys though. – manoflogan Mar 30 '21 at 20:39
  • What do you mean by `command line keys`? Test my code and look at the `Namespace`. If you want different behavior, you might want to parse `sys.argv` directly. – hpaulj Mar 30 '21 at 20:43
  • I may be wrong but if one passes `--{key} value`, then it means that the values are optional, aren't they? I want the first three to be mandatory. – manoflogan Mar 30 '21 at 20:48
  • You could set `required=True`. Or just give them reasonable defaults, so you don't care. Or make them `positionals` (but then you can't use flag words in the input). – hpaulj Mar 30 '21 at 20:52
  • Your suggestion worked for me. If you can update your answer with `required=True`, then I can accept it. – manoflogan Mar 31 '21 at 00:18