Search code examples
pythonfiledefaultargparseoptional-arguments

python argparse, search for specific file if option is omitted


I have an argument for input file and its easy to handle it with argparse

parser.add_argument( '-al', nargs = 1, type = argparse.FileType( 'r' ),
                     dest = 'alphabet' )

This parameter is optional but if it is omitted I still need to get this input file by searching current directory. And if there is more than one or none file with .al extensions I will raise the error, otherwise open file I found.

#if no alphabet look for .al file in current directory
if( args.alphabet == None ):
    AlFiles = [ f for f in os.listdir( '.' ) 
                if os.path.isfile( f ) and f.endswith( '.al' ) ]

    #there should be one file with .al extension
    if( len( AlFiles ) != 1 ):
            sys.exit( 'error: no alphabet file provided and '
                    'there are more than one or no .al file in current directory, '
                    'which leads to ambiguity' )

    args.alphabet = open( AlFiles[0], 'r' )

Is there anyway to perform this with argparse, with default or action parameters maybe. If I do the search before parsing arguments and there are an exception situation I still can not raise it because needed file may be provided by command line arguments. I thought of performing action if parser did not meet needed parameter, but can not find out how to do it with argparse.


Solution

  • You can fix that by setting the default attribute for the argument.

    parser = argparse.ArgumentParser()
    parser.add_argument('-al',
                        type = argparse.FileType('r'),
                        default = [ f for f in os.listdir( '.' )
                                    if os.path.isfile( f ) and f.endswith( '.al' )],
                        dest = 'alphabet' )
    

    And afterwards do your checking. That way you only have one function checking if there are more than one or none *.al files whether the argument was omitted or not.

    This could, for example, be accomplished by something like this:

    args =  parser.parse_args()
    if isinstance(args.alphabet,types.ListType):
        if len(args.alphabet) != 1:
            parser.error("There must be exactly one alphabet in the directory")
        else:
            args.alphabet = open(args.alphabet[0])
    

    This way args.alphabet will hold an open file if there was a alphabet file specified or there is only one alphabet file in the current working directory, but will raise an error if there are more or none in the cwd.

    Note: Because we get a list if the -al argument is omitted, argparse.FileType('r') will not open any file. You also have to omit nargs=1 since that would create a list containing the one opened file, the user specified in the -al argument. Omitting this attribute will give us the raw open file, the user specified.

    EDIT: You will have to import types.