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.
--
http://mail.python.org/mailman/listinfo/python-list