Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Python - command Line how to Args

Posted on 2011-03-16
10
Medium Priority
?
772 Views
Last Modified: 2012-06-27
Hi,

from the commend line I need to execute a file liek this.

test.py daily [YYY-WW-DD-HH]

the date time stamp is optional

Is is the first time I am doing this.

What is the code to get this info?

If the time is optional then revert to current time e.g.

if input_time==None:
 time = now

0
Comment
Question by:dmontgom
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
  • 2
  • +2
10 Comments
 
LVL 16

Expert Comment

by:sjklein42
ID: 35153021
http://diveintopython.org/scripts_and_streams/command_line_arguments.html

Each command-line argument passed to the program will be in sys.argv, which is just a list.

Put this in your program to see how the arguments are being passed in:

#argecho.py

import sys

for arg in sys.argv: 
    print arg

Open in new window

0
 

Author Comment

by:dmontgom
ID: 35153068
I am not looking for a link....looking for a solution.  I know how to google.

Here a better link

http://www.doughellmann.com/PyMOTW/getopt/

I am looking for best pratice for handing the case where the second optinal is optional.
0
 

Author Comment

by:dmontgom
ID: 35153254
THis is what I did...but I know its not proper.  What is best practice?

 #job-name = daily | hourly
    if sys.argv[1:][0]=='daily':
        job_type='daily'
    elif sys.argv[1:][0]=='hourly':
        job_type='hourly'
    else:
        print 'job name not specified'
        exit()
       
    #YYYY-MM-DD-HH
    try:
        dt_flag = sys.argv[1:][1]
        if len(dt_flag)!=13:
            print 'date is not in proper format'
            exit()
        now_utc = datetime.datetime.fromtimestamp(time.mktime(time.strptime(dt_flag, "%Y-%m-%d-%H")))
    except:
        now_utc = datetime.datetime.now(timezone('UTC'))
0
Enroll in September's Course of the Month

This month’s featured course covers 16 hours of training in installation, management, and deployment of VMware vSphere virtualization environments. It's free for Premium Members, Team Accounts, and Qualified Experts!

 
LVL 8

Expert Comment

by:LunarNRG
ID: 35153712
Best practice? Why didn't you say so? ;)

Although, I'm not sure you'll get consensus.  I tend to think that employing the argparse[1] module (now included in python 3.2) might be considered the best practice (also available as a 3rd party module for previous python versions). It has facilities for optional arguments.

You should really try to avoid using bare excepts, in favor of explicitly specifying the type of exception expected (the latter being the best practice). Otherwise, I don't think there is a whole lot wrong with your approach -- you can simplify it some, perhaps take greater advantage of exception handling. Something like (untested) ...

try:
    job_type, dt_flag = sys.argv[1:]
except ValueError:
    try:
        job_type = sys.argv[1:][0]
    except IndexError:
        print 'job name is a required argument'
        sys.exit(1)
    now_utc = datetime.datetime.now(timezone('UTC'))
else:
    if job_type.lower() not in ('hourly', 'daily'):
        print 'invalid job name'
        sys.exit(1)
    try:
        now_utc = datetime.datetime.fromtimestamp(time.mktime(time.strptime(dt_flag, "%Y-%m-%d-%H")))
    except ValueError:
        print 'date is not in proper format'
        sys.exit(1)

Open in new window


[1] http://docs.python.org/dev/library/argparse.html

HTH
0
 
LVL 8

Expert Comment

by:LunarNRG
ID: 35153763
FWIW, here an example using argparse (also untested) ...

import argparse

def datify(s):
    try:
        return datetime.datetime.fromtimestamp(time.mktime(time.strptime(s, "%Y-%m-%d-%H")))
    except ValueError:
        raise argparse.ArgumentTypeError('date is not in proper format')

parser = argparse.ArgumentParser()
parser.add_argument('jobtype', choices=['hourly', 'daily'])
parser.add_argument('nowutc', type=datify)

args = parser.parse_args()

print args.jobtype
print args.nowutc

Open in new window


0
 
LVL 29

Accepted Solution

by:
pepr earned 500 total points
ID: 35154791
I suggest to start with as simple as possible approach and enhance it later. Try the code below:

a.py
import sys
import time

print sys.argv              # this is a Python list data type

if len(sys.argv) < 2:       # sys.argv[0] is the name of a program/script
    print 'Expecting at least one argument.'
    sys.exit(1)             # terminate immediately
    
frequency = sys.argv[1]     # 'daily' or whatever -- you should test it
theTime = time.localtime()  # default, now

if len(sys.argv) > 2:       # the third argument present
    theTime = time.strptime(sys.argv[2], '%Y-%m-%d-%H')
    
print frequency
print theTime    

Open in new window


You can try to call it like this

C:\tmp\___python\dmontgom\Q_26892495>python a.py
['a.py']
Expecting at least one argument.

C:\tmp\___python\dmontgom\Q_26892495>python a.py daily
['a.py', 'daily']
daily
time.struct_time(tm_year=2011, tm_mon=3, tm_mday=17, tm_hour=10, tm_min=0, tm_sec=51, tm_wday=3, tm_yday=76, tm_isdst=0)

C:\tmp\___python\dmontgom\Q_26892495>python a.py daily 2011-03-11-10
['a.py', 'daily', '2011-03-11-10']
daily
time.struct_time(tm_year=2011, tm_mon=3, tm_mday=11, tm_hour=10, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=70, tm_isdst=-1)

C:\tmp\___python\dmontgom\Q_26892495>python a.py daily cripledTS
['a.py', 'daily', 'cripledTS']
Traceback (most recent call last):
  File "a.py", line 14, in <module>
    theTime = time.strptime(sys.argv[2], '%Y-%m-%d-%H')
  File "c:\Python27\lib\_strptime.py", line 454, in _strptime_time
    return _strptime(data_string, format)[0]
  File "c:\Python27\lib\_strptime.py", line 325, in _strptime
    (data_string, format))
ValueError: time data 'cripledTS' does not match format '%Y-%m-%d-%H'

Open in new window


I am not sure if the format of the timestamp is what you really want (not clear from the question).

I suggest to add the try/except construct only when you are sure why -- see the last example.  Also, there is no need for datetime manipulation unless you want do do some calculation where working with the time structure is not enough.

A side note: I can see no reason for using expressions like sys.argv[1:][0].  This is simply sys.argv[1] only extracted by more complex way.
0
 
LVL 29

Expert Comment

by:pepr
ID: 35154808
0
 
LVL 8

Assisted Solution

by:LunarNRG
LunarNRG earned 500 total points
ID: 35157091
There are potentially even more problems, but these few stood out to me after re-reading my posts -- and it's safe to assume both remain untested. I've also included a few notes, as comments in the code. Please ask questions, if you need additional clarification.

#!/usr/bin/env python
import sys, datetime
from pytz import timezone

# take only the first 2 arguments, if less than 2 check for one
try: 
    # this will ignore arguments after the 2nd
    job_type, dt_flag = sys.argv[1:3]
except ValueError:
    # take the first argument, exit if not given
    try: 
        # pepr is right about [1:][0] vs [1]
        job_type = sys.argv[1]
    except IndexError:
        print 'job name is a required argument'
        sys.exit(1)
    # default value for optional argument
    now_utc = datetime.datetime.now(timezone('UTC'))
else:
    # restrict choices of first argument
    if job_type not in ('hourly', 'daily'):
        print 'invalid job name'
        sys.exit(1)
    try:
        # datetime objects now have a strptime method, starting w/ python 2.5
        now_utc = datetime.datetime.strptime(dt_flag, "%Y-%m-%d-%H")
    except ValueError:
        print 'date is not in proper format'
        sys.exit(1)

Open in new window


Sample output:

$ ./args2.py 
job name is a required argument
$ ./args2.py daily
daily
2011-03-17 14:53:39.420964+00:00
$ ./args2.py daily 2011-01-01-01
daily
2011-01-01 01:00:00
$ ./args2.py daily 2011-01-01
date is not in proper format
$ ./args2.py monthly 2011-01-01-01
invalid job name

Open in new window


#!/usr/bin/env python
import argparse, datetime
from pytz import timezone

# argparse handles most of the drudgery of dealing with 
# command-line options and arguments, as you can see ...

# you can define your own "type" functions in argparse, very useful
def convert_to_date(strng):
    try:
        return datetime.datetime.strptime(strng, "%Y-%m-%d-%H")
    except ValueError:
        raise argparse.ArgumentTypeError('date is not in proper format')

parser = argparse.ArgumentParser()
parser.add_argument('jobtype', choices=['hourly', 'daily'], metavar='JOBTYPE', help='The job name.')
# default value, used when the 2nd arg is not passed
parser.add_argument(
    'nowutc', nargs='?', type=convert_to_date, metavar='TIMESTAMP',
    default=datetime.datetime.now(timezone('UTC')), help='Timestamp [optional]'
)

args = parser.parse_args()

print args.jobtype
print args.nowutc

Open in new window


Sample output:

$ ./args.py
usage: args.py [-h] JOBTYPE [TIMESTAMP]
args.py: error: too few arguments
$ ./args.py daily
daily
2011-03-17 14:53:35.128120+00:00
$ ./args.py daily 2011-01-01-01
daily
2011-01-01 01:00:00
$ ./args.py daily 2011-01-01
usage: args.py [-h] JOBTYPE [TIMESTAMP]
args.py: error: argument TIMESTAMP: date is not in proper format
$ ./args.py monthly 2011-01-01-01
usage: args.py [-h] JOBTYPE [TIMESTAMP]
args.py: error: argument JOBTYPE: invalid choice: 'monthly' (choose from 'hourly', 'daily')
$ ./args.py -h
usage: args.py [-h] JOBTYPE [TIMESTAMP]

positional arguments:
  JOBTYPE     The job name.
  TIMESTAMP   Timestamp [optional]

optional arguments:
  -h, --help  show this help message and exit

Open in new window

0
 
LVL 31

Expert Comment

by:James Murrell
ID: 36515798
This question has been classified as abandoned and is closed as part of the Cleanup Program. See the recommendation for more details.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The really strange introduction Once upon a time there were individuals who intentionally put the grass seeds to the soil with anticipation of solving their nutrition problems. Or they maybe only played with seeds and noticed what happened... Som…
Sequence is something that used to store data in it in very simple words. Let us just create a list first. To create a list first of all we need to give a name to our list which I have taken as “COURSE” followed by equals sign and finally enclosed …
Learn the basics of lists in Python. Lists, as their name suggests, are a means for ordering and storing values. : Lists are declared using brackets; for example: t = [1, 2, 3]: Lists may contain a mix of data types; for example: t = ['string', 1, T…
Learn the basics of modules and packages in Python. Every Python file is a module, ending in the suffix: .py: Modules are a collection of functions and variables.: Packages are a collection of modules.: Module functions and variables are accessed us…

722 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question