New employee orientation was awkward and horrible. Don’t feel bad. No -inator could have avoided that.
Doofenshmirtz barges into your office. “Since we hired these temps, the number of inator-related incidents has gone up dramatically!” He pulls a flip chart out of nowhere and starts pointing at pages. One is a graph with a big red line trending upward. The next is blue, trending downward. The next is a picture of a puppy.
“You get the idea” he says.
“I think part of the problem is that no one here knows which of these inators actually works anymore. Kevin got explodinated after he pulled the lever on the explodinator. To be fair, it does look a lot less dangerous than it is.”
“You’re a hip… computer person. Why don’t you whip up one of those fancy… oh… what’s it called… internet-inators. Yeah, make one of those web-inators, so the temps can enter some information about the rest of the inators we’ve got. One more accident and OSHA is going to send out their inspectors again. You know, it does seem a little weird that they don’t seem to have a problem with all the evildoing as long as everyone wears closed toed shoes.”
You then begin an unexpected long and thoughtful discourse with your new boss about whether or not overalls are coming back in style.
Your task is to develop a web application that can be used by Dr. Doofenshmirtz’s temporary employees to track the locations and conditions of his inators2. You are to do the following:
Refer to this assignment’s rubric for further description of point values for completed tasks.
The purpose of the web application is to allow Dr. Doofenshmirtz’s helpers to…
To make sure that only authorized employees are able to use the web application, it will require users to login to access most pages.
The web application (“the app”) will respond to the URL paths listed below.
If the app receives a request for a path that is not listed below, it should respond with an
HTTP 404 Not Found.
Fortunately, Flask will handle that part for you automatically!
If your app receives a request for an unknown path, Flask will respond with a
The following list describes how the app should respond to requests for each path.
Note that certain paths should be capable of handling multiple HTTP request methods (e.g.,
Further description of the request handlers and helper functions can be found in the documention.
ACTUALLY_WORKSinators at the top,
HOPELESSLY_BROKENinators at the bottom
name- a string
location- a string
condition- a dropdown menu with 5 options
description- a string
username- a string
password- a string
Refer to the documentation to discern how to handle errors.
When necessary, functions should raise errors using the
If you have questions about what should happen in specific cases or questions about assumptions you can make, ask your instructors for clarification.
You are going to need a virtual environment for this assignment.
# After you've cloned your starter code and changed into your project directory... $ virtualenv --python=$(which python3.5) env # Whenever you want to work on your project, you have to source env/bin/activate $ source ./env/bin/activate # You know you've activated your virtual environment if you see "(env)" in front # of your shell prompt! (env) $ # wow!
The above command will create a virtual environment configured to use Python 3.5.
All relevant files will be stored in a new subdirectory called
env which you should not track with git.
We don’t want to see any virtual environments in GitLab.
envas shown above.
.gitignorethat tells git to ignore the directory named
env/, so you won’t have to worry about accidentally committing it.
pytest.ini), so that it will ignore
env/as well. This prevents
pytestfrom exploring those packages for more and more unit tests to run.
Be sure to install the packages listed in
$ source env/bin/activate (env) $ pip install -r requirements.txt
For this assignment, your program will be a web application. It accepts two optional command line flags that allow the user to specify the host and port number that the server will bind to.
--host: Tells your Flask server which address it should use to listen for incoming HTTP requests.
127.0.0.1is your loopback address. You can only access it if you’re using the machine the server is running on.
0.0.0.0is the “anywhere and everywhere” address. This tells the server to listen to HTTP requests coming in through any network interface.
--port: Tells your Flask server which port number to use when listening on
5000is the default.
5000is probably fine. You won’t have permission to use low port numbers (less than 100), so don’t do that. Stick with numbers in the 5000 to 9000 range. If a port is taken, just pick another one.
# Assuming that we've activated our virtual environment, and we've # installed the packages from requirements.txt... # We can use --help to see how to use "flask run" (env) $ FLASK_APP=searchinator.py FLASK_DEBUG=1 flask run --help Usage: flask run [OPTIONS] Runs a local development server for the Flask application. ... Options: -h, --host TEXT The interface to bind to. -p, --port INTEGER The port to bind to. ...
We can start the application like so:
# Assuming that we've activated our virtual environment, and we've # installed the packages from requirements.txt... (env) $ FLASK_APP=searchinator.py FLASK_DEBUG=1 flask run --host=0.0.0.0 --port=5050 * Serving Flask app "searchinator" * Running on http://0.0.0.0:5050/ (Press CTRL+C to quit)
You can now interact with the web application by pointing a browser to
The value of
<hostname> depends on where you are running the server.
The value of
<portnum> is whatever you specified with the
--port=8034. In that case, your port will be
rc06ucs213.managed.mst.edu. Your hostname will be
--port=9255. In that case, your port will be
If you’re working with a campus machine, use one of the
Note the u in there.
If you’re using a campus machine to work on this assignment, there is a non-zero[^favorite] probability that someone else will be working on the same assignment on the same computer.
So, if you both try to bind to the same port number (let’s say port 8080), then one of you is going to see this message:
(env) $ FLASK_APP=searchinator.py FLASK_DEBUG=1 flask run --host=0.0.0.0 --port=5050 * Serving Flask app "searchinator" Traceback (most recent call last): Hooooooly trackeback, Batman. OSError: [Errno 48] Address already in use
In that case, just pick a different port number
# Assuming no one else has taken THIS port.... (env) $ FLASK_APP=searchinator.py FLASK_DEBUG=1 flask run --host=0.0.0.0 --port=5050 * Serving Flask app "searchinator" * Running on http://0.0.0.0:5051/ (Press CTRL+C to quit)
Be careful that you’re using the correct port number when you connect to it with your browser.
If you are going to edit code with PuTTy, then listen up. While the application is running, the PuTTy session you have opened will be busy. This means you will not be able to navigate to files or open them while your Flask app is running. The simple solution is to open up a second PuTTy session and connect to the same machine. The second PuTTy session will be where you do your work, and the first one will run your application.
/add/is not the same as
/add. Your app expects all paths to end with
The starter code includes a complete (enough) test suite. You are welcome to add additional tests, but the current test suite should cover all the bases. DO NOT modify the existing test suite without the advice of your instructor.
Note: passing the test suite does not guarantee that your code is correct. You should use them to help develop the project, but you need to pay careful attention to your implementation as well.
Make sure your app looks right, too. Check that your list is the right color, messages are flashing properly, etc.
This time around, you will be the one installing
You should use a
virtualenv to create an isolated environment to use with this project.
Note that the
requirements.txt file lists
pytest as a dependency.
If you use
requirements.txt to set up your virtualenv, then you’ll have the right version of
# Assuming that we've activated our virtualenv (called env in this # case) and we've installed the packages listed in requirements.txt (env) $ py.test
Note that you don’t need the
./ this time around.
Activating the virtualenv adds flake8 to your
PATH environment variable, which is nice.
requirement.txt specifies the expected version of
This is the exact version that we will use to grade your assignment.
A couple more notes:
pytest.ini. That file prevents
py.testfrom exploring your virtualenv for more tests to run. You only need to test your code. You don’t want to run all the unit tests for all the third-party libraries that were installed…
conftest.pythat you can look at.
pytestfixtures are neat.
py.test, you’re on your own to install
flake8 in your virtual environment.
# Assuming that we've activated our virtualenv (called env in this # case) and we've installed the packages listed in requirements.txt (env) $ flake8 *.py
Make sure that
flake8 has no output when you pass it your files.
All of the
.py files (including tests) should pass
If there are any messages (warnings, errors, etc), you should address them.
Also, do not suppress or exclude any of
requirements.txt file specifies the following version of
flake8, which is exactly what we will use to grade your assignment.
username, value: logged in user’s username).
Make sure your virtual environment is using Python 3.5. Otherwise, you may get weird results.
Be mindful of the order in which you apply decorators. The order is important.
You may find it easier to run the tests from one, specific test file. You can do that like so:
(env) $ pytest test/test_utils.py
Update your success/warning/error flash messages to match the messages expected by the unit tests. Do not update the unit tests to match your messages.
Do not modify the existing unit tests. You may add your own, but the instructor tests (mentioned in the rubric) will include the exact tests that came with the starter code. If you have questions about the current tests, email your instructor.
You are welcome to add your own unit tests!
Feel free to add more
test_*.py files to the
test directory to help you develop your web app.
Just make sure your code passes the provided tests AND your own.
Don’t waste a bunch of time copying docstrings this time. A brief, single-line docstring is sufficient this time around.
This assignment is worth 100 points. It will be graded according to the following rubric:
|Feature||Points Possible||Mostly or completely incorrect (0% of points possible)||Needs improvement (50% of points possible)||Adequate, but still some deficiencies (75% of points possible)||Mostly or completely correct (100% of points possible)|
|Student passes instructor tests||20||-20||-10||-5||0|
|Demonstrates understanding of Flask (request.form, abort, flash, redirect, session, etc.)||10||-10||-5||-3||0|
|Demonstrates understanding of decorators||20||-20||-10||-5||0|
|Demonstrates understanding of json module||5||-5||-3||-2||0|
|Demonstrates understanding of exception handling||5||-5||-3||-2||0|
|Demonstrates understanding of context managers and file IO||10||-10||-5||-3||0|
|Program runs without runtime/syntax errors||10||-10||–||–||0|
|flake8 outputs no suggestions for improvement for any “.py” file (no warnings, no errors, etc.)||10||-10||–||–||0|
|Code Review (sufficient comments, implementation looks Pythonic, etc.)||10||-10||-5||-3||0|
Each cell indicates how many points out of the available points will be awarded for that feature (row) and assessment level (column).
-- cannot be achieved.
Refer to the assignment submission page on the course website for details on submitting your code to GitLab.
When your assignment is graded, we will do the following (roughly).
# Set up and activate our own virtualenv $ virtualenv --python=$(which python3.5) env $ source env/bin/activate (env) $ pip install -r requirements.txt # Run flake8 and check for style issues. Note versions in the requirements.txt. (env) $ flake8 *.py test/*.py # Run unit tests. Also note versions in the requirements.txt. (env) $ py.test # Run your main file and check the output (env) $ FLASK_APP=searchinator.py FLASK_DEBUG=1 flask run # Then we're going to see if it works correctly.
Now that I’ve gotten into this virtual environment, how do I get out? Am I trapped here forever? Who’s going to take care of my dog?
When you log out, your virtual environment will go away. Each time you log in, you’ll have to reactivate it.
If you’d like to deactivate the virtual environment without logging out, use the
deactivate, you’ll notice your little
(env) indicator disappears.
You can always reactivate with
source env/bin/activate later.
Everyone is trying to use the same machine, so it’s slow, and I am feeling very salty and unpleasant about that.
First, write your congressman about funding issues.
Then consider using an SSH tunnel.
Basically, what we want to do is use Putty to create a tunnel3 that forwards your traffic to the Linux machine you’re using. This way, your browser can talk to a port on the local Windows computer you’re using, and PuTTY will forward that traffic to the remote Linux machine you’re coding on. If you haven’t realized already, SSH (and PuTTY, I guess) is an incredibly useful tool. You can do a lot more than just run a shell.
So here’s a quick-and-dirty tutorial:
xcsmachines work too!), but DON’T open a connection yet.
Source portenter your favorite port number. You’re going to run your Flask app on that port later, so pick a sturdy one.
<portnum>is the port number you chose in the previous step.
--hostoption, since we want the default (
--portoption. The port your app runs on must match the port number you chose above.
<portnum>is your chosen port number.
If you need to run your app on another port, you’ll have to start over and configure your tunnel differently.
Do users need to be logged in to view
Is it OK for the user to submit blank values for
If the user doesn’t enter a value for
description, that’s fine.
Those are allowed to be blank4.
There’s no need to do anything special if any of those fields are blank.
condition is blank5, we have a problem.
As the docs explain, we have to be able to construct a
condition.Condition object out of the value we receive.
The empty string can’t be converted to a
Condition, so we’ll
abort(400) for that.
It’s close, but it’s not quite what we need. ↩
An imaginary tunnel, tbh. ↩
Even though blank fields are not very useful for searchinating. ↩
Yes, they’re choosing a condition from a drop down. In reality, it’s not likely they’d send a blank form. Regardless, you still need to handle that case. ↩
I guess it’s not that amazing. We’re setting the bar pretty low for that comparison. ↩