Skip to content

Argparse incorrectly handles '--' as argument to option #58572

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mmaker mannequin opened this issue Mar 18, 2012 · 18 comments
Closed

Argparse incorrectly handles '--' as argument to option #58572

mmaker mannequin opened this issue Mar 18, 2012 · 18 comments
Labels
3.7 (EOL) end of life 3.8 (EOL) end of life 3.9 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@mmaker
Copy link
Mannequin

mmaker mannequin commented Mar 18, 2012

BPO 14364
Nosy @rhettinger, @merwok, @bitdancer, @mmaker, @vadmium, @shihai1991, @horazont
PRs
  • gh-58572: Fix behavior when '--' as argument to option in argparse #15714
  • Files
  • foo.py
  • issue14364.test.patch
  • dbldash.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2012-03-18.14:29:12.929>
    labels = ['3.7', '3.8', 'type-bug', 'library', '3.9']
    title = "Argparse incorrectly handles '--' as argument to option"
    updated_at = <Date 2021-03-23.01:07:11.301>
    user = 'https://github.com/mmaker'

    bugs.python.org fields:

    activity = <Date 2021-03-23.01:07:11.301>
    actor = 'rhettinger'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2012-03-18.14:29:12.929>
    creator = 'maker'
    dependencies = []
    files = ['24926', '29938', '45944']
    hgrepos = []
    issue_num = 14364
    keywords = ['patch', 'needs review']
    message_count = 17.0
    messages = ['156254', '156256', '156275', '156293', '187283', '187344', '187346', '187349', '262545', '262558', '283501', '351230', '353865', '354001', '354049', '354066', '389361']
    nosy_count = 9.0
    nosy_names = ['rhettinger', 'bethard', 'eric.araujo', 'r.david.murray', 'maker', 'martin.panter', 'paul.j3', 'shihai1991', 'jssfr']
    pr_nums = ['15714']
    priority = 'high'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue14364'
    versions = ['Python 2.7', 'Python 3.7', 'Python 3.8', 'Python 3.9']

    @mmaker
    Copy link
    Mannequin Author

    mmaker mannequin commented Mar 18, 2012

    http://docs.python.org/library/argparse.html#arguments-containing
    The attached file shows different behaviours when using '--' immediately after an optional argument.

    tumbolandia:cpython maker$ python foo.py --test=-- foo
    []
    tumbolandia:cpython maker$ python foo.py --test -- foo
    usage: foo.py [-h] [-t TEST] [yuri]
    foo.py: error: argument -t/--test: expected 1 argument(s)

    The same is for single-dash arguments.

    tumbolandia:cpython maker$ python foo.py -t -- foo
    usage: foo.py [-h] [-t TEST] [yuri]
    foo.py: error: argument -t/--test: expected 1 argument(s)
    tumbolandia:cpython maker$ python foo.py -t-- foo
    []

    Obviously argparse should return an error in both cases.
    The bug is probably due to Lib/argparser.py:2211

    @bitdancer
    Copy link
    Member

    It does look like there's anomalous behavior here of some sort, but I'd expect --test=-- to result in test="--", myself, rather than an error. My intuition is that '--' would need to be preceded by a space to function as the 'end of options' marker. Because of that, I've never tried the above scenario with a unix command, so maybe my intuition is wrong :)

    Just for reference (the code paths may be different), there is another open issue about -- parsing, bpo-13922.

    @bitdancer bitdancer added the stdlib Python modules in the Lib dir label Mar 18, 2012
    @bethard
    Copy link
    Mannequin

    bethard mannequin commented Mar 18, 2012

    I just tried this with grep's "-e" and "--regexp":

    $ cat > temp.txt
    a--b
    cdef
    $ grep -e-- -v temp.txt
    cdef
    $ grep --regexp=-- -v temp.txt
    cdef
    $ grep -e -- -v temp.txt
    cdef
    $ grep --regexp -- -v temp.txt
    cdef

    And with diff's "-I" and "--ignore-matching-lines":

    $ cat > temp2.txt
    cdef
    a--b
    $ diff temp.txt temp2.txt
    1d0
    < a--b
    2a2
    > a--b
    $ diff -I-- temp.txt temp2.txt 
    $ diff -I -- temp.txt temp2.txt 
    $ diff --ignore-matching-lines -- temp.txt temp2.txt 
    $ diff --ignore-matching-lines=-- temp.txt temp2.txt 
    $

    Note though that for options that don't take an argument, the "--" is just removed:

    $ grep -v -- a temp.txt 
    cdef
    $ diff -i -- temp.txt temp2.txt
    1d0
    < a--b
    2a2
    > a--b

    So I guess the unix rule is: if an option that takes an argument is followed by "--", use that as the option's argument and continue parsing as usual. If an option that takes no argument is followed by "--", then delete the "--" and treat all following flags as positional arguments.

    Argparse can't follow this directly, because then people who are using "--" to signal the end of an option with nargs="*" would start getting "--" included in that list. (And I know people have used "--" this way for a while.)

    I guess my preference is what R. David Murray suggests: "--" when part of an argument (i.e. not separated by spaces) is treated like any other characters, and only a lone "--" signals the end of options (and is ignored otherwise). That would mean that both "--test=--" and "-t--" in your example would give you ["--"], and the other errors would stay as you saw them.

    @mmaker
    Copy link
    Mannequin Author

    mmaker mannequin commented Mar 18, 2012

    +1 also for me.
    I will try to work for a patch in the next days. :)

    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Apr 18, 2013

    @michele could you provide a patch for this?

    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Apr 19, 2013

    The patch that I recently submitted for http://bugs.python.org/issue13922
    appears to solve this issue. It only removes the '--' that marked the end of options.

    With:

    parser = argparse.ArgumentParser()
    parser.add_argument('-f','--foo')
    print(parser.parse_args(['-f--']))
    print(parser.parse_args(['--foo=--']))
    print(parser.parse_args(['-f', '--']))

    I get:

    Namespace(foo='--')
    Namespace(foo='--')
    usage: foodash.py [-h] [-f FOO]
    foodash.py: error: argument -f/--foo: expected one argument

    @mmaker
    Copy link
    Mannequin Author

    mmaker mannequin commented Apr 19, 2013

    wow, I was just writing the unittests, thanks paul.
    Shall I continue? I don't see any test case on tip.

    @mmaker
    Copy link
    Mannequin Author

    mmaker mannequin commented Apr 19, 2013

    Yes, http://bugs.python.org/file29845/dbldash.patch seems to fix this.
    Attaching the unittests, and noisying on your issue.

    @vadmium
    Copy link
    Member

    vadmium commented Mar 28, 2016

    In Python 3.5, this does not seem fixed. bpo-13922 is marked as resolved and fixed, but Pauls’s patch has not actually been committed.

    >>> ap = ArgumentParser()
    >>> ap.add_argument("-t", "--test", type=str, nargs=1)
    _StoreAction(option_strings=['-t', '--test'], dest='test', nargs=1, const=None, default=None, type=<class 'str'>, choices=None, help=None, metavar=None)
    >>> ap.add_argument('yuri', nargs='?')
    _StoreAction(option_strings=[], dest='yuri', nargs='?', const=None, default=None, type=None, choices=None, help=None, metavar=None)
    >>> ap.parse_args(["--test=--", "foo"])
    Namespace(test=[], yuri='foo')
    >>> ap.parse_args(["--test", "--", "foo"])
    usage: [-h] [-t TEST] [yuri]
    : error: argument -t/--test: expected 1 argument
    argparse.ArgumentError: argument -t/--test: expected 1 argument
    
    During handling of the above exception, another exception occurred:
    
    __main__.SystemExit: 2
    >>> ap.parse_args(["-t--", "foo"])
    Namespace(test=[], yuri='foo')
    >>> ap.parse_args(["-t", "--", "foo"])
    usage: [-h] [-t TEST] [yuri]
    : error: argument -t/--test: expected 1 argument
    argparse.ArgumentError: argument -t/--test: expected 1 argument
    
    During handling of the above exception, another exception occurred:

    __main__.SystemExit: 2

    @vadmium vadmium changed the title Argparse incorrectly handles '--' Argparse incorrectly handles '--' as argument to option Mar 28, 2016
    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Mar 28, 2016

    I made a mistake of trying to add to or refine a closed patch. Maybe I need to move the dbldash.patch over here for more formal consideration.

    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Dec 17, 2016

    I've copied 'dbldash.patch' over from http://bugs.python.org/issue13922. I mistakenly added it to a closed issue.

    The patch is old, and should be revised. It is also missing tests for this '--opt=--' case, even though it solves it.

    I also reference this patch in http://bugs.python.org/issue9571, which tries to refine dbldash handling for PARSER, REMAINDER nargs.

    I'm raising the priority on this because the issue has a come up a couple of times on Stackoverflow:

    http://stackoverflow.com/questions/40685320/python-argparse-with-as-the-value

    @paulj3 paulj3 mannequin added the 3.7 (EOL) end of life label Dec 17, 2016
    @shihai1991
    Copy link
    Member

    some test cases which paul provided looks doesn't keep compatible.

    In TestDoubleDashRemoval:
    # output in my env is Namespace(cmd='cmd', foo=None, rest=['--', '--foo'])
    ('-- cmd -- -- --foo', NS(cmd='cmd', foo=None, rest=['--', '--', '--foo']))

    # output in my env is Namespace(cmd='--', foo='1', rest=['1', '2'])
    ('-f1 -- -- 1 -- 2', NS(cmd='--', foo='1', rest=['1', '--', '2']))

    # output in my env is Namespace(cmd='--foo', foo=None, rest=['--bar', '2'])
    ('-- --foo -- --bar 2', NS(cmd='--foo', foo=None, rest=['--', '--bar', '2']))

    # output in my env is Namespace(cmd='cmd', foo=None, rest=['--foo', '-f2'])
    ('cmd -- --foo -- -f2', NS(cmd='cmd', foo=None, rest=['--foo', '--', '-f2']))

    In TestDoubleDashRemoval1:
    # output in my env is Namespace(cmd='cmd', foo='1', rest=['-f2', '3'])
    ('-f1 -- cmd -- -f2 3', NS(cmd='cmd', foo='1', rest=['--', '-f2', '3']))

    my python's version is: 2.7.5, 3.6.8

    @shihai1991 shihai1991 added the type-bug An unexpected behavior, bug, or error label Sep 6, 2019
    @horazont
    Copy link
    Mannequin

    horazont mannequin commented Oct 3, 2019

    Since I have been adversely affected by this bug (1), I looked at the patches.

    I combined bpo-14364.test.patch (which adds test cases for --foo=--) and dbldash.patch in my local working tree and that seems to resolve the issue (tests pass if and only if I apply dbldash.patch and my reproducer from 1) passes too).

    The patches do not contain any type of metainformation, so I’m not comfortable with submitting this as a PR. I am also not at all familiar with the process of managing the changelog etc.

    This should serve as a confirmation that this issue can be resolved with the patches. Someone more familiar than me with the process could take up the task to get this merged.

    Note: As you can see in 1, this issue has already caused data loss.

    @shihai1991
    Copy link
    Member

    Hi, Jonas. Thanks for your report.
    Let us wait core team's discuss;)

    @rhettinger
    Copy link
    Contributor

    Paul and David, is the current PR complete in your opinion? Are there known cases where the PR would break existing, working code?

    Also there needs to be doc entry that is clear on both new and old strategy for distinguishing options from arguments when a dash or dashdash is present. The PR's Misc/NEWS entry, "Fix behavior of argparse when '--' as argument to option", is insufficient.

    @rhettinger rhettinger added 3.8 (EOL) end of life 3.9 only security fixes labels Oct 6, 2019
    @rhettinger rhettinger self-assigned this Oct 6, 2019
    @shihai1991
    Copy link
    Member

    The PR's Misc/NEWS entry, "Fix behavior of argparse when '--' as argument to option", is insufficient.

    Thanks for your comment, Raymond. I would continue update the desc.

    @rhettinger
    Copy link
    Contributor

    Unassigning because I haven't been able to make time for this one.

    @vadmium
    Copy link
    Member

    vadmium commented May 4, 2024

    I expect this is now fixed for 3.11+ via #109475

    @github-project-automation github-project-automation bot moved this from Bugs to Doc issues in Argparse issues Sep 20, 2024
    @serhiy-storchaka serhiy-storchaka closed this as not planned Won't fix, can't repro, duplicate, stale Sep 20, 2024
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life 3.8 (EOL) end of life 3.9 only security fixes stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    Status: Doc issues
    Development

    No branches or pull requests

    5 participants