Skip to content
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

argparse: type=<callable> doesn't honor nargs > 1 #66248

Closed
ChrisBruner mannequin opened this issue Jul 23, 2014 · 6 comments
Closed

argparse: type=<callable> doesn't honor nargs > 1 #66248

ChrisBruner mannequin opened this issue Jul 23, 2014 · 6 comments
Labels
docs Documentation in the Doc dir type-bug An unexpected behavior, bug, or error

Comments

@ChrisBruner
Copy link
Mannequin

ChrisBruner mannequin commented Jul 23, 2014

BPO 22049
Nosy @bitdancer
Files
  • argparse_typedef_bug.py: Reproducer
  • 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 = <Date 2017-03-28.16:50:13.951>
    created_at = <Date 2014-07-23.17:16:22.349>
    labels = ['type-bug', 'invalid', 'docs']
    title = "argparse: type=<callable> doesn't honor nargs > 1"
    updated_at = <Date 2017-03-28.16:50:13.950>
    user = 'https://bugs.python.org/ChrisBruner'

    bugs.python.org fields:

    activity = <Date 2017-03-28.16:50:13.950>
    actor = 'paul.j3'
    assignee = 'docs@python'
    closed = True
    closed_date = <Date 2017-03-28.16:50:13.951>
    closer = 'paul.j3'
    components = ['Documentation']
    creation = <Date 2014-07-23.17:16:22.349>
    creator = 'Chris.Bruner'
    dependencies = []
    files = ['36048']
    hgrepos = []
    issue_num = 22049
    keywords = []
    message_count = 6.0
    messages = ['223748', '223756', '223916', '223975', '224009', '224240']
    nosy_count = 4.0
    nosy_names = ['r.david.murray', 'docs@python', 'paul.j3', 'Chris.Bruner']
    pr_nums = []
    priority = 'normal'
    resolution = 'not a bug'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue22049'
    versions = ['Python 2.7', 'Python 3.4', 'Python 3.5']

    @ChrisBruner
    Copy link
    Mannequin Author

    ChrisBruner mannequin commented Jul 23, 2014

    From the documentation, I think that argparse should pass the entire nargs-long string to the "type=" callable. Instead, it only passes the first argument (of nargs), making it impossible within argparse's framework to check for a tuple of mixed types, e.g., 2 ints and a float (my case), or a string and three numbers, etc.

    See attached reproducer.

    @ChrisBruner ChrisBruner mannequin added the type-bug An unexpected behavior, bug, or error label Jul 23, 2014
    @bitdancer
    Copy link
    Member

    Nope. The documentation says:

    N (an integer). N arguments from the command line will be gathered together into a list
    

    The type function is applied to each argument independently. It would be easy enough to make this explicit in one of the nargs multi-argument examples by using type as well.

    @bitdancer bitdancer added the docs Documentation in the Doc dir label Jul 23, 2014
    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Jul 25, 2014

    Note that

    '-t 1 2 3'.split()
    

    becomes

    ['-t', '1', '2', '3']
    

    Your 'type' function sees those 3 strings individually. Try printing 'string' the first thing in your function to see what we mean.

    @ChrisBruner
    Copy link
    Mannequin Author

    ChrisBruner mannequin commented Jul 25, 2014

    Yes, I know. My function just sees '1', but I think it should see '1 2 3' so that it can figure out what to do. That's impossible (well, impossible without saving state between calls) when it sees the arguments piecemeal.

    Sent from my iPhone

    On Jul 24, 2014, at 9:42 PM, paul j3 <report@bugs.python.org> wrote:

    paul j3 added the comment:

    Note that

    '-t 1 2 3'.split()

    becomes

    ['-t', '1', '2', '3']

    Your 'type' function sees those 3 strings individually. Try printing 'string' the first thing in your function to see what we mean.

    ----------
    nosy: +paul.j3


    Python tracker <report@bugs.python.org>
    <http://bugs.python.org/issue22049\>


    @paulj3
    Copy link
    Mannequin

    paulj3 mannequin commented Jul 25, 2014

    What you want is a custom Action rather than a custom Type.

    from the documentation:

        >>> class FooAction(argparse.Action):
        ...     def __call__(self, parser, namespace, values, option_string=None):
        ...         print('%r %r %r' % (namespace, values, option_string))
        ...         setattr(namespace, self.dest, values)

    'values' will be the list ['1','2','3'], which you test and manipulate, before finally saving it to the 'namespace'.

        ret = (int(values[0]), int(values[1]), float(values[2]))
        setattr(namespace, self.dest, ret)

    Setting 'nargs=3' ensures that this action will always get a 3 item list. If the parser can't give it 3 items, it will raise an error rather than call your Action.

    'optparse' passed the remaining argument strings to Option's callback, which could consume as many as it wanted. 'argparse' does not give the Actions that power. There is a fundamental difference in the parsing algorithm.

    @ChrisBruner
    Copy link
    Mannequin Author

    ChrisBruner mannequin commented Jul 29, 2014

    Just had a chance to try this, and this does exactly what I wanted from
    "type=". Thank you!

    On Fri, Jul 25, 2014 at 4:17 PM, paul j3 <report@bugs.python.org> wrote:

    paul j3 added the comment:

    What you want is a custom Action rather than a custom Type.

    from the documentation:

    \>\>\> class FooAction(argparse.Action):
    ...     def \_\_call__(self, parser, namespace, values,
    

    option_string=None):
    ... print('%r %r %r' % (namespace, values, option_string))
    ... setattr(namespace, self.dest, values)

    'values' will be the list ['1','2','3'], which you test and manipulate,
    before finally saving it to the 'namespace'.

    ret = (int(values[0]), int(values[1]), float(values[2]))
    setattr(namespace, self.dest, ret)
    

    Setting 'nargs=3' ensures that this action will always get a 3 item list.
    If the parser can't give it 3 items, it will raise an error rather than
    call your Action.

    'optparse' passed the remaining argument strings to Option's callback,
    which could consume as many as it wanted. 'argparse' does not give the
    Actions that power. There is a fundamental difference in the parsing
    algorithm.

    ----------


    Python tracker <report@bugs.python.org>
    <http://bugs.python.org/issue22049\>


    @paulj3 paulj3 mannequin closed this as completed Mar 28, 2017
    @paulj3 paulj3 mannequin added the invalid label Mar 28, 2017
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    docs Documentation in the Doc dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    1 participant