Introduction
This page contains Python programs that can make your record keeping more efficient. It contains some recommendations on directory structure. You can read my screed on file system organization. It's aimed at students, but it applies to teachers, too.
Pro Tip Avoid spaces in file names. They make things messier and far less pleasant. It is easy to use camelNotation or snake_notation for file names with more than one word. Using the command-line to navigate your file system is very efficient, but spaces in file names introduce complexities you don't want to mess with. If the command line is new to you, the beginners menu offers resources to help you learn to use it.
When I taught at NCSSM, I made a directory (folder) for each
class. Inside this folder, I made a directory called students
and uses it to store a directory for each student.
In this folder, I would store student work, or other notes about a student
and the results of any program testing.
Using setUpClass.py
This program makes an empty folder for each name given it. Begin by creating a roster file.
Do not put spaces in the names. If your student is named
John Smith, use smithJohn
or smithJ
If
your school issues email addresses, use the email name, because it is
a unique identifier for each student. Use a plain-text editor to do this.
One name goes on each line as in this example. I usually name this file
roster.txt
keep it for whenever I need to see a roster.
Here is a very simple example.
robertsT bellamyD nixonR oconnorP
Now run the program setUpClass.py
while inside your
students
folder. When you list the contents of this folder,
you will see one empty folder for each student and your roster file.
You now have a place to save work for each student.
Using deal.py
Suppose you want to place the same file in each student's directory. This program will do that for you. If you are teaching programming and have a file of test cases to run against student programs, you can distribute that program to each student's folder to make running the tests easier. If you are teaching webdev and need to put a the same CSS file in each folder, this is a handy tool.
You specify a file you want "dealt" and a copy of that file is places in every folder in your current working directory. Nothing happens to regular files.
Using rt.py
This program tests Python functions to see if they are working correctly.
Most of the assignments in my classes were given in the form
of modules of functions, which the students implement. Pure functions
can be tested using this program rt.py
.
I wrote the original version and my student Chris Agrella improved upon it; this is what you see here.
When you specify an assignment, tell the students not to change the file name or the names of the functions. It is OK if they write helper functions in addition to those in the assignment.
Here is a typical assignment with method stubs.
def square(x):
"""precondition: x is a number
postcondition: returns the square of x."""
return 0
def circle_area(radius):
"""precondition: radius is the radius of a circle (number)
postcondition: returns the area of the circle"""
return 0
def get_even(numlist):
"""precondition: numlist is a list of integers
postcondition: returns a list with all even numbers from numlist."""
return []
def add(x,y):
"""precondition: x, y are numbers
postcondition: returns x + y"""
return 0
Here is the correctly completed assignment.
import math
def square(x):
"""precondition: x is a number
postcondition: returns the square of x."""
return x*x
def circle_area(radius):
"""precondition: radius is the radius of a circle (number)
postcondition: returns the area of the circle"""
return math.pi*radius*radius
def get_even(numlist):
"""precondition: numlist is a list of integers
postcondition: returns a list with all even numbers from numlist."""
return [k for k in numlist if k%2 == 0]
def add(x,y):
"""precondition: x, y are numbers
postcondition: returns x + y"""
return x + y
You will write something like this and deal it to each student's folder.
from sample import *
from rt import *
#Testing square. Enclose arguments in a list.
print("Testing function square for values -10, 0, 10")
run_test(square, 100, [10])
run_test(square, 100, [-10])
run_test(square, 0, [0])
run_test_float(circle_area, 314.1592653589793, [10])
run_test_float(circle_area, 78.53981633974483, [5])
run_test_float(circle_area, 0, [0])
run_test(get_even, [2,4,6,8], [[1,2,3,4,5,6,7,8,9]])
run_test(get_even, [2,4,6,8], [[1,2,5,4,9,6,7,8,9]])
run_test(add, 50, [19,31])
run_test(add, 0, [2,-2])
run_test_float(add, 1.75, [.875,.875])
This imports the student's code and the test code. If a floating-point
value is to be returned use run_test_float
; otherwise use
run_test
. This is in file test_sample.py
Now run it and you will see this. The symbol $ stands for your command-line prompt.
$ python test_sample.py Testing function square for values -10, 0, 10 PASS for case 10 (100) PASS for case -10 (100) PASS for case 0 (0) Testing circle_area for values 10, 5, 0 PASS for case 10 (314.1592653589793) PASS for case 5 (78.53981633974483) PASS for case 0 (0.0) Testing get_even for values [1,2,3,4,5,6,7,8,9] and [1,2,5,4,9,6,7,8,9] PASS for case [1, 2, 3, 4, 5, 6, 7, 8, 9] ([2, 4, 6, 8]) PASS for case [1, 2, 5, 4, 9, 6, 7, 8, 9] ([2, 4, 6, 8]) Testing add for values (19,31), (2,-2), and (.875, .875) PASS for case [19, 31] (50) PASS for case [2, -2] (0) PASS for case [0.875, 0.875] (1.75) $
Let's make some stuff fail so you can see that.
import math
def square(x):
"""precondition: x is a number
postcondition: returns the square of x."""
return x*x*x
def circle_area(radius):
"""precondition: radius is the radius of a circle (number)
postcondition: returns the area of the circle"""
return math.pi*radius*radius
def get_even(numlist):
"""precondition: numlist is a list of integers
postcondition: returns a list with all even numbers from numlist."""
return [k for k in numlist if k%2 == 1]
def add(x,y):
"""precondition: x, y are numbers
postcondition: returns x + y"""
return x * y
Now run and watch the vandalized cases fail.
Testing function square for values -10, 0, 10 FAIL because f(10) != 100. Failed Output: 1000 FAIL because f(-10) != 100. Failed Output: -1000 PASS for case 0 (0) Testing circle_area for values 10, 5, 0 PASS for case 10 (314.1592653589793) PASS for case 5 (78.53981633974483) PASS for case 0 (0.0) Testing get_even for values [1,2,3,4,5,6,7,8,9] and [1,2,5,4,9,6,7,8,9] FAIL because f([1, 2, 3, 4, 5, 6, 7, 8, 9]) != [2, 4, 6, 8]. Failed Output: [1, 3, 5, 7, 9] FAIL because f([1, 2, 5, 4, 9, 6, 7, 8, 9]) != [2, 4, 6, 8]. Failed Output: [1, 5, 9, 7, 9] Testing add for values (19,31), (2,-2), and (.875, .875) FAIL because f([19, 31]) != 50. Failed Output: 589 FAIL because f([2, -2]) != 0. Failed Output: -4 FAIL because f([0.875, 0.875]) != 1.75. Failed Output: 0.765625 $