2.3 Calling main()
As the program stands now, it does nothing. It is
simply a bunch of functions. While they call each other, there is
nothing that instigates the execution process if the file is fed to the
Python interpreter. We need to call main().
As every Python program can also function as a module, it is necessary for us to ensure that main() is only executed if the program is called directly. Now that all the functions are defined, we can use an if statement to verify how the program is called and to launch main() accordingly.
if __name__ == '__main__':
main()
Calling main() as a result of this if
statement at the very end of the program is like not connecting the
power to an electric circuit until you are ready to test it. It helps us
to avoid lots of possible problems.
Now the program can be called at the command-line. You can either give it a shebang line at the top and ensure the file is set for execution, or call it as an argument to the Python interpreter:
python ./project-ch3.py -d world -u skipper -p secret
For reference, the full code of the program to follow is here. First, the shebang line and the imported modules:
#!/usr/bin/env python
import getpass, MySQLdb, optparse, string
Next, we define all supporting functions:
def valid_digit(value):
if value.isdigit() is not True:
value = query(value, "digit")
else:
value = value
return value
def valid_string(value):
if value.isalpha() is not True:
value = query(name, "alpha")
else:
value = value
return value
def query(value, type):
if type == "alpha":
print "The value you entered ('%s') is not correct. Please enter a valid value." %(value)
new_value = raw_input("New value: ")
valid_string(new_value)
return new_value
elif type == "digit":
print "The value you entered ('%s') is not correct. Please enter a valid value." %(value)
new_value = raw_input("New value: ")
valid_digit(new_value)
return new_value
else:
## if type != "alpha" and type != "digit":
return 1
def valid_table(choice, tables):
valid_choice = valid_digit(choice) # Check whether the choice is a valid number
valid_choice = int(valid_choice)
while (valid_choice <= 0) or (valid_choice > len(tables)): # Ensure the choice is among the valid options
print "Your selection is outside the bounds of possible choices."
valid_choice = query(valid_choice, "digit")
return valid_choice
We then need to define main(), the master function. First we parse the options and assign their values:
def main():
opt = optparse.OptionParser()
opt.add_option("-d", "--database", action="store", type="string", dest="database")
opt.add_option("-p", "--passwd", action="store", type="string", dest="passwd")
opt.add_option("-u", "--user", action="store", type="string", dest="user")
opt, args = opt.parse_args()
database = opt.database
passwd = opt.passwd
user = opt.user
Next, we validate the input, asking the user for clarification as necessary:
while (user == "") or (user == None):
print "This system is secured against anonymous logins."
user = getpass.getuser()
while (passwd == "") or (passwd == None):
print "You must have a valid password to log into the database."
passwd = getpass.getpass()
while (database == "") or (database == None):
database = raw_input("We need the name of an existing database to proceed. Please enter it here: ")
Then we try to connect to the database with the
credentials that the user passed to the program. If we fail, we print a
simple error message:
try:
mydb = MySQLdb.connect(host = 'localhost', user = user, passwd = passwd, db = database)
cur = mydb.cursor()
quit = 1
except:
print "The login credentials you entered are not valid for the database you indicated. Please check your login details and try again."
quit = 0
If we successfully make a connection, we carry on
showing the tables of the database and further interacting with the user
to form the INSERT statement:
if quit == 1:
get_tables_statement = """SHOW TABLES"""
cur.execute(get_tables_statement)
tables = cur.fetchall()
print "The tables available for database %s follow below:" %(database)
for i in xrange(0, len(tables)):
print "%s. %s" %(i+1, tables[i])
table_choice = input("Please enter the number of the table into which you would like to insert data. ")
table_choice = str(table_choice)
table_no = valid_table(table_choice, tables)
table = tables[table_no-1][0]
show_def = raw_input("Would you like to see the database structure of the table '%s'? (y/n) " %(table))
def_statement = """DESCRIBE %s""" %(table)
cur.execute(def_statement)
definition = cur.fetchall()
if show_def == "y":
from prettytable import PrettyTable
tabledef = PrettyTable()
tabledef.set_field_names(["Field", "Type", "Null", "Key", "Default", "Extra"])
for j in xrange(0, len(definition)):
tabledef.add_row([definition[j][0], definition[j][1], definition[j][2], definition[j][3], definition[j][4], definition[j][5]])
tabledef.printt()
print "Please enter the data you would like to insert into table %s" %(table)
columns = ''
values = '"'
for j in xrange(0, len(definition)):
column = definition[j][0]
value = raw_input("Value to insert for column '%s'?" %(definition[j][0]))
columns = columns + str(column)
values = values + str(value)
if j < len(definition)-1:
columns = columns + ", "
values = values + '", "'
else:
values = values + '"'
We then form the INSERT statement and execute it. It is always a good idea to give the user feedback about what data has just been processed:
statement = """INSERT INTO %s(%s) VALUES(%s)""" %(table, columns, values)
cur.execute(statement)
print "Data has been inserted using the following statement: \n", statement
The next bit of code is necessary only if you have
switched off auto-commit in MySQL for Python. Otherwise, you can skip
this part.
cur.close()
mydb.commit()
mydb.close()
Finally, we need to check whether the program has
been called directly. If the program is imported as a module into
another Python program, main() is never run.
if __name__ == '__main__':
main()
Room to grow
We have fulfilled the specification we set out for
this project. However, there are several points that you might consider
for further development:
Set the host name dynamically while validating the data. This will require you either to create a whitelist
of hosts or to do some network programming in order to validate the
existence not just of the host, but of a running MySQL server on it.
Validate the success of the INSERT statement by running a SELECT statement afterward. Ideally, you will need to close one connection and open another one to be sure that the data is there.
Validate the user's data more fully than we have here.
Abstract the database connection and/or the table selection to a function. See how small you can make main().