Getting command line arguments as tuples in python
Asked Answered
S

5

7

Here is an example of how I would like to call my script:

python script.py -f file1.txt "string1" "string2" -f file2.txt "string3" "string4"

Every file that goes as input will have 2 strings associated with that file. There can be any number of files.

To simplify, I am trying to get a print like this:

('file1.txt', 'string1', 'string2')
('file2.txt', 'string3', 'string4')

Here is what I have so far:

import sys, os, traceback, optparse
import time
import re
#from pexpect import run, spawn

def main ():
    global options, args

    print options.filename

    #for filename in options.filename:
    #  print filename
      #f = file(filename,'r')
      #for line in f:
      #  print line,
      #f.close()



if __name__ == '__main__':
    try:
        start_time = time.time()
        parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id$')
        parser.add_option ('-f', '--file', dest='filename', help='write report to FILE', metavar='FILE', nargs=3)
        parser.add_option ('-v', '--verbose', action='store_true', default=False, help='verbose output')
        (options, args) = parser.parse_args()
        #if len(args) < 1:
        #    parser.error ('missing argument')
        if options.verbose: print time.asctime()
        main()
        if options.verbose: print time.asctime()
        if options.verbose: print 'TOTAL TIME IN MINUTES:',
        if options.verbose: print (time.time() - start_time) / 60.0
        sys.exit(0)
    except KeyboardInterrupt, e: # Ctrl-C
        raise e
    except SystemExit, e: # sys.exit()
        raise e
    except Exception, e:
        print 'ERROR, UNEXPECTED EXCEPTION'
        print str(e)
        traceback.print_exc()
        os._exit(1)

With the above script, I get only the second file and related strings:

('file2.txt', 'string3', 'string4')
Sharrisharron answered 21/3, 2011 at 0:36 Comment(1)
I would appreciate if someone could help me with some code to achieve my goals (maybe using argparse). I tried understanding argparse, but couldn't figure out how to proceed. I would learn only if I am able to continue with my mini project. Right now I am stuck just at the argument parsing phase... Starting a bounty.Sharrisharron
M
14

I think you want to use the action=append argument of the add_argument method

import argparse

parser= argparse.ArgumentParser()
parser.add_argument ('-f', '--file', nargs=3, action='append')

files = parser.parse_args('-f file1 string1 string2 -f file2 string3 string4 -f file3 string5 string6'.split()).file

for f in files:
    print tuple(f)

gives you:

('file1', 'string1', 'string2')
('file2', 'string3', 'string4')
('file3', 'string5', 'string6')

Testing on cli:

with:

import argparse

parser= argparse.ArgumentParser(prog='Test', usage='%(prog)s -f Filename Option1 Option2 ')
parser.add_argument ('-f', '--file', nargs=3, action='append')

files = parser.parse_args().file

for f in files:
    print tuple(f)

results:

python test.py -f file1 "foo bar" "baz" -f file2 foo bar
('file1', 'foo bar', 'baz')
('file2', 'foo', 'bar')

python test.py -f file1 "foo bar" "string2" -f file2 foo bar -f file3 "foo" "bar"
('file1', 'foo bar', 'string2')
('file2', 'foo', 'bar')
('file3', 'foo', 'bar')

python test.py -f file1 "foo bar"
usage: Test -f Filename Option1 Option2
Test: error: argument -f/--file: expected 3 argument(s)
Mortonmortuary answered 26/3, 2011 at 5:7 Comment(2)
This works for optparse too, so all you need is adding action='append' to parser.add_option.Bursar
& @Emilio - This works great on optparse. Thank you very much. Accepting this response.Sharrisharron
M
1

argparse supports the notion of accumulators, which allow you to specify the same option more than once, which is probably more like what you want than anything optparse supports (your particular problem is that optparse doesn't know what to do with an argument specified multiple times, so it's "last one wins" at the command line). argparse is included in Python 2.7 and 3.2, but you should be able to download it for anything 2.6.x or later.

Mouthful answered 21/3, 2011 at 0:41 Comment(0)
D
0

You weren't very clear on your constraints, but this will work for any number of -fs and other flags

import getopt
import sys

args = sys.argv[1:]
tuples = []
while args:
    try:
        opts, args = getopt.getopt(args, "f:v", ["file", "verbose"])
    except getopt.GetoptError, err:
        print str(err)
        sys.exit(-1)    

    for o, a in opts:
        if o in ("-f", "--file"):
            tuples.append((a, args.pop(0), args.pop(0)))
        if o in ("-v", "--verbose"):
            print "yep, verbose"

print tuples
Dumah answered 26/3, 2011 at 5:43 Comment(1)
just did a test... this hangs on an incorrect input such as -f file1.txt "string1" "string2" -f file2.txt "string3" --verbose "string4"Dumah
R
0

I would approach this similarly to the previous answer with a slight tweak:

import getopt
import sys

args = sys.argv[1:]
tuples = []
while args:
try:
    (opts, args) = getopt.getopt(args, "f:v", ["file=", "verbose"])
except getopt.GetoptError, err:
    print str(err)
    sys.exit(2)    

Now you can either require input in the following way:

-f file1.txt,string1,string2

And parse it in the following way:

for opt, arg in opts:
    if opt in ("-f", "--file"):
        tuples.append(tuple(arg.split(",")))
    if opt in ("-v", "--verbose"):
        print "yep, verbose"
print tuples

Or design the input as one string:

-f "file1.txt string1 string2"

and split on whatever strikes your fancy.

Rankle answered 27/3, 2011 at 12:58 Comment(0)
U
0

If you are using optparse because you want to remain compatible with python 2.6, the action='append' solution works, too:

import optparse

parser = optparse.OptionParser()
parser.add_option('-f', '--file', dest='filename', nargs=3, action='append')

Demonstration

>>> (opts, args)  = parser.parse_args("-f file1.txt string1 string2 -f file2.txt string3 string4".split())
>>> for fn_tuple in opts.filename:
...    print fn_tuple
('file1.txt', 'string1', 'string2')
('file2.txt', 'string3', 'string4')
Urial answered 28/3, 2011 at 15:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.