Posts Tagged ‘Python’

In Defense of Text-Based GTD Methods

September 20, 2017

Okay, so the title of this post is not fair to Robert Talbert, who talked about why he is going away from a text-based approach to Getting Things Done and went back to using ToDoist. However, this is a post I have been meaning to write for a week, and it fits in perfectly with what Talbert wrote.

Basically, Talbert wrote that he is moving away from a text-based approach to organizing his life (Todo.txt) and back to the ToDoist app. He explicitly said that this is a personal decision, and he is just reporting what works for him. I am going to describe a way that I solved one of the issues he describes in his post.

Background: I organize my word by having a plain text file on my work computer with all of the things I need to do (in part so that I can use with it, which I love). I do not use the Todo.txt method, and I think that I have probably evolved far enough away from Getting Things Done that I should not be referring to my process as GTD at all. However, I evolved from GTD, so there will still be a lot of overlap.

In addition to my text-based ToDo file, I use

  1. I ssh into my work computer to write down things I need to do if I am on a computer.
  2. A hipster PDA to capture ideas when I am away from a computer.
  3. I use a tickler file to capture items that I do not need to work on now.

Talbert’s main problem with Todo.txt involved syncing, and it sounds like a real problem. However, I never expected my hipster PDA to sync, so this is not an issue for me.

Talbert also mentioned that there is no easy way to do recurring tasks in Todo.txt. He talked about looking into cron jobs to take care of this for him, and he decided that he would rather have an app that just works (as Todoist does—you just click a button or two to make it the task keep reappearing regularly).

I opted for the cron job approach, which I explain below.

First, I will describe the old way. I have lists of recurring tasks I need to do every day. For instance, here is a list of tasks that I need to remind myself to do every Monday/Wednesday/Friday, the days that I teach (the details are not important, although it is worth telling you that I teach Math 124 and Math 343 this fall):

343:
Check Canvas for pre-class work at 10 am
Change Dailywork in Canvas
Update Actual Plan
Grade (Daily Homework for sure, maybe other things)0 1 * * 1,3,5 /usr/bin/python Dropbox/HodgePodge/MWFToDo.py

Look at next class’s materials

124:
Collect Daily HW in class, give to TA
Change Dailywork in Canvas
Update Actual Plan
Look at next class’s materials

These are things I need to think about every day I teach. The old way was to print out this list at the beginning of the semester, put it in my tickler for the next MWF, read it, type all of the above items into my text-based ToDo list, put the paper list back into the tickler file corresponding to the next MWF, and then delete the items as I do them.

It occurred to me, though, that I could just have the computer write these tasks to my text-based ToDo list. So I wrote a Python script (called MWFToDo.py) that does it and set a cron job to schedule the Python script (cron is a scheduler for Linux machines).

First, here is my cron job code. I just typed “crontab -e” in a command line and added the following line of code:

0 1 * * 1,3,5 /usr/bin/python Dropbox/HodgePodge/MWFToDo.py

The initial “0 1” means to do “0 minutes after 1 am.” Then next “* *” means do any day of the month (1–31) and any month of the year. The final “1,3,5” means do the first, third, and fifth days of the week (MWF). So “0 1 * * 1,3,5” just means “do something at 1 am every MWF.” What should be done is to run Python (located at /usr/bin/python) on the file at “Dropbox/HodgePodge/MWFToDo.py).

That is it—the computer now runs that Python script every Monday, Wednesday, and Friday. The Python script is below:

with open(“Dropbox/ToDo”, “r+”) as f:
old = f.read() # read everything in the file
f.seek(0) # rewind
f.write( “343:\nCheck Canvas for pre-class work at 10 am\nChange Dailywork in Canvas\nUpdate Actual Plan\nGrade (Daily Homework for sure, maybe other things)\nLook at next class’s materials\n\n124:\nCollect Daily HW in class, give to Joe\nChange Dailywork in Canvas\nUpdate Actual Plan\nLook at next class’s materials\n\n” + old) # write the new line before

Basically, this code (which I stole from someone—probably someone from Stack Overflow) just copies what was already in the ToDo file, prepends my new items for Math 124 and Math 343, and overwrites the old file with both the new information and the old (so it effectively just adds some stuff to the beginning).

This has worked well—my to-do list is ready for me immediately when I get to work, saving me a couple of minutes. In addition to MWFToDo.py, I also have TuesadyToDo.py, WednesdayToDo.py, FridayToDo.py, and MonthlyToDo.py, which all have their own cron job. Notice that both MWFToDo.py and WednesdayToDo.py both run on Wednesdays—to be safe, I just schedule the WednesdayToDo.py at a different time (12:30 am, which is

30 0 * * 1,3,5 /usr/bin/python Dropbox/HodgePodge/WednesdayToDo.py

in crontab, where “12 am” corresponds to the first 0).

I agree with Talbert that this is all personal preference. However, I like my system, I just did this a week before Talbert posted, and this seems to have a nice harmony with what Talbert wrote.

Advertisements

Reporting Grades in SBG

January 25, 2017

I mostly have liked the course management software I have used (Moodle and Canvas), but both are pretty terrible when it comes to keeping track of grades in an Standards-Based Grading system. I have mostly kept the my grades in a spreadsheet, which does all of the calculations that I want it to, but the students then do not have access to their grades. I tried using Canvas to report grades in Spring 2016 and Fall 2016, but Canvas will not do the calculations I need it to (I just posted the raw scores to Canvas, and I gave the students the logic to figure it out); I had to keep a separate spreadsheet to do everything I needed.

Neither of these made me happy, because I want my students to have access to their grades (if only to check for mistakes I have made), but I also want a single place to put my grades. My solution was inspired by Drew Lewis, who created a PERL script to send his students email updates of their grades directly off his spreadsheet. If I were more computer-savvy, this probably should have been an obvious solution, but I am very grateful that Drew pointed out what I could not recognize on my own.

I am more familiar with Python, so I wrote my own script (included below). Once I have the code written, I go to a command line (I use Linux), type “crontab -e” to edit my crontab, and type (without the quotation marks) “14 3 * * 2 /usr/bin/python 118-S17/Grades/118EmailGrades.py” to send an email at 3:14 am (the 14 3) every Tuesday morning (the “2” in “14 3 * * 2”). The “/usr/bin/python” says to run the program “python” and input the file “118-S17/Grades/118EmailGrades.py.”

Below is the code. It seems to work, but there is one issue that I am ironing out: I am only allowed to send five emails at a time when I tested it. I am pretty sure that this is a limitation on the server’s end, since I am sending the messages to only a couple of email addresses (all mine for the test runs). My (ugly) hack, which worked on Tuesday, is that I broke up my code so that each program only emails 5 students. I welcome troubleshooting ideas from those who know about this stuff, although I suspect that I could just try the single program and it would work, since I am not actually going to email to the same email address more than once for my class.

Here is the code. Note that indentation matters A LOT in Python, so be careful if you cut-and-paste.

import openpyxl
import smtplib
import email
import time

#This gets the spreadsheet the grades are in.
wb=openpyxl.load_workbook('Grades118S17.xlsx',data_only=True)

#Here I am getting each 'sheet' of the spreadsheet.
rosterSheet=wb.get_sheet_by_name('Roster')
summarySheet=wb.get_sheet_by_name('Summary')
quizSummarySheet=wb.get_sheet_by_name('QuizSummary')
quizLogicSheet=wb.get_sheet_by_name('QuizLogic')

#I put my password in my spreadsheet, since that is supposed to be more secret than this code is.  I put it in Cell AA1 of the "Roster" sheet, and this gets it out.
pw=rosterSheet['AA1'].value

#I am logging into my email server here.
smtpObj=smtplib.SMTP('exchange.csbsju.edu',587)
smtpObj.ehlo()
smtpObj.starttls()
smtpObj.login('bbenesh@csbsju.edu',pw)

#I want to put the date in the email, so I am getting it here.
todaysDate=str(time.strftime("%m/%d/%y"))

#The From email address and Subject of the email will be the same for every student; I put today's date in the Subject for the students' convenience.
fromVar="bbenesh@MYSCHOOL.edu"
subject="Math 118: Grade Update for "+todaysDate

#Put the last row you want to check prior to the +1  
NUMBEROFROWS=54+1

#Put the rows you do not want to check (because they are blank or because the student dropped) in the list below.
EXCEPTIONS=[28]


#I have to hardcode the range, and I skip rows 28 and 29 because they do not contain student data.
#The commented out for loop is just to test so that I am not flooded with emails.
for rowVar in range(2,NUMBEROFROWS):
	&nbsp#This just skips the blank rows that I hard-coded into the exceptions.	
	if rowVar in EXCEPTIONS:
		continue
	#This gets the student's first name and email, and I print the first name so that I can see who received an email (I get an email update once this program runs).
	firstName=rosterSheet.cell(row=rowVar, column=3).value
	print firstName
	toEmail=rosterSheet.cell(row=rowVar, column=4).value
	todaysGrade=summarySheet.cell(row=rowVar,column=2).value
	#I am going to put together the body of the message in several steps, storing it in the 'text' variable each time.  This is just the saluation of the email.
	text="Dear %s,\n\nBelow is your weekly grade update for %s.  If the semester ended today, you would receive a grade of %s.  Of course, I fully expect your grade to go up, since the semester is not yet over."   % (firstName,todaysDate,todaysGrade)
	
	#Here I am getting the summaries of their grade components and putting it in the text.		
	quizGrade=summarySheet.cell(row=rowVar,column=19).value
	gatewaysGrade=summarySheet.cell(row=rowVar,column=20).value
	teamProjectGrade=summarySheet.cell(row=rowVar,column=21).value
	individualProjectGrade=summarySheet.cell(row=rowVar,column=22).value
	SRLGrade=summarySheet.cell(row=rowVar,column=23).value
	text+="\n\nBelow are your current letter grades for each of the components of your semester grade.  Your grade is determined by the lowest of these, so you should focus on the component with the lowest grade; see the syllabus for more details.\n\nQuiz Grade: %s \nGateways Grade: %s\nTeam Project Grade: %s\nIndividual Project Grade: %s\nSelf-Regulated Learning Reflections Grade: %s\n\n" % (quizGrade,gatewaysGrade,teamProjectGrade,individualProjectGrade,SRLGrade)

	#Here I am giving them the next two things they should be studying to improve their grade; the logic in the spreadsheet figures this out.	
	firstMissingQuiz=quizLogicSheet.cell(row=rowVar,column=2).value	
	secondMissingQuiz=quizLogicSheet.cell(row=rowVar,column=3).value	
	text+="The two Learning Outcomes you should focus on next are %s and %s.  At the bottom of this email is a list of the number of times you have demonstrated each of the Learning Outcomes.  Please check this over to see that it is correct, and be sure to email me if you find a mistake.\n\nHave a great day!\nBret\n\n\n" % (firstMissingQuiz,secondMissingQuiz)

 	#Next, I am just going to loop over the raw data for each Standard and print it out at the end of the email.  This is so they can check to make sure that their records agree with mine.	
	#Put the number of the column corresponding to your last learning outcome prior to the +1
	NUMBEROFCOLUMNS=23+1
	#Again, I am hardcoding the column range for my spreadsheet.	
	for columnVar in range(2,NUMBEROFCOLUMNS):
		labelCode=quizSummarySheet.cell(row=1,column=columnVar).value	
		numberOfMarks=quizSummarySheet.cell(row=rowVar,column=columnVar).value	
		text+="%s:  %s\n" % (labelCode,numberOfMarks)	

        #Here I just format the final message, addding a subject header to my 'text' variable.  Then I send the email.	
	message='Subject: %s\n\n%s' % (subject,text)	
	smtpObj.sendmail(fromVar,toEmail,message)

#I log out of the email server.
smtpObj.quit()

APOS and Computer Programming in Mathematics Classes

March 4, 2011

My students had their first programming experience this week, and it went reasonably well. I perhaps gave too much background on programming, resulting in only a small amount of class time being devoted to have the students write code. In fact, here is an outline of the day:

  1. I showed them how to use codepad.org.
  2. I showed them if/elif/else statements in Python.
  3. I showed them for loops in Python.
  4. We created a program that would add two single-digit numbers in base six.

This took the entire class period, leaving the students almost no time to start writing a program that would add two four-digit numbers in base six.

Finishing that program was one of several ways students could get credit in the course. As I expected, some students decided to do the coding, although most did not.

I had been wondering about the worth of doing this in a class for elementary education courses. I am attempting to focus on why these algorithms work, whereas the programming seems to only help with understanding how to do the algorithms. I am still undecided for this class, although Ed Dubinsky and Robert Moses wrote an interesting article for this month’s AMS Notices (I also recommend reading Beckmann’s article and Wu’s article).

In short, Dubinsky and Moses write about APOS theory, which roughly (I am not an expert) says that students progress through several stages of understanding any sort of mathematical idea:

  1. Action: a student can do a particular mathematical “move,” but cannot really reflect on that move. For instance, a student could cube a given number.
  2. Procedure: a student can reflect on the action, and consider it abstractly. For instance, a student could imagine cubing a number without actually doing it. Now, for instance, a student might be able to think of how you one might attempt to find an inverse to cubing a number.
  3. Object: a student things of the former action/procedure as a “thing,” and realizes that he/she can act on it. For instance, the student could imagine taking f(x)=x^3, and transforming it by taking the derivative. The former action/process becomes more “tangible.”
  4. Schema: I am particularly hazy on this one, but it seems to me like a student is able to abstract the object and consider other actions and procedures that are related to it. My best guess is that the student might realize that f(x)=x^3 fits into a larger category called functions, and one can add/compose/differentiate this type of object.

To be sure, students do not progress through these four stages in a step-like manner; it is messier than that (it is sometimes useful to think of something as a Process, and other times it is useful to think of it as an Object). I would also welcome people to correct my inevitable misconceptions on APOS theory in the comments.

Anyway, Dubinsky and Moses wrote that computer programming can help students rapidly ascend through these four steps. Once the student has already internalized a mathematical idea into an Action, having the student write a computer program is a great help to turn that idea into a Process. Having the student code a different program that calls the first program turns that idea into an Object. “Going back and forth between object and process conceptualizations of a mathematical idea, so necessary in doing mathematics, resulted from this pedagogy almost effortlessly (Weller et al., 2003).”

This makes me think that requiring my elementary education students to code might be a good idea, since it would seem that they would definitely need to view addition, say, as a Process (rather than solely as an Action).

Comments on the programming project’s worth in my class an on APOS Theory in general are welcome.

Area professor introduces students to Python

February 25, 2011

After a couple of years of building up the courage to try, I finally attempted to incorporate computer programming in my mathematics classes. The reasons for doing so are two-fold:

  1. Computers are everywhere, and it seems like an educated person should have some experience in programming them.
  2. Programming is a fantastic tool for getting students to understand algorithms.

In particular, I am teaching elementary education majors this semester, and I am starting by having them code the standard addition algorithm for base six numbers. Here is how I set up the exercise:

  1. I reserved a classroom set of laptop computers for the day.
  2. I decided to use Python. This is because it is a useful language, the syntax is relatively minimal, and it is relatively easy to read.
  3. My students were to input numbers as lists; furthermore, I made the requirement that their program only work with four digit numbers. That is, 1234+45 would be inputted as [1,2,3,4]+[0,0,4,5]. These were both done to eliminate the coding that would not help them understand the algorithm better.
  4. I coded up a similar base six subtraction algorithm. I gave them a copy of my code to help them get started on the addition algorithm (the addition algorithm is substantially easier to code). (I also gave them a copy of a program that will take a sum of numbers of arbitrary length—not just four-digit numbers. I still, however, kept the inputs as lists).
  5. My school does not have a Python interpreter on its network, and I cannot request one until the summer (there are only two times per year that I can request software—before each semester). Instead, I decided to use Sage Online as my interpreter.

I explained this plan to my students, and they seemed game. However, there was a serious problem with using Sage Online. For some reason—perhaps because all of the computers were being funnelled through the same wireless router—one student could see everyone else’s worksheets on Sage, and no one else could see any worksheet.

At this point, I decided to delay the programming project until Monday. Then, I will attempt the same process, only using codepage instead of Sage Online.

Does anyone have a suggestion for how to improve this?