Introduction
Program make_python_prog.py is a code generator that produces Python programs that parse command line arguments using Python 2.7's 'argparse' module.
The purpose of the program is to save typing. It is not a goal to handle all features of the 'argparse' module, but rather to produce code that runs, and, if desired, can be easily modified to take advantage of more advanced argparse features; and of course to modify the program to do whatever the programs is intended to do.
It is a goal to make the command-line input format for make_python_prog.py both simple and easy-to-remember. Thus additional argparse features, such a argument groups, and the 'choices' feature, and other argparse features are not added as these would complicate the command line input to the make_python_prog.py program. It is easier to modify the generated code to add these advanced argparse features.
Program make_python_prog.py runs under Python version 2.6 or 2.7 and produces programs that run under Python version 2.7. If the user copies the Python 2.7 distribution file argparse.py to the generated program folder, the generated program will run under Python version 2.6, and perhaps even earlier versions.
Both program make_python_prog.py and the generated code conform to Python coding standard PEP8. Python is unusual, because there are no special keywords or brackets to define scope, it is completely defined by indentation. This makes it easy to write code rapidly, but whitespace becomes a detriment because program structure is not seen as well if the program is broken up with whitespace.
Update: Nov. 10 2013
Program make_python_prog.py is still in the latest code drop. I added two other programs, make_python_2_prog.py and make_python_3_prog.py. These write Python code for before version 2.5 versions of Python, and Python version 3 respectively.
Before Python 2.5, the string.format
method did not exist, so program make_python_2_prog.py uses the old way to insert strings in strings. As long as a modified file argparse2.py is provided for versions of Python before Python 2.7, which has argparse.py built-in, then make_python_2_prog.py will write code that runs on Python 2.x, at least as far back as Python 2.2 (I think - I didn't test that far back). The old way to insert strings in strings works on all later versions of Python (I think even version 3.x?).
Unfortunately, the code generated by the make_python_2_prog.py program for earlier versions of Python cannot run the code in module argparse.py. There are instructions below for how to modify argparse.py to be used wiht that program.
Program make_python_3_prog.py is for Python version 3.0 and later versions of Python. Version 3 continues to support the string.format
method and has a new way to print. The old version 2 way to print no longer works. So where:
print "Hello"
worked for Python 2.x,
Python 3.x's print requires parenthesis because print
is now a built-in function.
print("Hello")
Program make_python_3_prog.py only runs on post 3.0 versions of Python and the generated code will only run on version 3.0 and later versions of Python. I did not test this at all (yet)! I just inspected the code. If anyone has issues, please report this in the message section below.
I am still running Python 2.7, and I use program make_python_prog.py, which supports the string.format
method. Until I go to the most recent version of Python, that will be my program of choice. I'm supplying the other code generators for those who are still running older versions and those who are up to the latest version.
By the way, most people I know who write Python are still using Python 2.6 or Python 2.7. Python 3.x is better syntactically and has better features, particularly built-in Unicode support, and it has been gaining ground for some time. However, there are lots of libraries, particularly third-party libraries, to the best of my knowledge, still don't work with Python 3.x.
Using program make_python_prog.py
This program generates python programs that parse command-line arguments and displays the parsed values. The purpose of this program is to save typing and allowing the rapid creation of python programs that can be modified for some intended purpose.
Arguments passed to this program specify the program name and the creation of generated program arguments, including the parameter names, also known as the variable names, parameter types, number of times a parameter may be entered, and whether a parameter is optional, and whether the parameter is entered or controlled by specifying a command-line switch.
A folder is created with the same name as the base name of the program name passed on the command line and the generated code is created in this folder.
Usage:
See further below for example command lines.
Command line format:
python make_python_prog.py <program name> <parameter text>
The formal specification for the program command line is in the form of:
Below <x> indicates x is required and [y] indicates that y is optional
python make_python_prog.py <program_name> [parameter 1] [parameter 2} ... [parameter N]
Each parameter is a comma delimited list of the form:
<variable_name[="initial_value"]>[,parameter_type][,parameter_count_token][,parameter_switch][,parameter_switch]
The parameter_type
, parameter_count_token
, and any parameter_switch
specifier can be in any order.
About variable_name
The variable name must always be the first item specified for each parameter. The variable name may only contain letters of the English alphabet or the underscore character. The initial_value
for a variable name should only be surrounded by double quote characters if the parameter type is a string, and even then the double quotes are only necessary if the inital_value
string contains whitespace.
The only valid default values for a Boolean parameter are False and True.
About parameter_type
The parameter_type
specifier can be one of the following characters. If no initial_value
is specified for each of these types, the indicated initial value default is used.
- s - A string parameter, defaults to the empty string, or ''.
- i - An integer parameter, defaults to 0.
- f - A floating point parameter, defaults to 0.0.
- b - A Boolean parameter, defaults to False.
If the parameter_type
is not specified, then the parameter_type
defaults to 's', which indicates a string argument.
About parameter_count_token
The optional count token controls the number of arguments that are accepted for specified argument type. If the number is more than one, then the variable specified by the given name will be a python list. This final optional count parameter is used as 'nargs
' in the argument parser code. The nargs
parameter would typically be one of the following:
- * - Accept 0 or more of the argument type.
- + - Accept 1 or more of the argument type.
- ? - The argument is optional.
- [A positive integer] - Accept the specified number of arguments, e.g. 2
If the parameter_count_token
is not specified, then at run-time, only one value is entered on the command line for that parameter. if the parameter_count_token
indicates multiple values, then variable_name
will identify a Python list instance, and each value entered will be added to the list by the parsing code.
About parameter_switch
An initial dash character indicates a parameter_switch
. A single dash character indicates a short, or single character, switch name. Two initial dash characters specify a long-name switch.
Both a short-name switch and a long-name switch can be specified.
The '-h' and '--help' switches are implemented automatically and should not be specified as switch parameters. Using either one of these help switches results in the __doc__
string at the start of the generated program being printed.
Additional information regarding Boolean parameters.
A Boolean parameter, with parameter_type
'b', is typically used as an optional switch parameter. Using the switch for a Boolean parameter in the generated program results in the variable name for the Boolean argument being set to the opposite of the initial_value
, which for the default for a Boolean parameter, changes the variable from False to True.
Example command lines:
python make_python_prog.py foo alpha,i beta,f,+ file_name gamma,-g,--gm,b
This command line generates a program named 'foo.py' that takes an integer parameter named 'alpha', and one or more floating point parameters that are in a list named 'beta', then a string parameter named file_name
, and finally an optional parameter named 'gamma' that is a Boolean value that is only 'True' if either the '-g' switch or the '--gm' switch are specified.
python make_python_prog.py foo file_name='foo.txt',?
The ? in this command line makes the file_name
parameter an optional parameter. If no argument is specified, then variable 'file_name
' is set to 'foo.txt'.
Program Structure
The 'main
' function near the end of the program starts argument processing. Main is called at the very end of the program.
For each command line parameter, the main functions uses an ArgInfo
class instance to store the variable name and attributes of the variable, including the type, default (initial) value, and other data relative to the variable. After the comma-delimited parameter data is parsed and stored in an ArgInfo
class instance, the instance is stored in a list, designated by variable name 'param_info_list
'.
The ArgInfo
class and methods can be seen here. The self.name
parameter stores the variable name. The rest should be obvious.
class ArgInfo
name_regex = re.compile('[A-Za-z_]*[0-9A-Za-z_]')
def __init__(self):
self.name = ''
self.default_value = ''
self.data_type = ''
self.count_token = ''
self.switch_name_list = []
def get_switch_name_list(self):
return self.switch_name_list
def set_switch_name_list(self, switch_name_list):
for switch_name in switch_name_list:
if switch_name.startswith('-'):
switch_name = switch_name[1:]
if switch_name.startswith('-'):
switch_name = switch_name[1:]
self.validate_name(switch_name)
self.switch_name_list = switch_name_list
def get_name(self):
return self.name
def set_name(self, name):
self.validate_name(name)
self.name = name
def get_default_value(self):
return self.default_value
def set_default_value(self, default_value):
self.default_value = default_value
def get_type(self):
return self.data_type
def set_type(self, type):
self.data_type = type
def get_count_token(self):
return self.count_token
def set_count_token(self, count):
self.count_token = count
def validate_name(self, name):
result = ArgInfo.name_regex.match(name)
if not result:
raise ValueError('Illegal name: {0}'.format(name))
After creating a folder to store the program files, the main function opens the new generated program file and calls the write_program
function, passing the file specifier, the base_program_name
, which for "foobar.py" would be "foobar
", and the list of ArgInfo
instances.
with open(program_name, 'w') as outfile:
write_program(outfile, base_program_name, param_info_list)
The write_program
function is very simple. First, the write_program_header
function is called. That function writes the boilerplate that starts every Python program and the program imports, including importing the ArgumentParser
class from module argparse.
Next, the 'write_primary_main_function
' function writes a function that takes a comma-delimited list of arguments and writes code to print each argument name and value.
Finally, the write_program_end
function writes the 'main
' function for the generated program, which contains the argument parsing code. The write_program_end
function is the most complicated function. It produces the lines of code necessary for the python argparse.ArgumentParser
instance to parse the command lines arguments. For each ArgInfo
instance in param_info_list
, separate lines are written for the argparse.ArgumentParser
instance.
def write_program(outfile, base_program_name, param_info_list):
""" Main function to write the python program. """
# Extract just the argument names to a list.
param_list = []
for param_info in param_info_list:
param_list.append(param_info.get_name())
write_program_header(outfile, base_program_name, param_list)
write_primary_main_function(outfile, base_program_name, param_list)
write_program_end(outfile, base_program_name, param_list, param_info_list)
If the program command line is:
python make_python_prog.py Enroll name age,i company="The Company",? height,f,-h,--height is_member,b,-m,--member
Then the variables 'name
', 'age
', 'company
', 'height
', and 'is_member
' are created by the write_program_end
function. The resulting 'main' function in the generated code is:
def main(argv=None):
# Initialize the command line parser.
parser = ArgumentParser(description='TODO: Text to display before the argument help.',
epilog='Copyright (c) 2013 TODO: your-name-here.',
add_help=True,
argument_default=None, # Global argument default
usage=__doc__)
parser.add_argument(action='store', dest='name', help='TODO:')
parser.add_argument(action='store', dest='age', type=int, help='TODO:')
parser.add_argument(action='store', dest='company', default=The Company, nargs='?', help='TODO:')
parser.add_argument('-h', '--height', action='store', dest='height', type=float, default=0.0, help='TODO:')
parser.add_argument('-m', '--member', action='store_true', dest='is_member', default=False, help='TODO:')
# Parse the command line.
arguments = parser.parse_args(args=argv)
name = arguments.name
age = arguments.age
company = arguments.company
height = arguments.height
is_member = arguments.is_member
status = 0
try:
Enroll_main(name, age, company, height, is_member)
except ValueError as value_error:
print value_error
status = -1
except EnvironmentError as environment_error:
print environment_error
status = -1
return status
This code will run as-is, but the user will want to search for the string 'TODO:' and replace that with meaningful text. For example, the help text for each line of code to add a variable to the parser should have help text added.
parser.add_argument(action='store', dest='name', help='TODO:')
Program make_python_prog.py source code
"""
This program generates python programs that parse command-line
arguments and displays the parsed values. The purpose of this
program is to save typing and allowing the rapid creation of
python programs that can be modified for some intended purpose.
Arguments passed to this program specify the program name and the
creation of generated program arguments, including the parameter
names, also known as the variable names, parameter types, number
of times a parameter may be entered, and whether a parameter is
optional, and whether the parameter is entered or controlled by
specifying a command-line switch.
Usage:
See further below for example command lines.
Command line format:
python make_python_prog.py <program name> <parameter text>
The formal specification for the program command line is in the form of:
Below <x> indicates x is required and [y] indicates that y is optional.
python make_python_prog.py <program_name> [parameter 1] [parameter 2} ... [parameter N]
Each parameter is a comma delimited list of the form:
<variable_name[="initial_value"]>[,parameter_type][,parameter_count_token][,parameter_switch][,parameter_switch]
The parameter_type, parameter_count_token, and any parameter_switch specifier
can be in any order.
About variable_name
The variable name must always be the first item specified for each
parameter. The variable name may only contain letters of the
English alphabet or the underscore character. The initial_value for
a variable name should only be surrounded by double quote characters
if the parameter type is a string, and even then the double quotes
are only necessary if the inital_value string contains whitespace.
The only valid default values for a Boolean parameter are False and True.
About parameter_type
The parameter_type specifier can be one of the following characters.
If no initial_value is specified for each of these types, the
indicated initital value default is used.
s - A string parameter, defaults to the empty string, or ''.
i - An integer parameter, defaults to 0.
f - A floating point parameter, defaults to 0.0.
b - A Boolean parameter, defaults to False.
If the parameter_type is not specified, then the parameter_type defaults
to 's', which indicates a string argument.
About parameter_count_token
The optional count token controls the number of arguments that
are accepted for specified argument type. If the number is more
than one, then the variable specified by the given name will be a
python list. This final optional count parameter is used as 'nargs'
in the argument parser code. The nargs parameter would typically
be one of the following:
* - Accept 0 or more of the argument type.
+ - Accept 1 or more of the argument type.
? - The argument is optional.
[A positive integer] - Accept the specified number
of arguments, e.g. 2
If the parameter_count_token is not specified, then at runtime, only
one value is entered on the command line for that parameter. if the
parameter_count_token indicates multiple values, then variable_name
will identify a Python list instance, and each value entered will
be added to the list by the parsing code.
About parameter_switch
An initial dash character indicate a parameter_switch. A single
dash character indicates a short, or single character, switch name.
Two initial dash characters specify a long-name switch.
Both a short-name switch and a long-name switch can be specified.
The '-h' and '--help' switches are implemented automatically and
should not be specified as switch parameters. Using either one of
these help switches results in the __doc__ string at the start of
the generated program being printed.
Additional information regarding Boolean parameters.
A Boolean parameter, with parameter_type 'b', is typically used as
an optional switch parameter. Using the switch for a Boolean
parameter in the generated program results in the variable name for
the Boolean argument being set to the opposite of the initial_value,
which for the default for a Boolean parameter, changes the variable
from False to True.
Example command lines:
python make_python_prog.py foo alpha,i beta,f,+ file_name gamma,-g,--gm,b
This command line generates a program named 'foo.py' that takes
an integer parameter named 'alpha', and one or more floating point
parameters that are in a list named 'beta', then a string parameter
named file_name, and finally an optional parameter named 'gamma'
that is a Boolean value that is only 'True' if either the '-g'
switch or the '--gm' switch are specified.
python make_python_prog.py foo file_name='foo.txt',?
The ? in this command line makes the file_name parameter an optional
parameter. If no argument is specified, then variable 'file_name'
is set to 'foo.txt'.
"""
import sys
import os
import re
import time
import keyword
class ArgInfo
name_regex = re.compile('[A-Za-z_]*[0-9A-Za-z_]')
def __init__(self):
self.name = ''
self.default_value = ''
self.data_type = ''
self.count_token = ''
self.switch_name_list = []
def get_switch_name_list(self):
return self.switch_name_list
def set_switch_name_list(self, switch_name_list):
for switch_name in switch_name_list:
if switch_name.startswith('-'):
switch_name = switch_name[1:]
if switch_name.startswith('-'):
switch_name = switch_name[1:]
self.validate_name(switch_name)
self.switch_name_list = switch_name_list
def get_name(self):
return self.name
def set_name(self, name):
self.validate_name(name)
self.name = name
def get_default_value(self):
return self.default_value
def set_default_value(self, default_value):
self.default_value = default_value
def get_type(self):
return self.data_type
def set_type(self, type):
self.data_type = type
def get_count_token(self):
return self.count_token
def set_count_token(self, count):
self.count_token = count
def validate_name(self, name):
result = ArgInfo.name_regex.match(name)
if not result:
raise ValueError('Illegal name: {0}'.format(name))
def validate_no_duplicate_switches(arg_info_list)
switch_list = []
for arg_info in arg_info_list:
for switch_name in arg_info.get_switch_name_list():
if switch_name in switch_list:
raise ValueError('Duplicate switch name {0}.'.format(switch_name))
switch_list.append(switch_name)
def is_integer(s)
try:
x = int(s)
is_int = True
except ValueError:
is_int = False
return is_int
def is_floating_point(s)
try:
x = float(s)
is_float = True
except ValueError:
is_float = False
return is_float
def write_program_header(outfile, base_program_name, param_list)
outfile.write('#!/usr/bin/env python\n')
outfile.write('"""\n')
outfile.write(' python {0}.py\n\n'.format(base_program_name))
outfile.write(' TODO: Add usage information here.\n')
outfile.write('"""\n')
outfile.write('import sys\n')
outfile.write('# TODO: Uncomment or add imports here.\n')
outfile.write('#import os\n')
outfile.write('#import re\n')
outfile.write('#import time\n')
outfile.write('#import subprocess\n')
if param_list != None and len(param_list) > 0:
outfile.write('from argparse import ArgumentParser\n')
outfile.write('\n')
return
def get_function_call_string(function_name, param_list)
function_call = '{0}('.format(function_name)
number_of_params = len(param_list)
for i in xrange(0, number_of_params):
function_call = '{0}{1}'.format(function_call, param_list[i])
if i != (number_of_params - 1):
function_call = '{0}, '.format(function_call)
function_call = '{0})'.format(function_call)
return function_call
def write_function_start(outfile, function_name, param_list)
if function_name == 'main':
outfile.write('# Start of main program.\n')
function_call = get_function_call_string(function_name, param_list)
function_declaration = 'def {0}:\n'.format(function_call)
outfile.write(function_declaration)
if function_name != 'main':
outfile.write(' """ TODO: Add docstring here. """\n')
return
def write_primary_main_function(outfile, base_program_name, param_list)
function_name = '{0}_main'.format(base_program_name)
write_function_start(outfile, function_name, param_list)
outfile.write(' # TODO: Add or delete code here.\n')
outfile.write(' # Dump all passed argument values.\n')
for param in param_list:
outfile.write(" print '{0} = {1}0{2}'.format(repr({3}))\n".format(param, '{', '}', param))
outfile.write(' return 0\n\n')
return
def get_year()
now = time.ctime()
now_list = now.split()
year = now_list[4]
return year
def get_default_value_for_type(arg_type)
arg_default_value_dict = {'string' : "''", 'boolean' : 'False', 'int' : '0', 'float' : '0.0'}
return arg_default_value_dict[arg_type]
def write_argument_parsing_code(outfile, param_info_list)
if len(param_info_list) > 0:
outfile.write(' # Initialize the command line parser.\n')
outfile.write(" parser = ArgumentParser(description='TODO: Text to display before the argument help.',\n")
outfile.write(" epilog='Copyright (c) {0} TODO: your-name-here - All Rights Reserved.',\n".format(get_year()))
outfile.write(" add_help=True,\n")
outfile.write(" argument_default=None, # Global argument default\n")
outfile.write(" usage=__doc__)\n")
for param_info in param_info_list:
switch_name_list = param_info.get_switch_name_list()
arg_name = param_info.get_name()
arg_default_value = param_info.get_default_value()
arg_type = param_info.get_type()
arg_count = param_info.get_count_token()
argument_string = ' parser.add_argument('
if len(switch_name_list) > 0:
switches_string = repr(switch_name_list)
switches_string = switches_string.replace('[', '')
switches_string = switches_string.replace(']', '')
argument_string = "{0}{1},".format(argument_string, switches_string)
if not argument_string.endswith('('):
argument_string = "{0} ".format(argument_string)
if arg_type == 'boolean':
if not arg_default_value or arg_default_value == 'False':
argument_string = "{0}action='store_true',".format(argument_string)
elif arg_default_value == 'True':
argument_string = "{0}action='store_false',".format(argument_string)
else:
argument_string = "{0}action='store',".format(argument_string)
argument_string = "{0} dest='{1}',".format(argument_string, arg_name)
if arg_type == 'int':
argument_string = "{0} type=int,".format(argument_string)
elif arg_type == 'float':
argument_string = "{0} type=float,".format(argument_string)
elif arg_type != 'boolean':
arg_type = 'string'
if len(switch_name_list) > 1 or arg_count == '?':
if not arg_default_value:
arg_default_value = get_default_value_for_type(arg_type)
argument_string = '{0} default={1},'.format(argument_string, arg_default_value)
elif arg_default_value:
print "'{0}' is a required parameter. Default argument value '{1}' ignored".format(arg_name, arg_default_value)
print "Use parameter_count_token '?' to change to a non-required parameter."
if arg_count and arg_count in '*+?':
argument_string = "{0} nargs='{1}',".format(argument_string, arg_count)
elif is_integer(arg_count):
argument_string = "{0} nargs={1},".format(argument_string, int(arg_count))
argument_string = "{0} help='TODO:')\n".format(argument_string)
outfile.write(argument_string)
outfile.write(' # Parse the command line.\n')
outfile.write(' arguments = parser.parse_args(args=argv)\n')
for param_info in param_info_list:
arg_name = param_info.get_name()
outfile.write(" {0} = arguments.{1}\n".format(arg_name, arg_name))
return
def write_program_end(outfile, base_program_name, param_list, param_info_list)
write_function_start(outfile, 'main', ['argv=None'])
if param_list != None and len(param_list) > 0:
write_argument_parsing_code(outfile, param_info_list)
function_name = '{0}_main'.format(base_program_name)
function_call = get_function_call_string(function_name, param_list)
outfile.write(' status = 0\n')
outfile.write(' try:\n')
function_call = ' {0}\n'.format(function_call)
outfile.write(function_call)
outfile.write(' except ValueError as value_error:\n')
outfile.write(' print value_error\n')
outfile.write(' status = -1\n')
outfile.write(' except EnvironmentError as environment_error:\n')
outfile.write(' print environment_error\n')
outfile.write(' status = -1\n')
outfile.write(' return status\n\n')
outfile.write('if __name__ == "__main__":\n')
outfile.write(' sys.exit(main())\n')
return
def write_program(outfile, base_program_name, param_info_list)
param_list = []
for param_info in param_info_list:
param_list.append(param_info.get_name())
write_program_header(outfile, base_program_name, param_list)
write_execute_function(outfile, base_program_name, param_list)
write_program_end(outfile, base_program_name, param_list, param_info_list)
def file_exists(file_name)
exists = True
try:
with open(file_name) as f:
pass
except IOError as io_error:
exists = False
return exists
def validate_arg_default_value(arg_type, arg_default_value, argument)
if not arg_type or arg_type == 'string':
if arg_default_value:
if not arg_default_value.startswith("'") or not arg_default_value.endswith("'"):
arg_default_value = repr(arg_default_value)
elif arg_type == 'boolean':
if arg_default_value:
if arg_default_value != 'False' and arg_default_value != 'True':
raise ValueError("Boolean default value {0} in {1} must be either 'False' or 'True'".format(arg_default_value, argument))
elif arg_type == 'int':
if arg_default_value and not is_integer(arg_default_value):
raise ValueError('Integer default value {0} in {1} is not a valid number.'.format(arg_default_value, argument))
else:
if arg_default_value and not is_floating_point(arg_default_value):
raise ValueError('Floating point default value {0} in {1} is not a valid floating point number.'.format(arg_default_value, argument))
return
def validate_variable_name(arg_name, unique_name_list)
if keyword.iskeyword(arg_name):
raise ValueError('Variable name "{0}" is a python keyword.'.format(arg_name))
if arg_name in unique_name_list:
raise ValueError('Variable name "{0}" was already specified.'.format(arg_name))
unique_name_list.append(arg_name)
def create_folder_under_current_directory(folder_name):
current_path = os.getcwd()
new_path = os.path.join(current_path, folder_name)
if not os.path.exists(folder_name):
os.makedirs(folder_name)
return new_path
def main(argv=None):
if argv == None:
argv = sys.argv
status = 0
if len(argv) < 2:
print 'Program: make_python_prog.py\nUse -h or --help for more information.'
return status
base_program_name = argv[1]
if base_program_name == '-h' or base_program_name == '--help':
print __doc__
return status
program_name = base_program_name
if base_program_name.endswith('.py'):
base_program_name = base_program_name[:-3]
param_info = ArgInfo()
try:
param_info.validate_name(base_program_name)
program_name = '{0}.py'.format(base_program_name)
lower_case_program_name = program_name.lower()
if lower_case_program_name == 'make_python_prog.py':
raise ValueError('The generated program name cannot be the same name as this program.')
arg_type_dict = {'s' : 'string', 'b' : 'boolean', 'i' : 'int', 'f' : 'float'}
unique_name_list = []
param_info_list = []
for i in xrange(2, len(argv)):
argument = argv[i].strip()
arg_item_list = argument.split(',')
param_info = ArgInfo()
arg_name = arg_item_list.pop(0)
arg_default_value = ''
arg_name_list = arg_name.split('=')
if len(arg_name_list) > 1:
arg_name = arg_name_list[0]
arg_default_value = arg_name_list[1]
arg_switch_list = []
arg_count_token = ''
arg_type = ''
for arg_item in arg_item_list:
if arg_item.startswith('-'):
arg_switch_list.append(arg_item)
continue
elif (len(arg_item) == 1 and arg_item in '*+?') or is_integer(arg_item):
if arg_count_token:
raise ValueError(
'Argument count token {1} in {0} is a duplicate count token.'.format(arg_item, argument))
arg_count_token = arg_item
continue
elif (len(arg_item) == 1 and arg_item in 'sbif'):
if arg_type:
raise ValueError('Argument type {1} in {0} is a duplicate type.'.format(arg_item, argument))
arg_type = arg_type_dict.get(arg_item)
continue
raise ValueError('Parameter {0} contains invalid setting {1}.'.format(argument, arg_item))
validate_arg_default_value(arg_type, arg_default_value, argument)
validate_variable_name(arg_name, unique_name_list)
param_info.set_name(arg_name)
param_info.set_default_value(arg_default_value)
param_info.set_switch_name_list(arg_switch_list)
param_info.set_count_token(arg_count_token)
param_info.set_type(arg_type)
param_info_list.append(param_info)
validate_no_duplicate_switches(param_info_list)
if file_exists(program_name):
print "File '{0}' already exists. Enter 'y' or 'Y' to overwrite the file. >".format(program_name),
c = raw_input()
if c != 'y' and c != 'Y':
return status
new_path = create_folder_under_current_directory(base_program_name)
os.chdir(new_path)
with open(program_name, 'w') as outfile:
write_program(outfile, base_program_name, param_info_list)
print 'Created program {0}'.format(program_name)
except EnvironmentError as environment_error:
print environment_error
status = -1
except ValueError as value_error:
print value_error
status = -1
return status
if __name__ == "__main__":
sys.exit(main())
argparse for program make_python_2_prog.py
Programs generated by the make_python_2_prog.py program, which is for very early versions of Python prior to version 2.4 (2.5?) require a modified argparse.py file. Here are the steps to modify the file so that it will work on earlier versions of Python.
- Download file argparse.py. Rename it to be named argparse2.py.
- Copy argparse2.py to the generated program folder.
- When you try to run the program, you will get two errors in file argparse2.py that will be easy to fix.
Specifically, change line 1131 in file argparse.py
except IOError as e:
to:
except IOError, e:
and change line 1595 from:
default_prefix = '-' if '-' in prefix_chars else prefix_chars[0]
to:
default_prefix = '-'
if '-' not in prefix_chars:
default_prefix = prefix_chars[0]
Copy the new file argparse2.py to the folder that contains the generated program, and then the program will run.
Points of Interest
Even if you don't want to use the argparse module to parse arguments, perhaps because your running an early version of Python that does not include the argparse module, and you don't want to locate and download file argparse.py, this program still saves typing as it writes most of the boilerplate necessary for a good Python program.
Both program make_python_prog.py and the generated code conform to Python PEP8. Python is unusual, because there are no special keywords or brackets to define scope, it is completely defined by indentation. This makes it easy to write code rapidly, but white-space becomes a detriment because program structure is not seen as well if the program text is broken up with white-space.
History
- First posting.
- Fixed the final paragraph under "Points of Interest" about whitespace. The text ended with "if the program is broken" instead of "if the program text is broken up with white-space".
- Removed the words "All Rights Reserved" in the copyright notice in the generated code. Updated the zip file and the code text in the article.
- In addition to program make_python_prog.py, now two other versions, make_python_2_prog.py and make_python_3_prog.py are supplied.
- Renamed the "write_execute_function" function to be named "write_primary_main_function".
Renamed the generated function name from "execute_<somename>" to "<somename>_main".