[Tutor] Script Feedback
Steven D'Aprano
steve at pearwood.info
Tue Mar 30 18:57:54 CEST 2010
On Wed, 31 Mar 2010 01:27:43 am Damon Timm wrote:
[...]
> My initial questions are:
>
> 1. Is there a better way to implement a --quiet flag?
I usually create a function "print_" or "pr", something like this:
def print_(obj, verbosity=1):
if verbosity > 0:
print obj
and then have a variable "verbosity" which defaults to 1 and is set to 0
if the user passes the --quiet flag. Then in my code, I write:
print_("this is a message", verbosity)
> 2. I am not very clear on the use of Exceptions (or even if I am
> using it in a good way here) — is what I have done the right
> approach?
Hmmm... perhaps.
Usually, you want to catch an exception in order to try an alternative
approach, e.g.:
try:
result = somefunction(x)
except ValueError:
# Fall back on some other approach.
result = "something else"
Occasionally, you want to catch an exception just to ignore it. It's
generally *not* a good idea to catch an exception just to print an
error message and then exit, as you do. Just let the exception
propagate, and Python will print a rich and detailed traceback together
with your error message.
However, a reasonable exception (pun intended) for that rule is to hide
the traceback from the users, who probably can't do anything about it,
and would only get confused by the details. So you want to have your
functions and classes raise exceptions, and the application layer (the
user interface) catch them.
So I would do something like this (untested). In your function code:
...
if os.path.exists(tar_name):
msg = "A tar file already exists this this directory name." \
" Move or rename it and try again."
raise DestinationTarFileExists(msg)
Then your application layer looks something like:
if __name__ == '__main__':
try:
...
except KeyboardInterrupt:
sys.exit(1)
except DestinationTarFileExists, e:
print e.message
sys.exit(2)
# Any other exception is unexpected, so we allow Python
# to print the full traceback as normal.
> 3. Finally, in general: any feedback on how to improve
> this? (I am thinking, just now, that the script is only suitable for
> a command line usage, and couldn’t be imported by another script, for
> example.)
Separate the underlying functionality from the application-level code.
These functions should NEVER print anything: they do all communication
through call-backs, or by returning a value, or raising an exception.
E.g.:
def tar_bzip2_directories(directories, callback=None):
for directory in directories:
file_name = '-'.join(directory.split(' '))
tar_name = file_name.replace('/','').lower() + ".tar.bz2"
if os.path.exists(tar_name):
raise DestinationTarFileExists(errmsg)
if callback is not None:
callback(directory, filename, tarname)
...
Create a main function that runs your application:
def main(argv=None, callback=None):
if argv is None:
argv = sys.argv
process_command_line_options(argv)
if callback is None:
def callback(dirname, filename, tarname):
print "Processing ..."
tar_bzip2_directories(...)
if __name__ == '__main__':
try:
main()
except ... # as above
Now anyone can import the module and call individual functions, or even
call main, or they can run it as a script.
Hope this helps,
--
Steven D'Aprano
More information about the Tutor
mailing list