This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author paul.j3
Recipients docs@python, paul.j3
Date 2014-09-14.05:46:36
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1410673598.78.0.274465754789.issue22401@psf.upfronthosting.co.za>
In-reply-to
Content
When there's a conflict involving an argument that was added via 'parents', and the conflict handler is 'resolve', the action in the parent parser may be damaged, rendering that parent unsuitable for further use.

In this example, 2 parents have the same '--config' argument:
  
    parent1 = argparse.ArgumentParser(add_help=False) 
    parent1.add_argument('--config')

    parent2 = argparse.ArgumentParser(add_help=False)
    parent2.add_argument('--config')

    parser = argparse.ArgumentParser(parents=[parent1,parent2],
        conflict_handler='resolve')

The actions of the 3 parsers are (from the ._actions list):

               (id,          dest,    option_strings)
    parent1:  [(3077384012L, 'config', [])]    # empty option_strings

    parent2:  [(3076863628L, 'config', ['--config'])]

    parser:   [(3076864428L, 'help', ['-h', '--help']),
               (3076863628L, 'config', ['--config'])]  # same id

The 'config' Action from 'parent1' is first copied to 'parser' by reference (this is important).  When 'config' from 'parent2' is copied, there's a conflict.  '_handle_conflict_resolve()' attempts to remove the first Action, so it can add the second.  But in the process it ends up deleting the 'option_strings' values from the original action.

So now 'parent1' has an action in its 'optionals' argument group with an empty option_strings list.  It would display as an 'optionals' but parse as a 'positionals'.  'parent1' can no longer be safely used as a parent for another (sub)parser, nor used as a parser itself.

The same sort of thing would happen, if, as suggested in the documentation:

    "Sometimes (e.g. when using parents_) it may be useful to simply
     override any older arguments with the same option string." 

In test_argparse.py, 'resolve' is only tested once, with a simple case of two 'add_argument' statements.  The 'parents' class tests a couple of cases of conflicting actions (for positionals and optionals), but does nothing with the 'resolve' handler.

------------------------------

Possible fixes:

- change the documentation to warn against reusing such a parent parser

- test the 'resolve' conflict handler more thoroughly

- rewrite this conflict handler so it does not modify the action in the parent

- possibly change the 'parents' mechanism so it does a deep copy of actions.

References:

http://stackoverflow.com/questions/25818651/argparse-conflict-resolver-for-options-in-subcommands-turns-keyword-argument-int

http://bugs.python.org/issue15271 
argparse: repeatedly specifying the same argument ignores the previous ones

http://bugs.python.org/issue19462
Add remove_argument() method to argparse.ArgumentParser

http://bugs.python.org/issue15428
add "Name Collision" section to argparse docs
History
Date User Action Args
2014-09-14 05:46:39paul.j3setrecipients: + paul.j3, docs@python
2014-09-14 05:46:38paul.j3setmessageid: <1410673598.78.0.274465754789.issue22401@psf.upfronthosting.co.za>
2014-09-14 05:46:38paul.j3linkissue22401 messages
2014-09-14 05:46:36paul.j3create