The Artima Developer Community
Sponsored Link

Weblogs Forum
Python main() functions

29 replies on 2 pages. Most recent reply: Mar 13, 2012 11:08 PM by skippy V

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 29 replies on 2 pages [ « | 1 2 ]
The Mollusc

Posts: 1
Nickname: mollusc
Registered: Jul, 2003

Re: Python main() functions Posted: Jul 20, 2003 6:12 AM
Reply to this message Reply
Advertisement
I've been thinking recently about making Python modules more testable having seen way too many ad-hoc main functions. To my main functions I add a funky command line interface:


def main():
from cmd import Cmd
class dbcmd(Cmd):
def deault(self, line):
print 'Unknown command: ', line
def do_EOF(self, line):
print
return 1
def do_foo(self, line):
print 'bar'
import readline
c = dbcmd()
c.prompt = 'db> '
readline.parse_and_bind('tab: complete')
readline.set_completer(c.complete)
c.cmdloop()


There are several advantages to this little pattern. You get a nice little command line interface to your module if you execute it instead of importing it (with command line completion as well - woot!) Make your commands simple wrappers around the exported functions.

Unfortunately, once you throw command line parsing in it starts to get a bit heavyweight. Perhaps some creative use of builtin modules can be done to make this simpler. I haven't investigated it yet.

David M. Wilson

Posts: 1
Nickname: davemw
Registered: Nov, 2003

Re: Python main() functions Posted: Nov 10, 2003 6:25 PM
Reply to this message Reply
As a small improvement (in my opinion), how about:


class Usage(Exception):
...


def CLI(argv):
"""
Command-line interface implementation.
"""

...
raise Usage, ...
return 0


def main():
try:
sys.exit(CLI(sys.argv))

except Usage, u:
...


if __name__ == '__main__':
main()



This way should you desire to 'script' this module in a shell-like way rather than calling it's interfaces, you can do so via a call to CLI(), catching Usage yourself. Rather than having your entire python instance fall over in an error condition, you now have the ability to catch errors in the usual manner.


David.

Todd Warner

Posts: 1
Nickname: taw
Registered: Jun, 2004

Re: Python main() functions Posted: Jun 4, 2004 3:04 PM
Reply to this message Reply
if __name__ == '__main__':
sys.exit(main(...) or 0)


That's my only contribution. I suppose we could merely enforce main() returns an int, but... anyway... this is my practice; make it for what it is worth.

Sridhar Ratna

Posts: 3
Nickname: srid
Registered: Jan, 2005

Re: Python main() functions Posted: Jan 9, 2005 9:30 PM
Reply to this message Reply
but contents of sys.argv may change

Lion Kimbro

Posts: 1
Nickname: lionkimbro
Registered: May, 2005

Re: Python main() functions Posted: May 26, 2005 4:58 PM
Reply to this message Reply
I had a hard time using this approach with optparse.

Something about this approach causes optparse to include the name of the program (foo.py) as the first argument. Normally, optparse just strips that out.

We don't want to have to call main(["dummy-value-to-fill-for-program-name", "arg1", "arg2", ...]); we just want to call main(["arg1", "arg2", ...]).

So, I'm afraid this approach isn't so friendly with optparse.

Allen Downey

Posts: 1
Nickname: abdowney
Registered: Aug, 2005

Re: Python main() functions Posted: Aug 31, 2005 1:58 PM
Reply to this message Reply
After all these suggestions, I am surprised that no one
has mentioned my favorite, which is to use Python's
optional argument mechanism to handle command-line arguments:

<pre>
def main(script, arg1='default1', arg2='default2', *args):
print script, arg1, arg2, args

if __name__ == '__main__':
main(*sys.argv)
</pre>

This work great as long as you only need to parse command-line arguments (no options).

Laurent Szyster

Posts: 4
Nickname: lavs
Registered: Aug, 2005

Re: Python main() functions Posted: Feb 13, 2008 6:43 AM
Reply to this message Reply
My favorite convention for writing main() can be found in anoption.py:

http://laurentszyster.be/blog/anoption/

>>> import anoption
>>> def main (
a, b, c,
d="", e=100, f=3.0, g=False,
*args, **kwargs
):
print a, b, c, d, e, f, g, args, kwargs

>>> anoption.cli (main, [
"A", "B", "--extended", "C", "D",
"-g=yes" "-f=12",
])
A B C D 100 12.0 True () {'extended': None}

>>> print anoption.doc (main)
a, b, c {-d="", -e=100, -f=3.0, -g=True, ...} [...]

Dag Henrik Fjær

Posts: 1
Nickname: nayru
Registered: Mar, 2008

Re: Python main() functions Posted: Mar 21, 2008 11:27 AM
Reply to this message Reply

def process_args():
parser = OptionParser("usage: %prog [options]")
parser.add_option("-p", help = "population size",
dest = "p", type = "int")
parser.add_option("-g", help = "number of generations",
dest = "g", type = "int")
parser.add_option("-c", help = "crossover rate (%)",
dest = "c", type = "int")
parser.add_option("-m", help = "mutation rate (%)",
dest = "m", type = "int")
parser.add_option("-f", help = "filename",
dest = "f", type = "string")
(opts, args) = parser.parse_args()
# Verify that that all the arguments have been provided
for n, m in opts.__dict__.iteritems():
if m == None:
print >>sys.stderr, "missing argument: -%c" % n
sys.exit(1)
return opts

Michael Jackson

Posts: 1
Nickname: majgis
Registered: Apr, 2009

Re: Python main() functions Posted: Apr 13, 2009 2:19 AM
Reply to this message Reply
I hope it isn't a faux pas to comment six years later, but I found this resource helpful and would like to make an addition:


"""Module docstring.

A long usage message.

"""

import sys

def main(*argv):

# code of choice; catch all exceptions and return exit status

if __name__ == "__main__":
sys.exit(main(*sys.argv))


Also, if you want to call main from the interactive Python prompt, and use optparse, keep in mind that the parse_args() method handles errors by exiting with error status 2. You would need to subclass OptionParser and override its exit() and/or error() methods to prevent the interpreter from exiting.

Henk Wiersema

Posts: 2
Nickname: hwiersema
Registered: Nov, 2009

Re: Python main() functions Posted: Nov 15, 2009 2:55 PM
Reply to this message Reply
I have gathered some templates here and there, and made a Python 3 template with a unix-style help and some example options. Just paste it in IDLE, and try.

"""Name
command - do something
Synopsys
command [-g file][-d] file ...
command --help

Description
command does something, dont know what.

Usage
To start doing something:
command file1 file2

Options
-g file
--grammar=file
define grammar file, defailt kant.xml
-h
--help
prints this use message
-d turns on debugging

Files
Yeah, we need files. More files.

"""

import sys
import getopt
import pprint
pp = pprint.PrettyPrinter(indent=4)

class Usage(Exception):
def __init__(self, msg):
self.msg = msg

# def main():
def main(argv=None):
if argv is None: argv = sys.argv

# parse command line options
try:
try:
# put the short and the long options in the same order
opts, args = getopt.getopt(argv[1:], "hg:dx", ["help" "grammar="])
except getopt.error as msg:
raise Usage(msg)

# define the defaults
g_grammar = "kant.xml"
g_debug=0
g_list_of_files=[]

# process options
for opt, arg in opts:
if opt in ("-h", "--help"):
print(__doc__)
return 0
elif opt == '-d':
g_debug = 1
elif opt in ("-g", "--grammar"):
g_grammar = arg
else:
# in case you defined an option with getopt,
# but forgot to write the handler here
raise Usage('option '+opt+' unhandled')

# process arguments
for arg in args:
g_list_of_files.append(arg)

print ('Starting program body with these arguments:')
print ('grammar='+g_grammar)
print ('debug='+str(g_debug))
print ('list_of_files='+pp.pformat(g_list_of_files))
# your code here, usually a procedure call
return 0

except Usage as err:
print(sys.argv[0].split('/')[-1].split('\\')[-1] + ': ' \
+ str(err.msg) \
, file=sys.stderr)
print ("for help use --help", file=sys.stderr)
return 2

if __name__ == "__main__":
sys.exit(main())

This template.py works fine on Windows.
To test it in IDLE with the options, use this:

>>> main(['dummy','-g','gram_file','-d','file1','file2'])
Starting program body with these arguments:
grammar=gram_file
debug=1
list_of_files=['file1', 'file2']
0
>>>


I have created an .exe using cx_Freeze (since py2exe isn't available for Python 3), and that worked fine too with all options.


Have fun!

Henk Wiersema

Posts: 2
Nickname: hwiersema
Registered: Nov, 2009

Re: Python main() functions Posted: Nov 15, 2009 3:06 PM
Reply to this message Reply
The same code, now well formatted.


"""Name
command - do something
Synopsys
command [-g file][-d] file ...
command --help

Description
command does something, dont know what.

Usage
To start doing something:
command file1 file2

Options
-g file
--grammar=file
define grammar file, defailt kant.xml
-h
--help
prints this use message
-d turns on debugging

Files
Yeah, we need files. More files.

"""

import sys
import getopt
import pprint
pp = pprint.PrettyPrinter(indent=4)

class Usage(Exception):
def __init__(self, msg):
self.msg = msg

# def main():
def main(argv=None):
if argv is None: argv = sys.argv

# parse command line options
try:
try:
# put the short and the long options in the same order
opts, args = getopt.getopt(argv[1:], "hg:dx", ["help" "grammar="])
except getopt.error as msg:
raise Usage(msg)

# define the defaults
g_grammar = "kant.xml"
g_debug=0
g_list_of_files=[]

# process options
for opt, arg in opts:
if opt in ("-h", "--help"):
print(__doc__)
return 0
elif opt == '-d':
g_debug = 1
elif opt in ("-g", "--grammar"):
g_grammar = arg
else:
# in case you defined an option with getopt,
# but forgot to write the handler here
raise Usage('option '+opt+' unhandled')

# process arguments
for arg in args:
g_list_of_files.append(arg)

print ('Starting program body with these arguments:')
print ('grammar='+g_grammar)
print ('debug='+str(g_debug))
print ('list_of_files='+pp.pformat(g_list_of_files))
# your code here, usually a procedure call
return 0

except Usage as err:
print(sys.argv[0].split('/')[-1].split('\\')[-1] + ': ' \
+ str(err.msg) \
, file=sys.stderr)
print ("for help use --help", file=sys.stderr)
return 2

if __name__ == "__main__":
sys.exit(main())



Sorry :-(

Karl Dickman

Posts: 1
Nickname: kdickman
Registered: Jan, 2010

Re: Python main() functions Posted: Jan 12, 2010 5:38 AM
Reply to this message Reply
A fellow on ActiveState came up with a decorator for main methods (http://code.activestate.com/recipes/499333/). Inspired by this, I came up with simplified decorator of my own:

def main_function(parse_arguments=None):
  if parse_arguments is None:
parse_arguments = lambda arguments: (None, arguments)
def main_decorator(to_decorate):
def decorated_main(arguments=None):
if arguments is None:
arguments = sys.argv
options, arguments = parse_arguments(arguments)
sys.exit(to_decorate(options, arguments))
return decorated_main
return main_decorator

I keep this in "miscellaneous.py" on my path. Then I import it, and I hardly have to tweak my scripts at all.

@main_function(parse_arguments)
def main(options, arguments):
pass

def parse_arguments(arguments):
option_parser = optparse.OptionParser()
option_parser.add_option("-s", "--spam")
return option_parser.parse_args(arguments[1:])

if __name__ == "__main__":
main()

Harry Newton

Posts: 1
Nickname: hazza
Registered: Jan, 2010

Re: Python main() functions Posted: Jan 12, 2010 8:11 AM
Reply to this message Reply
Suggestion for use with optparse rather than getopt

"""Module information.

Put something useful here.
"""


from __future__ import print_function

import sys
import optparse


class optopt(optparse.OptionParser):
"""Subclassed OptionParser, to prevent exiting from the interpreter when
called interactively."""

class optexit(Exception):
def __init__(self, msg, status):
self.msg = msg
self.status = status

def __str__(self):
return self.msg

def exit(self, status=0, msg=None):
"""Base class version with sys.exit() replaced by raise."""

if msg:
sys.stderr.write(msg)
raise self.optexit(msg, status)


def adjutant(a, b, c):
"""The starting point for code."""

print(a, b, c)

return 0


def main(argv=None):
"""Parse and check options, and then call adjutant()."""

if argv is None:
argv = sys.argv[1:]

try:
parser = optopt("%prog [options] arg")

parser.add_option("-f", "--file", dest="filename", help="read data from FILENAME")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose")
parser.add_option("-q", "--quiet", action="store_false", dest="verbose")

(options, args) = parser.parse_args(argv)

if len(args) != 1:
parser.error("incorrect number of arguments")
if options.verbose:
print("reading ... {0:s} ".format(options.filename))

return adjutant(1, 2, 3)

except optopt.optexit as e:
return e.status


if __name__ == "__main__":
sys.exit(main())
else:
sys.argv = [ "interpreter" ]

The parsing and checking of the arguments and options is carried out in main(), with control being passed subsequently to adjutant().

Anjum Naseer

Posts: 1
Nickname: mufasa
Registered: Feb, 2011

Re: Python main() functions Posted: Feb 6, 2011 2:53 PM
Reply to this message Reply
You may be interested in a little Python module I wrote to make handling of command line arguments even easier (open source and free to use) - http://freshmeat.net/projects/commando

skippy V

Posts: 1
Nickname: skippyv
Registered: Mar, 2012

Re: Python main() functions Posted: Mar 13, 2012 11:08 PM
Reply to this message Reply
Excuse my ignorance but how does one call the main() from the interpreter with multiple args. I placed this code in a module argTest.py and did this from the interpreter:
>>> from argTest import *
>>> main('-a *')
And also tried
>>> main(['-a','*'])
but couldn't get opts to parse the args correctly.
But if I just call python from the command line:
> python argTest.py -a *
It works fine.
What am I missing?
Regards

Flat View: This topic has 29 replies on 2 pages [ « | 1  2 ]
Topic: Down on the Upside Previous Topic   Next Topic Topic: A Test of Knowledge


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us