GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — argparse: optional subparsers · Issue #53499 · python/cpython

argparse: optional subparsers #53499

New issue
Copy link
New issue
Copy link
Closed
Closed
argparse: optional subparsers#53499
Copy link
Labels
3.7 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement

Description

nvie
mannequin
opened on Jul 13, 2010
Issue body actions
BPO 9253
Nosy @csernazs, @jwilk, @merwok, @bitdancer, @wking, @cjerdonek, @Julian, @asottile, @Mariatta, @johnnybubonic, @epicfaace
Dependencies
  • bpo-26510: [argparse] Add required argument to add_subparsers
  • Files
  • ed0fce615582.diff
  • check.py: Test for optional subparsers vs. "too few arguments"
  • required.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 2010-07-13.21:29:47.745>
    labels = ['3.7', 'type-feature', 'library']
    title = 'argparse: optional subparsers'
    updated_at = <Date 2020-04-03.11:22:15.235>
    user = 'https://bugs.python.org/nvie'

    bugs.python.org fields:

    activity = <Date 2020-04-03.11:22:15.235>
    actor = 'bsaner'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2010-07-13.21:29:47.745>
    creator = 'nvie'
    dependencies = ['26510']
    files = ['24217', '28778', '29793']
    hgrepos = ['68', '69', '100', '101', '102']
    issue_num = 9253
    keywords = ['patch']
    message_count = 36.0
    messages = ['110231', '110232', '110244', '110309', '113267', '113512', '113558', '113575', '113577', '121250', '121271', '144484', '144512', '149533', '150757', '150784', '150816', '150821', '150953', '153771', '170491', '180229', '181855', '186052', '186387', '186532', '186695', '193956', '215894', '217461', '267692', '300283', '302294', '302296', '302661', '304594']
    nosy_count = 26.0
    nosy_names = ['csernazs', 'bethard', 'jwilk', 'frispete', 'eric.araujo', 'r.david.murray', 'zzzeek', 'labrat', 'chris.jerdonek', 'nvie', 'DasIch', 'elsdoerfer', 'G2P', 'Julian', 'dsully', 'derks', 'seblu', 'paul.j3', 'bewest', 'bkabrda', 'couplewavylines', 'svilgelm', 'Anthony Sottile', 'Mariatta', 'bsaner', 'epicfaace']
    pr_nums = []
    priority = 'high'
    resolution = None
    stage = 'test needed'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue9253'
    versions = ['Python 3.7']

    Reacted by Michael Terry

    Activity

    Next
    1. nvie commented on Jul 13, 2010

      @nvie
      nviemannequin
      on Jul 13, 2010
      MannequinAuthor
      More actions

      **NOTE**: This is a re-post of http://code.google.com/p/argparse/issues/detail?id=47

      What steps will reproduce the problem?

      parser = argparse.ArgumentParser()
      sub = parser.add_subparsers()
      sub.add_parser("info")
      parser.add_argument("paths", "+")
      parser.parse_args(["foo", "bar"])

      What is the expected output? What do you see instead?
      Expected behavior is that, failing to match one of the subparser inputs
      ("info"), the parser checks if the argument matches any of the top-level
      arguments, in this case the 'paths' multi-arg. In other words, it should be
      possible to make the subparser be optional, such that when the subparser
      argument fails to retrieve any valid subparser, the remaining args are
      parsed as if no subparser exists. At present, it does not seem possible to
      make a subparser be optional at all.
      Perhaps this could be exposed to the user as:

      parser.add_subparsers(nargs=argparse.OPTIONAL)

      or something to that effect. Or, allow a default subparser to be specified.
      I.e.,

      sub = parser.add_subparsers()
      info = sub.add_parser("info")
      main = sub.add_parser("main")
      sub.default = main

      I'm sure the point will come up that the current behavior is correct,
      because given a subparser like "info", a user could easily make a mistake
      like "myapp ino foo bar" and rather than get a safe error be given
      something unexpected. For this reason, I think the default behavior is
      usually going to be correct. BUT, it would still be nice if it could be
      optional, so that developers could be free to make that call. Sometimes the
      potential user errors aren't really an issue, and having to explicitly set
      a subparse arg every time can be a nuissance.

    2. nvie
      added
      stdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory
      type-featureA feature request or enhancementA feature request or enhancement
      on Jul 13, 2010
    3. nvie commented on Jul 13, 2010

      @nvie
      nviemannequin
      on Jul 13, 2010
      MannequinAuthor
      More actions

      Changed the title, so it shows that the feature request is for argparse.

    4. nvie
      changed the title [-]optional subparsers[/-] [+]argparse: optional subparsers[/+] on Jul 13, 2010
    5. bitdancer commented on Jul 13, 2010

      @bitdancer
      bitdancer
      on Jul 13, 2010
      Member
      More actions

      I've added Steven as nosy so he knows this was reposted here. I've also set the priority to low. Personally I'm at least -0 on this, since if I use a command that has subcommands I expect to get an error if I supply an invalid subcommand. As you say, however, the command designer *could* be supplied with the opportunity to shoot themselves in the foot :)

      The issue isn't going to go anywhere unless someone proposes a patch, though.

    6. nvie commented on Jul 14, 2010

      @nvie
      nviemannequin
      on Jul 14, 2010
      MannequinAuthor
      More actions

      Actually, this is a rather common concept. Broadly used tools like for example Git use this kind of subcommand handling.

      This command shows all remotes:
      git remote (i.e. is like git remote list)

      Showing/removing remotes is done using subsubcommands:
      git remote show [...]
      git remote rm [...]

      That, in combination with the explicit design goal that "[argparse] isn't dogmatic about what your command line interface should look like" should be enough reason to be wanting this, in my humble opinion.

    7. bitdancer commented on Aug 8, 2010

      @bitdancer
      bitdancer
      on Aug 8, 2010
      Member
      More actions

      See also 9540, which has an alternate proposal (that I don't like as much) for how to handle parser arguments supplied after subparsers are declared.

      Reviewing this, I'm now +1 on fixing this *somehow*, since clearly there is an ambiguity here that needs to be resolved.

    8. bethard commented on Aug 10, 2010

      @bethard
      bethardmannequin
      on Aug 10, 2010
      Mannequin
      More actions

      Seems like there's minimally the bug that argparse should currently throw an error if you add an argument after subparsers (since that argument will never be parsed under the current semantics).

      I do believe that supporting an optional command like the "git remote" example is useful, but as RDM suggests, this probably won't go anywhere unless someone proposes a patch.

    9. elsdoerfer commented on Aug 10, 2010

      @elsdoerfer
      elsdoerfermannequin
      on Aug 10, 2010
      Mannequin
      More actions

      To expand on my case from bpo-9540, I have a bunch of commands, each of which should enable a specific subset of options only available the individual command, but all of the commands share the same behavior in taking nargs='*' positional arguments:

      ./script.py --global-option command --command-option arg1 arg2 arg3

      For example:

      ./backups.py -c /etc/tarsnap.conf make --no-expire job1 job2

      If no positional arguments are given, all jobs defined in the config file are run. Or, in the above example, only "job1" and "job2" are run.

      The positional arguments are the same for *all* commands. Now I can define them separately for each subparser, which is what I'm currently doing, but I kind of like having the global usage instructions (script.py -h) indicating the fact that positional arguments can be passed after the command.

      In fact, right now I'm able to sort of achieve this by defining the positional nargs arguments both globally (to have them show in usage) and in each subparser (to have them parsed). This wouldn't be possible anymore if argparse where to throw an error after adding arguments after a subparser, although probably a more correct behavior.

      Anyway, while the two issues are clearly related, I don't think that the two are necessarily mutually exclusive. argparse could allow both optional subparsers (if no subparser matches), as well as pass control back to the parent parser once an already matched subparser is no longer able to handle further command line input. Or optionally, support defining subparsers as "options only", so that positional arguments would always be handled by the parent parser.

      Now, I can see how this could potentially become messy if we start talking about these positional arguments handled by the parent then being followed by more flags, which would then presumably also be handled by the parent etc. On the other hand, my use case doesn't seem that strange to me.

    10. merwok commented on Aug 11, 2010

      @merwok
      merwok
      on Aug 11, 2010
      Member
      More actions

      Stable releases don’t go into stable branches, so I’m editing versions. I also remove 3.3 since it doesn’t exist now, it means “this won’t go in 3.2”.

    11. merwok commented on Aug 11, 2010

      @merwok
      merwok
      on Aug 11, 2010
      Member
      More actions

      Wow, it is late. I wanted to write: New features don’t go into stable branches.

    12. G2P commented on Nov 15, 2010

      @G2P
      G2Pmannequin
      on Nov 15, 2010
      Mannequin
      More actions

      Trying to spec this, here is a proposed API:

          parser = argparse.ArgumentParser()
          sub = parser.add_subparsers(default='show')
          sub_show = sub.add_parser('show')
          sub_add = sub.add_parser('add')

      If default isn't passed, the subcommand isn't optional.
      If default is passed, and no explicit subcommand is given,
      the default subcommand is picked.
      Arguments are given to the top parser; passing arguments
      to the subcommand requires naming it explicitly.

      As far as motivation, I'd like to change a program that
      uses --choice options (that can have a default) to use
      more expressive subcommands. Some programs rely on implicit
      subcommands a lot; the ip command on linux is a good
      example.

    13. bethard commented on Nov 16, 2010

      @bethard
      bethardmannequin
      on Nov 16, 2010
      Mannequin
      More actions

      I think the proposed API looks fine and should be backwards compatible since add_subparsers will currently throw an exception with a default= argument.

      In case someone feels like writing a patch, you'll want to look at _SubParsersAction.__init__, which will need to grow the default= argument, and pass a different nargs= argument on. I think you'll need to define a new nargs type which means you probably also need to look at ArgumentParser._get_nargs_pattern as well.

    14. bewest commented on Sep 24, 2011

      @bewest
      bewestmannequin
      on Sep 24, 2011
      Mannequin
      More actions

      I spent some time looking at this, as I was interested in
      using this pattern to simulate what git and hg do. I
      considered a few modifications and then found this bug. I
      think the default keyword passed to
      _SubParsersAction.__init__ makes sense.

      I started on a patch, that looks promising, but I'm having
      trouble getting the regexp right.

      Here's a changeset higlighting where I think the
      problematic regexp is:
      https://bitbucket.org/bewest/argparse/changeset/938e1e91ddd0

      https://gist.github.com/1202975#file_test_opt_subcommand.py
      Is the meager little test I put together.

    15. 16 remaining items

    16. paulj3 commented on Apr 10, 2014

      @paulj3
      paulj3mannequin
      on Apr 10, 2014
      Mannequin
      More actions

      http://stackoverflow.com/questions/22990977/why-does-this-argparse-code-behave-differently-between-python-2-and-3

      is answered by this change in how required arguments are tested, and how subparsers fell through the cracks.

    17. paulj3 commented on Apr 29, 2014

      @paulj3
      paulj3mannequin
      on Apr 29, 2014
      Mannequin
      More actions

      Another Stackoverflow question triggered by this issue

      http://stackoverflow.com/questions/23349349/argparse-with-required-subparser

    18. paulj3 commented on Jun 7, 2016

      @paulj3
      paulj3mannequin
      on Jun 7, 2016
      Mannequin
      More actions

      My answer to

      http://stackoverflow.com/questions/23349349/argparse-with-required-subparser

      is getting a slow but steady stream of + scores; so the required subparser issue is still bothering people.

      This particular question addresses the problem that the error message has when a required subparser is missing - it can't format the error with the default dest - SUPPRESS. The may be a another bug issue that addresses that.

      Anyways, due to this continued attention, I'm going to raise the priority for this issue.

    19. asottile commented on Aug 15, 2017

      @asottile
      asottilemannequin
      on Aug 15, 2017
      Mannequin
      More actions

      I've attempted to address some of the backward/forward compatibility issue with subparsers becoming optional by default (vs required by default in python2) with this pull request: #3027 (would love to get a review as well!)

    20. merwok commented on Sep 15, 2017

      @merwok
      merwok
      on Sep 15, 2017
      Member
      More actions

      I am now reviewing the PR added to the other issue by Anthony. This ticket has a lot of discussion; it would be good to check which parts are addressed by the other ticket, and particularly if the problems noted by Mike and others are now fixed.

    21. asottile commented on Sep 15, 2017

      @asottile
      asottilemannequin
      on Sep 15, 2017
      Mannequin
      More actions

      My patch mainly addresses the regression pointed out by mike bayer (zzzeek)'s comment.

    22. merwok
      added
      3.7 (EOL)end of lifeend of life
      on Sep 20, 2017
    23. merwok commented on Sep 20, 2017

      @merwok
      merwok
      on Sep 20, 2017
      Member
      More actions

      The other PR is now merged in 3.7, and won’t be backported (it changes default behaviour and adds a new param).

    24. paulj3 commented on Oct 18, 2017

      @paulj3
      paulj3mannequin
      on Oct 18, 2017
      Mannequin
      More actions

      In a recent stackoverflow question a user wanted this optional-subparsers ability in Python 2.7.

      https://stackoverflow.com/questions/46667843/how-to-set-a-default-subparser-using-argparse-module-with-python-2-7

      Short of modifying the _parse_known_args method, the best I could suggest was a two stage parsing. That is, one parser without the subparsers. This uses parse_known_args, and if a 'cmd' is provided passes the 'extras' to one that handles subparsers.

      ---

      Another issue which I don't think has been addressed is the 'usage' when subparsers are optional. At least with 3.5, subparsers are displayed with the choices: {'cmd1', 'cmd2', ...}, but no indication of being optional. An optional positional (with ? nargs) would normally be displayed as

       prog [-h] [{'one', 'two'}] ...
      

      My guess is that 'usage' adds the [] when positionals nargs='?', without regard to the 'required' attribute (I should verify this from code).

      I'm undecided as to whether we want the brackets or not. It's more accurate, but makes the usage messier. And the 'help' grouping for 'optional-positionals' is the subject of other bug/issue(s).

      I haven't checked it the patch has changed this behavior.

    25. ezio-melotti
      transferred this issue fromon Apr 10, 2022
    26. erlend-aasland
      added this to Argparse issueson May 19, 2022
    27. erlend-aasland
      moved this to Features in Argparse issueson May 19, 2022
    28. savannahostrowski commented on Jun 5, 2026

      @savannahostrowski
      savannahostrowski
      on Jun 5, 2026
      Member
      More actions

      I'm going to close this as resolved. Subparsers have been optional since Python 3.3, and the complementary required= keyword for add_subparsers() was added in 3.7 (gh-70697 / #3027).

      Reacted by Éric
    29. savannahostrowski
      closed this as completedon Jun 5, 2026
    30. github-project-automation
      moved this from Features to Doc issues in Argparse issueson Jun 5, 2026
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.7 (EOL)end of lifeend of lifestdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement

      Projects

      • Argparse issues
        Status
        Doc issues
        Show more project fields

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.