Q's on my first python script

Dave Angel davea at ieee.org
Sun May 10 15:33:31 EDT 2009

kj wrote:
> Below is my very firs python script.
> This was just a learning exercise; the script doesn't do anything
> terribly exciting: for an argument of the form YYMMDD (year, month,
> day) it prints out the corresponding string YYMMDDW, where W is a
> one-letter abbreviation for the day of the week.  E.g.
> % wd 090511
> 090511M
> The script runs OK, but I can still see a few areas of improvement,
> for which I could use your advice.
> 1. The name of the BadArgument exception class defined in the script
>    does not seem to me sufficiently specific.  If one were to import
>    the script in order to reuse its wkday_abbrev function, I'd like
>    this exception's name to be more unequivocally tied to this
>    script.  What I'm looking for is something like a "namespace"
>    for this script.  What's the pythonic way to construct a namespace?
> 2. In some python modules I've seen the idiom
>    if __name__ == "__main__":
>       # run some tests here
>    I'd like to set up tests for this script, mostly to ensure that
>    it handles the error cases properly, but I'm alread using the
>    idiom above to actually run the script under normal operation.
>    What's the typical python idiom for running tests on a *script*
>    (as opposed to a module that is normally not supposed to be run
>    directly)?
> 3. Still on the subject of testing, how does one capture in a
>    variable the output that would normally have gone to stdout or
>    stderr?
> 4. What's the python way to emit warnings?  (The script below should
>    warn the user that arguments after the first one are ignored.)
> 5. The variable wd is meant to be "global" to the script.  In other
>    languages I've programmed in I've seen some typographic convention
>    used for the name of such variables (e.g. all caps) to signal
>    this widened scope.  Does python have such a convention?
> Any comments/suggestions on these questions, or anything else about
> the script, would be much appreciated.
> TIA!
> kynn
> ----------------------------------------------------------------
> from optparse import OptionParser
> import re
> import datetime
> import sys
> class BadArgument(Exception): pass
> wd = ("M", "T", "W", "H", "F", "S", "U")
> def wkday_abbrev(str):
>   try:
>     mm = re.match("(\d{2})(\d{2})(\d{2})\Z", str)
>     y, m, d = map(lambda x: int(mm.group(x)), (1,2,3))
>     if y < 38: y = y + 1900
>     else: y = y + 2000
>     return wd[datetime.datetime(y, m, d).weekday()]
>   except (AttributeError, ValueError):
>     raise BadArgument()
> def main():
>   usage = '''Usage: %prog [options] YYMMDD
>        %prog -h|--help
> '''
>   parser = OptionParser(usage=usage)
>   parser.add_option("-n", "--no-newline", dest="nonl",
>                     action="store_true", help="omit newline in output")
>   (options, args) = parser.parse_args();
>   try:
>     sys.stdout.write("%s%s" % (args[0], wkday_abbrev(args[0])))
>     if not options.nonl: print
>   except (IndexError, BadArgument):
>     print usage
>     sys.exit(1)
>   except: raise
> if __name__ == "__main__": main()

Other replies cover most of your questions nicely.  But for the testing 

Rename this script to some other name, and call it a module
Write a new script with just three lines in it:

import  othermodule

if __name__ == "__main__":

Now your testing code can go in "othermodule.py"

Note that I would put the argument parsing logic in the new file, so 
parts of main() would actually move.  Normally I'd call main() with two 
arguments - options, args

Your use of optparse could be more streamlined.  For example, it'll 
build the help string for you, based on the various calls to 
add_option(), and it includes its own -h and --help implicitly.

More information about the Python-list mailing list