New submission from paul j3:

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

----------
assignee: docs@python
components: Documentation, Library (Lib), Tests
messages: 226862
nosy: docs@python, paul.j3
priority: normal
severity: normal
status: open
title: argparse: 'resolve' conflict handler damages the actions of the parent 
parser
type: behavior
versions: Python 3.5

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue22401>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to