This week we'll look at ways to take user input on the command line and in the web environment. We'll also talk about import and see how to “catch” errors.

User Input

  • Last week I introduced the 'input()' function.
  • One important thing that I didn't mention is that it's important to prompt the user when you take input.
  • For example:
print ('First Name:')
first = input()
print ('Last Name:') 
last = input()
print (f'Welcome {first} {last}')

When the above code runs it looks like this:

$ python3.6 ./ 
First Name:
Last Name:
Welcome Mike Matera
  • The input() function takes an argument. The argument is a prompt.
  • When you give an argument to input() the prompt is drawn on the same line.

Here's an example of using input() with a prompt:

first = input('First Name: ')
last = input('Last Name: ')
print (f'Welcome {first} {last}')

Notice the change in the way the prompt works:

$ python3.6 ./ 
First Name: Mike
Last Name: Matera
Welcome Mike Matera

Exception Handling

  • Python uses exceptions like many modern programming languages.
  • When problems with your program cause Python to exit it's because of an unhandled exception
  • Exceptions can be handled with a try/except block

Here's an example of checking user input:

  a = float(input('Type a number: '))
  print (f"You entered {a}")
  print ("That's not a number!")
  • If the numerical conversion using float() causes an error control flows to the except: phrase
  • Notice that the contents of the try: and except: block are indented
  • Indentation is syntax in Python
    • The indentation is how code appears “inside” of a block
    • Indentation can have spaces or tabs, but not both
There is a lot more to know about exceptions, we will discuss them again in weeks 8 and 12.

Command Line Input

  • Programs can take input when they are started
  • Input from the command line is common for UNIX programs
    • It's sometimes more convenient than taking input interactively
    • It can be more secure

Here's an example of running a Python program with arguments:

import sys
program, arg1, arg2 = sys.argv
print (f'Hello, I am {program} and my arguments are "{arg1}" and "{arg2}"')

The program now requires two arguments. Here's and example of how to call the program:

$ python3.6 ./ Hello World
Hello, I am ./ and my arguments are "Hello" and "World"

If the wrong number of arguments is given the program encounters an error:

$ python3.6 ./ Hello
Traceback (most recent call last):
  File "./", line 3, in <module>
    program, arg1, arg2 = sys.argv 
ValueError: not enough values to unpack (expected 3, got 2)
  • The variable sys.argv is a Python list.
  • The syntax in the book unpacks the list in a way that's easy to see
  • The following two code snippets are identical:
program, arg1, arg2 = sys.argv

Is the same as:

program = sys.argv[0]
arg1 = sys.argv[1]
arg2 = sys.argv[2]

You can also use sys.argv directly in your code without creating a variable. For example:

print (f'Hello, I am {sys.argv[0]} and my arguments are "{sys.argv[1]}" and "{sys.argv[2]}"')

Using Environment Variables

  • Another way to pass input to a program is through the environment.
  • Environment variables are used on Windows, Mac and Linux
    • We'll see how to set them in Linux/Mac
  • Environment variables are frequently used to pass input to web applications
  • The environment is a dictionary in Python

Here's how to set and environment variable in the BASH shell:

$ export MY_NAME="Mike Matera"
$ export MY_JOB=Instructor 
  • Bash is a very difficult programming language, so the pay close attention to the following
    • There can *never* be a space between the name of the variable, the equal sign (=) and the value of the variable
    • When a value contains a space it needs to be in quotes ()
    • When a value doesn't contain a space no quote is necessary.
    • It's a tradition to make environment variables upper case (but not required)
  • Environment variables are accessible to Python.
import os
name = os.environ['MY_NAME']
job = os.environ['MY_JOB']
print (f"Hello, I'm {name} and I'm a {job}")

The following code prints:

$ export MY_NAME="Mike Matera"
$ export MY_JOB=Instructor 
$ python3.6 /tmp/ 
Hello, I'm Mike Matera and I'm a Instructor

The program will have an error if an environment variable is not set:

$ unset MY_JOB 
$ python3.6 /tmp/ 
Traceback (most recent call last):
  File "/tmp/", line 4, in <module>
    job = os.environ['MY_JOB']
  File "/usr/local/lib/python3.6/", line 669, in __getitem__
    raise KeyError(key) from None
KeyError: 'MY_JOB'

Debugging Flask

  • Flask has a debug mode that is very useful while you're developing.
  • Debug mode is accessed using an environment variable.
  • Run this command on your UNIX prompt to enable debugging:
export FLASK_DEBUG=1


  • Using the command line and the environment required us to use the import statement.
  • import does just what it says, it imports Python code into your program.
  • The import statement does two things
    • It looks for a module with the supplied name
    • If found, it binds the module to the current namespace
  • In programming a namespace is the place where variable and function names live.
    • The scope of a variable or function name is the namespace where it lives.

Consider the following example. Here the Python interpreter has just been started:

>>> os.environ['USER'] 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined

The problem with the code is that the os module has not been found. Now see what happens when os is imported:

>>> import os 
>>> os.environ['USER'] 
  • After the import the contents of the os namespace are bound to the name os
  • It's possible to change name that a namespace is bound to using import.

Here's an example of choosing the name for a namespace:

>>> import os as blahblah
>>> blahblah.environ['USER'] 
  • Notice that instead of os.environ it's now blahblah.environ
  • Changing the import name binding is useful when the library has a long name

Example of shortening a long import name:

import cloudstorage as gcs
  • When you import a module like os or sys all of the functions and variables in the module become available.
  • They are all accessible via the name binding
  • You can access imported names without a name binding if you ask for the name specifically
>>> from os import environ 
>>> environ['USER'] 
  • You've seen this from version of import before.
  • Flask programs use the from syntax

The from type is used to help readability:

from flask import Flask 
app = Flask(__name__)

This is also valid:

import flask
app = flask.Flask(__name__)
  • It's possible to import multiple names into the current namespace
  • This was from the template code last week:
from flask import Flask, render_template

Understanding HTTP

  • The Hypertext Transfer Protocol (HTTP) is how your browser communicates with the internet.
  • HTTP is a client/server protocol.
  • The client is the browser.
  • The server is software like Flask.
  • The client initiates all requests
  • The server responds to requests
    • The server never contacts the client directly.
  • In a typical HTTP session the client requests a resource from the server.

Suppose you have the following flask program:

from flask import Flask
app = Flask(__name__)
def hello() :
    return "The server says hello."
if __name__ == '__main__' :'', 5050)

When you direct your browser to your application the browser sends this request:

GET / HTTP/1.1
Host: localhost:5050
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36

Flask replies with a server response like this:

HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 22
Server: Werkzeug/0.14.1 Python/3.6.2
Date: Sun, 25 Feb 2018 22:32:57 GMT

The server says hello.

The most essential line in the request is:

GET / HTTP/1.1
  • That's the client telling the server what it wants.
  • What comes after the GET is the page part of the URL.
  • For example when your browser retrieved this page it asked for:
GET /cis-15/user_input HTTP/1.1
  • The server always sends back a response code.
    • You're probably familiar with the most famous one.
  • The response code tells the client what happened to the request

Here's a table of the most used response codes:

Code Meaning
200 OK - The response contains the page requested
301 Moved Permanently - The server wants to redirect you to a different page.
400 Bad Request
403 Forbidden
404 Page not found.
500 Server error

Flask Debugging Output

  • When your flask program is running, flask supplies information about every request.
  • The request and response information is written to the command line.

Here's an example of Flask's output: - - [25/Feb/2018 14:32:57] "GET / HTTP/1.1" 200 - - - [25/Feb/2018 14:32:57] "GET /favicon.ico HTTP/1.1" 404 - - - [25/Feb/2018 15:01:38] "GET /bogus HTTP/1.1" 404 -
  • The first line shows a successful request (200)
  • The second line shows the browser attempting to find an icon for the site (404)
  • The third request is for a bogus page (404)

HTML Forms

  • An HTML form is an HTML document that takes input from the user.
  • When the user presses “Submit” the form data is sent to the web server
  • Flask can handle form data
  • If you're new to HTML forms read this tutorial with examples

Here's an example of a simple form that could have been used for Project 3:

        <title>Simple Form</title>
        <form action="/result" method="post">
          Value for the variable a:<br>
          <input type="text" name="a_value"><br>
          Value for the variable b:<br>
          <input type="text" name="b_value"><br><br>
          <input type="submit" value="Submit">
  • Notice the following about the form:
    • It's action field is set to /result
      • The forms action will be directed to <the-form-url>/result
      • The application must have a route to this URL
    • The method is set to post.
      • Submitting this form will create an HTTP POST request.
    • The text inputs are named a_value and b_value. Those will appear in the Python program
    • The last input is the Submit button.

The form is handled by the following Python function:

@app.route('/result', methods=['POST'])
def do_table():
    a = float(request.form['a_value'])
    b = float(request.form['b_value'])
    data = []
    data.append(['a', a])
    data.append(['b', b])
    data.append([f'{a}+{b}', a+b])
    return render_template('basic_answer.html', table_data=data)
  • Notice the following.
    • The form field values are accessible by the variable request.form which is a dictionary
    • The @app.route decorator has an additional argument methods=['POST']
      • That allows the function to handle post data.
      • The form would be rejected otherwise.

You need a function to render the form. That's shown below:

@app.route('/', methods=['GET'])
def do_form():
    return render_template('basic_form.html')

The code simply renders the form template, which is not parameterizable.

HTML Form Security Warning

The forms in this section aren't secure. Secure forms should:

  1. Validate user input
  2. Contain a random number to prevent cross site request forgery (XSRF)

I will show you how to do forms securely in the coming weeks!

Routing GET Requests

  • POST forms are “hide” the information they contain inside the HTTP request.
  • GET request can use the URL to encode data.
  • For example to find the Reddit user foobar you can go to their URL
  • Flask can bind parts of a URL to function arguments

Here's a function that gets it's arguments from the URL

def do_table(a, b):
    data = []
    data.append(['a', a])
    data.append(['b', b])
    data.append([f'{a}+{b}', a+b])
    return render_template('basic_answer.html', table_data=data)
  • Taking input this way is recommended in situations where
    • You want browser bookmarks to work
    • You want the forward and back buttons on the browser to do the right thing