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
question:
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__":
othermodule.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