Skip to content

Argparse.parse_args exits on unrecognized option with exit_on_error=False #85427

Description

@matthewhughes934
BPO 41255
Nosy @rhettinger, @tirkarthi, @matthewhughes934, @jacobtylerwalls, @bigbirdcode, @joshmeranda
PRs
  • bpo-41255: handle argparse errors with exit_on_error=False consistently #27295
  • gh-85427: Prevent exits if ArgumentParser.exit_on_error is False #30832
  • Files
  • exit_on_error_tests.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 2020-07-09.08:40:33.198>
    labels = ['type-bug', 'library', '3.9']
    title = 'Argparse.parse_args exits on unrecognized option with exit_on_error=False'
    updated_at = <Date 2022-01-29.03:10:17.942>
    user = 'https://github.com/matthewhughes934'

    bugs.python.org fields:

    activity = <Date 2022-01-29.03:10:17.942>
    actor = 'jacobtylerwalls'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2020-07-09.08:40:33.198>
    creator = 'mhughes'
    dependencies = []
    files = ['49310']
    hgrepos = []
    issue_num = 41255
    keywords = ['patch']
    message_count = 10.0
    messages = ['373382', '373383', '373385', '373405', '373437', '373440', '373470', '396345', '397975', '401629']
    nosy_count = 7.0
    nosy_names = ['rhettinger', 'paul.j3', 'xtreak', 'mhughes', 'jacobtylerwalls', 'bigbird', 'joshmeranda']
    pr_nums = ['27295', '30832']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue41255'
    versions = ['Python 3.9']

    Activity

    1. matthewhughes934 commented on Jul 9, 2020

      matthewhughes934mannequin
      MannequinAuthor
      >>> import argparse
          >>> parser = argparse.ArgumentParser(exit_on_error=False)
          >>> parser.parse_args(["--unknown"])
          usage: [-h]
          : error: unrecognized arguments: --unknown

      The docs https://docs.python.org/3.10/library/argparse.html#exit-on-error say:

      Normally, when you pass an invalid argument list to the parse_args() method of an ArgumentParser, it will exit with error info.
      If the user would like catch errors manually, the feature can be enable by setting exit_on_error to False:

      This description _appears_ to be at odds with the observed behavior.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      type-bugAn unexpected behavior, bug, or error
      on Jul 9, 2020
    3. tirkarthi commented on Jul 9, 2020

      @tirkarthi
      Member

      I guess the docs by manually mean that ArgumentError will be raised when exit_on_error is False that can be handled. By default with exit_on_error being True self.error() which raises SystemExit and catching SystemExit can mask other errors. This was added in bpo-9938 with #59567. There is also a typo in the docs that it should have used enabled instead of enable in "the feature can be enable by setting exit_on_error to False"

    4. matthewhughes934 commented on Jul 9, 2020

      matthewhughes934mannequin
      MannequinAuthor

      typo in the docs that it should have used enabled instead of enable

      Well spotted, I'll happily fix this up.

      I guess the docs by manually mean that ArgumentError will be raised when exit_on_error is False that can be handled.

      To be clear, in this case, even with exit_on_error=False, ArgumentError is _not_ being raised, but SystemExit is.

    5. matthewhughes934 commented on Jul 9, 2020

      matthewhughes934mannequin
      MannequinAuthor

      I've attached a patch containing tests showing the current behavior, namely that exit_on_error does not change the behavior of argparse.ArgumentParser.parse_args in either case:

      • An unrecognized option is given
      • A required option is not given

      Should the docs be updated to note this?

    6. paulj3 commented on Jul 10, 2020

      paulj3mannequin
      Mannequin

      I didn't pay attention to the patch that added this "exit_on_error" parameter. So I don't know exactly what error handling it was supposed to handle or why. But given the location of the code change, it does not handle every possible error.

      Specifically it's in parser.parse_known_args() where it calls _parse_known_args(). With this parameter True, a argparse.ArgumentError is caught and converted to parse.error() call. That's the original behavior.

      With False, there's no special handling for ArgumentError. Catching that is left to the developer, as illustrated in the docs.

      In the documented example, it's a 'type' error. 'choices' would also behave this way. 'nargs' errors also. But not all errors are handled like this.

      Inside _parse_known_args(), self.error() is called several times, once for 'required' arguments failure, and for a required mutually_exclusive_group error. I count 9 self.error() calls; exit_on_error only changes one of those.

      The error highlighted in this issue is called in parser.parse_args(). This calls parse_known_args(), and raises an error if there are 'extras', unrecognized strings.

      So clearly the new docs is is describing this new parameter in overly broad terms. It only changes the handling of a subset of parser.error() calls. Off hand I can't think of clean way of refining the description without getting overly technical about the error handling.

      Developers already had the documented option of changing the parse.error() and parse.exit() methods.

    7. 5 remaining items

    8. paulj3 commented on Sep 11, 2021

      paulj3mannequin
      Mannequin

      In

      https://stackoverflow.com/questions/69108632/unable-to-catch-exception-error-for-argparse

      it looked like exit_on_error does not work when using subparsers. On on further thought, I realized that it has to included in the definition of the subparser. As with other ArgumentParser parameters, the subparsers does not inherit from the main parser.

      So it's basically a documentation issue. The add_parser method is described briefly as:

       which takes a command name and any ArgumentParser constructor 
       arguments, and returns an ArgumentParser object that can be 
       modified as usual.
      

      But as my experience shows, its relevance is easily missed, even by an experienced users.

    9. transferred this issue fromon Apr 10, 2022
    10. added
      3.11only security fixes
      3.12only security fixes
      and removed on Jun 7, 2022
    11. ed-ij commented on Mar 31, 2023

      @ed-ij

      Just wanted to bump this after attempting to use the exit_on_error argument to prevent sys.exit() being called.

      The documentation could at least be improved until a better implementation is available. Adding a note in the documentation for this function which links to the "Exiting methods" section would also be helpful in the interim although I agree with bigbirdcode and joshmeranda that you shouldn't have to override methods just to have control over error handling.

    12. serhiy-storchaka commented on Jun 26, 2024

      @serhiy-storchaka
      Member

      I wrote #121056 before discovering this issue. It is basically an extended version of #30832.

      We now have 3 duplicate issues with 4 open PRs (and one incomplete PR was already merged). It is time to finish this.

    13. moved this from Bugs to Doc issues in Argparse issueson Jun 28, 2024
    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.10 (EOL)end of life3.11only security fixes3.12only security fixesstdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

      Projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions