0

Consider following MCVE:

import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("-t", "--test")
parser.add_argument("-o", "--other")
assert sys.argv == ['mcve.py', '-o', '-t 123']
parsed = parser.parse_args()
assert parsed.other == "-t 123"

And its' invocation:

lrogalsk-mac01:src lrogalsk$ python mcve.py -o "-t 123"
usage: mcve.py [-h] [-t TEST] [-o OTHER]
mcve.py: error: argument -o/--other: expected one argument

As you can see, values in shell are interpreted correctly and passed to Python process as separate command line arguments. Nevertheless, argparse parsing mechanism still rejects this value (likely because it begins with match of another parameter, -t).

Changing invocation to space-prepended value (see below) and adjusting assertions in MCVE script makes it work, but this for me is merely workaround and not an actual solution.

lrogalsk-mac01:src lrogalsk$ python mcve.py -o " -t 123"

Is there any known way of fixing this behaviour in argparse?

Set-up details:

lrogalsk-mac01:src lrogalsk$ python --version
Python 2.7.10
Łukasz Rogalski
  • 22,092
  • 8
  • 59
  • 93
  • Assertion is correct. Argument is wrapped in quotation marks in shell invocation for a reason. – Łukasz Rogalski Jan 04 '18 at 07:56
  • what if you do `mcve.py -o "'-t 123'"`? – Thomas Kühn Jan 04 '18 at 07:58
  • `sys.argv` is `['mcve.py', '-o', "'-t 123'"]`, parsing succeeded, but only because value string does not start with `-t`, as now it starts with `'-t`. I don't see how wrapping value in quotation marks differs from prepending value with space in this context. – Łukasz Rogalski Jan 04 '18 at 08:12
  • More on this at https://stackoverflow.com/questions/16174992/cant-get-argparse-to-read-quoted-string-with-dashes-in-it. I list several work arounds. Or stick with `optparse`. – hpaulj Jan 04 '18 at 08:38

1 Answers1

1

In the 'argparse' documentation, this case is mentioned (16.4.4.3):

The parse_args() method attempts to give errors whenever the user has clearly made a mistake, but some situations are inherently ambiguous. For example, the command-line argument -1 could either be an attempt to specify an option or an attempt to provide a positional argument. The parse_args() method is cautious here: positional arguments may only begin with - if they look like negative numbers and there are no options in the parser that look like negative numbers

For positional arguments, you can prepend a '--', but in your case that doesn't seem to work. Instead, the use of subparsers is supported, so

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help = 'the subparsers')
parser_a = subparsers.add_parser('o', help = 'the o option')
parser_a.add_argument('-t', '--test')
parsed = parser.parse_args()
print(parsed.test)

works. Calling the script with

python mcve.py o -t 123

gives the output

123
Thomas Kühn
  • 9,412
  • 3
  • 47
  • 63