Unexpected Error using the parse_args () function of the ArgumentParser object in Python

4

In a simple code I'm doing in Python, I get the exception below, when I call the function parser_args() on the object of type ArgumentParser :

Unexpected error: (<type 'exceptions.SystemExit'>, SystemExit(0,), <traceback object at 0x10c97fdd0>)

At the end I added the full tracer.

I started writing the code now, based on the template offered by Eclipse Mars.1 plus its the PyDev plugin, and there is nothing else besides the code below:

#!/usr/local/bin/python2.7
# encoding: utf-8
'''
br.com.cdcp.python.client -- Um Cliente TCP para comprovação de conhecimentos em programação Python

br.com.cdcp.python.client faz conexão com um sevidor que receber uma mensagem TCP,
aguarda a confirmação do envio, e armazena o token para uso futuro.

@author:     Carlos Delfino

@copyright:  2015, cdcp. All rights reserved.

@license:    GNU

@contact:    [email protected]
@deffield    updated: Updated
'''

import sys
import os

from argparse import ArgumentParser
from argparse import RawDescriptionHelpFormatter

__all__ = []
__version__ = 0.1
__date__ = '2015-11-17'
__updated__ = '2015-11-17'

DEBUG = 1
TESTRUN = 0
PROFILE = 0

class CLIError(Exception):
    '''Generic exception to raise and log different fatal errors.'''
    def __init__(self, msg):
        super(CLIError).__init__(type(self))
        self.msg = "E: %s" % msg
    def __str__(self):
        return self.msg
    def __unicode__(self):
        return self.msg


def main(argv=None): # IGNORE:C0111
    '''Opções da Linha de Comando.'''

    if argv is None:
        argv = sys.argv
    else:
        sys.argv.extend(argv)

    program_name = os.path.basename(sys.argv[0])
    program_version = "v%s" % __version__
    program_build_date = str(__updated__)
    program_version_message = '%%(prog)s %s (%s)' % (program_version, program_build_date)
    program_shortdesc = __import__('__main__').__doc__.split("\n")[1]
    program_license = '''%s

  Created by Carlos Delfino on %s.
  Copyright 2015 cdcp. All rights reserved.

  GNU - Versão 3.0

  Distributed on an "AS IS" basis without warranties
  or conditions of any kind, either express or implied.

USAGE
''' % (program_shortdesc, str(__date__))

    try:
        # Setup argument parser
        parser = ArgumentParser(
                                description=program_license,
                                formatter_class=RawDescriptionHelpFormatter)
        parser.add_argument('-s', '--server',
                            action="store",
                            required = False)
        parser.add_argument('-p', '--port',
                            action="store",
                            required = False)
        #parser.add_argument('-v', '--version',
        #                    action='version',
        #                    version=program_version_message)

        # Process arguments
        args = parser.parse_args()

        server = args.server
        port = args.port

        msg = '''
Servidor Selecionado: %s
Porta a ser usada: %s
''' % (server,port)
        sys.stdout.write(msg)

        return 0
    except KeyboardInterrupt:
        ### handle keyboard interrupt ###
        return 0
    except Exception as e:
        if DEBUG or TESTRUN:
            raise(e)
        indent = len(program_name) * " "
        sys.stderr.write(program_name + ": " + repr(e) + "\n")
        sys.stderr.write(indent + " use --help para obter ajuda.")
        return 2
    except:
        print "Unexpected error:", sys.exc_info()
        raise

if __name__ == "__main__":
    if DEBUG:
        sys.argv.append("-h")
    if TESTRUN:
        import doctest
        doctest.testmod()
    if PROFILE:
        import cProfile
        import pstats
        profile_filename = 'br.com.cdcp.python.client_profile.txt'
        cProfile.run('main()', profile_filename)
        statsfile = open("profile_stats.txt", "wb")
        p = pstats.Stats(profile_filename, stream=statsfile)
        stats = p.strip_dirs().sort_stats('cumulative')
        stats.print_stats()
        statsfile.close()
        sys.exit(0)

    sys.exit(main())

I'm using Python 2.7 on a Mac with El Capitain.

I've tried both Eclipse Mars.1, the Python console, and the command line by running the file directly.

Below is the complete tracer:

Traceback (most recent call last):
  File "/Users/extracbd/workspace/cdcp/workspace-entrevista-carlos-delfino/Client-Python/src/br/com/cdcp/python/client.py", line 197, in <module>
    exitCode = main()
  File "/Users/extracbd/workspace/cdcp/workspace-entrevista-carlos-delfino/Client-Python/src/br/com/cdcp/python/client.py", line 134, in main
    args = parseArgs(argv)
  File "/Users/extracbd/workspace/cdcp/workspace-entrevista-carlos-delfino/Client-Python/src/br/com/cdcp/python/client.py", line 95, in parseArgs
    args = parser.parse_args()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1701, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1733, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1939, in _parse_known_args
    start_index = consume_optional(start_index)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1879, in consume_optional
    take_action(action, args, option_string)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 1807, in take_action
    action(self, namespace, argument_values, option_string)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 997, in __call__
    parser.exit()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py", line 2362, in exit
    _sys.exit(status)
SystemExit: 0
    
asked by anonymous 17.11.2015 / 22:04

1 answer

2

Well, following my hypothesis, I went looking for the same Python code to see how it works. In the end it's pretty simple.

The class _HelpAction is logged as the action that should be taken when the argument -h or --help is passed in the command line. This class defines the __call__ method, which, when executed, calls the exit method of the parser that is passed as an argument.

The exit method belongs to the ArgumentParser class and it swims more than calling the exit method of the sys module.

Arriving at the root of all ills, the Python documentation on the sys module , says that this method does nothing more than generate a SystemExit exception and therefore, it will be caught if you have a finally or a last except like the one you put in.

The last paragraph of the documentation is clearer, which, translated freely, looks like this:

  

Given that exit() ultimately only throws an exception,   it will only terminate the process if it is called from the main thread and   if the exception is not intercepted .

To work around this problem and keep an exception that ensures that all errors have been caught, you can put a condition that if it is SystemExit passed with argument 0 , you can end the program quietly without printing anything or logging of something.

Or, a simpler solution, you can rely on the argparse module to deal with exceptions and simply take management out of block arguments try :

# ...
parser = ArgumentParser(
    description=program_license,
    formatter_class=RawDescriptionHelpFormatter)
parser.add_argument(
    '-s', '--server',
    action="store",
    required = False)
parser.add_argument(
    '-p', '--port',
    action="store",
    required = False)

# Process arguments
args = parser.parse_args()

server = args.server
port = args.port

try:
    msg = '''
Servidor Selecionado: %s
Porta a ser usada: %s
''' % (server,port)
    sys.stdout.write(msg)
    # ...
    
19.11.2015 / 18:10