We can has /properly formatted/ code in COMMENTS!

Hi folks!

Just enabled “Jetpack”… Jetpack Comment… and MARKDOWN on this blog.

WHAT THIS MEANS FOR YOU

You can now enter properly formatted code in comments! YES!

Or at least I’m led to believe this, heh. I shall try this as replies to this post.

HERE’S HOW:

  1. Enter three backticks ( ``` ) BEFORE and AFTER your code block, OR
  2. Wrap your code block with the HTML tags <pre> and </pre>

That should do it! Please do check out the replies to this post.

Scraping calendar data

This post to be a log of a different project.  I have an application that wants an “iCalendar” data feed ala RFC 2445.

The data I want to render into this format is found on my town’s government website, which is built on top of the Virtual Town Halls product. (http://www.vt-s.net/)

Here’s an example: Arlington, MA.

I am going to attempt to use Beautiful Soup to deal with the page…. and see what I can do!

 

Let’s build an action tracker

No python today, but a wish…

Many years ago, I worked at Digital with a PHENOMENAL team. Truly, one of those “peak work experiences”.

One of the cool things we had (this was the early 90’s) was a projector hooked up to the terminal in the conference room, and we would “work on the walls” during our group meeting.

A memory I carry with me to this day was our action tracker, just as simple thing, which was built on top of a simple database table with a spreadsheet-type interface (VAX Teamdata) in which we could capture our action items.

Basically a one-liner with info such as:

  • date created
  • DRI (“designated responsible individual”)
  • what to be done – deliverable is implicit in clear description
  • by when (date)
  • status – e.g. open, blocked, waiting, on-hold, done, cancelled
  • wait, here’s an update to status:
    • defined (initial state)
    • in-progress
    • complete
    • waiting (typically on someone else, use comments)
    • deferred (or withdrawn)
    • withdrawn
    • BLOCKED
  • requestor — who’s asking for the work, or the primary beneficiary, who can be consulted about the action
  • outcome

A quick recap after a few days thinking about this:

  • ID (#)
  • WHO
  • DUE (date in form of END BY this date)
  • STATUS (see above)
  • WHAT (meat of the request)
  • FOR (who)
  • CLOSED (date)
  • RESULTS (or COMMENTS)

One fancy enhancement that comes to mind is also a field for:

  • notes – comment(s) about status and/or progress    What’d be cool here is for this to be a timestamped log or audit of the action item.

I miss this simplicity, and in my new job, I need to have something that can quickly create and update such a record/records.  Getting way too swamped with action items and missed promises.

SO!  How about we create this in Python?

Right – and I want it accessible over the web.

Keyboard input with timeout in Python

From StackOverflow: http://stackoverflow.com/questions/1335507/keyboard-input-with-timeout-in-python

This seems to be something folks want to do.  I recently had an interest to launch a script every morning to have me check in with some goal, and was wondering how I could do this, i.e.

At 7:00 AM, fire up a script with some prompt and input request, something like:

raw_input("Time to log the daily weight-in! How much today? ")

But… suppose I slept in today.  The prompt just sits there, blocking… and suppose the script that launches this inquiry now fires up a new instance of the program… will that prompt and wait, too?  Ugh.

Better to have something that operates like “oh look, there’s been no answer for the past 30 minutes, maybe he forgot or slept in?” and then concludes “okay, log that there was no answer for today, and exit.”  Simple, and no more stacked up instances.

Problem is, there’s apparently no read with timeout in Python. Or at least, not one that works, cross-platform.  (There are some solutions with Linux signals.)

I found the following code at the above StackOverflow post mentioned above.  It was downvoted, but I actually found this approach interesting, a kind of “out of the box” thinking approach to the problem.  Here, a timer is set up.  And what you do is indicate, via Ctrl-C, when you’re at the keyboard and ready to begin input.  If the interrupt is never received?  Then it’s a timeout.

Sure, it’s a little quirky, but it can get a job done.

Two things I discovered or realized:

  1. Of course, if you do start typing, and then walk away, it will block just like the original case.
  2. I tried changing the sleep loop to just a single sleep statement.  But guess what — my Ctrl-C would not interrupt the sleep statement! (I”m on a Mac, fyi.)  If you have a loop around the sleep, it can detect the interrupt in-between the sleep statement.
    (I suppose I should head to the documentation to read up on this and verify my theory.)
  3. If you press Ctrl-C, you may have a perceptible momentary wait, while the “sleep(1)” completes.

P.S. Here is the exact code by “try” from the StackOverflow post.

from time import sleep

print('Please provide input in 20 seconds! (Hit Ctrl-C to start)')
try:
    for i in range(0,20):
        sleep(1) # could use a backward counter to be preeety :)
    print('No input is given.')
except KeyboardInterrupt:
    raw_input('Input x:')
    print('You, you! You know something.')

Here’s my slightly modified version, as a function (to make it easier to test in IDLE).

And sorry for the wrapping… i’m looking for a new template for the blog.


def prompt_with_timeout():
  from time import sleep

  print('Waiting... please press Ctrl-C when you wish to proceed.')
  try:
    for i in range(0, 30*60): # 30 minutes is 30*60 seconds
      sleep(1)
    print("Oops, sorry, no input was received today. Come back tomorrow.")
  except KeyboardInterrupt:
    weight_today = raw_input("Time to log the daily weight-in! How much today? ")
    print ("Thanks for logging: " + weight_today)
  return

Simple computational exercise

========
UPDATE 23-Jun-2013: After approving comments yesterday and tweaking my doctests, this exercise certainly must have been on my mind!  I woke up this morning with a “why didn’t I do it this way before?!” thought. My 2nd revision to this exercise is posted as a reply below.
========
UPDATE 10-Mar-2013: OUCH! Mongo apologies for all the kind people who have commented!!!! Just received another one today. I’m just a budding blogger (ha – more like blogger-wannabe; i don’t deserve the “blogger” title by any stretch — yet!) as well as a terrifically overworked employee, so there’s little time to play these days. I will be getting back into it with a small diversion toward into some HTML parsing.

Thank you, thank you, thank you to the commenters! It’s really delightful you happened to discover my little post. Cheers to all.

— Original 20-Jan-2013 post below —

Over the weekend, I was at the MIT Press bookstore in Cambridge MA for “The CSound Book” and of course I had to ask if they had any Python books.  I picked up a copy of John V. Guttag’s “Introduction to Computation and Programming Using Python“, Spring 2013 Edition.

Starting reading it, and will likely reveal various things from it as this blog continues.  For today, however, here’s the “finger exercise” from section 2.2:

“Write a program that examines three variables–x, y, and z–and prints the largest odd number among them.  If none of them are odd, it should print a message to that effect.”

Here’s my solution. It sure looks ugly to me, but I think it works.

I also added in the doctest module with verbose, as a kind of unit test, to validate against some outputs recorded in an IDLE session.   According to the documention, “The doctest module searches for pieces of text that look like interactive Python sessions, and then executes those sessions to verify that they work exactly as shown.”

Self-documenting AND testable — cool, yes?

POSTSCRIPT:  One can google and find an approach like this, but I took the path of a person who hasn’t yet learned anything other than simple comparison operators, compound Boolean operations, and int, print, and the modulo operator %.

OH, and to be clear. because I wanted to have the doctest module, the solution is also implemented with a function definition. Output from running is below the source code.

# largestodd.py
#
# Example 2.2 taken from "Introduction to Computation and
# Programming Using Python", Spring 2013 Edition, p.16
# Exercise author: John V. Guttag
#
# Code author: mgh from "My Pythonic Year" blog at pythonicyear.com

def largestodd(x,y,z):
    """Compare three numbers and print largest odd, 
       or none is odd, a message to that effect.

    >>> largestodd(1,3,5)
    z is largest odd
    >>> largestodd(1,5,3)
    y is largest odd
    >>> largestodd(7,5,3)
    x is largest odd
    >>> largestodd(2,5,3)
    y is largest odd
    >>> largestodd(2,5,7)
    z is largest odd
    >>> largestodd(5,2,7)
    z is largest odd
    >>> largestodd(7,2,5)
    x is largest odd
    >>> largestodd(7,9,2)
    y is largest odd
    >>> largestodd(11,9,2)
    x is largest odd
    >>> largestodd(11,2,2)
    x is largest odd
    >>> largestodd(2,3,2)
    y is largest odd
    >>> largestodd(2,2,23)
    z is largest odd
    >>> largestodd(2,2,2)
    NONE of x y z are odd

    """
    if x%2 != 0 :
        if y%2 != 0 :
            if z%2 !=0 :
            # all three are odd
                if x > y and x > z :
                    print 'x is largest odd'
                elif y > z:
                    print 'y is largest odd'
                else:
                    print 'z is largest odd'
            else: # only x and y are odd
                if x > y :
                    print 'x is largest odd'
                else:
                    print 'y is largest odd'
        elif z%2 != 0:
            # both x and z are odd
            if x > z :
                print 'x is largest odd'
            else:
                print 'z is largest odd'
        else:
            #x odd, but neither y nor z
            print 'x is largest odd'
    else:
        #x not odd, test y and z
        if y%2 != 0:
            # y is odd
            if z%2 != 0:
                # y and z are odd
                if y > z:
                        print 'y is largest odd'
                else:
                        print 'z is largest odd'
            else:
                print 'y is largest odd'
        else:
            #y not odd
            if z%2 != 0:
                print 'z is largest odd'
            else:
                print 'NONE of x y z are odd'
    return

if __name__ == "__main__":
        import doctest
        doctest.testmod()

Output when run:

>>> 
Trying:
    largestodd(1,3,5)
Expecting:
    z is largest odd
ok
Trying:
    largestodd(1,5,3)
Expecting:
    y is largest odd
ok
Trying:
    largestodd(7,5,3)
Expecting:
    x is largest odd
ok
Trying:
    largestodd(2,5,3)
Expecting:
    y is largest odd
ok
Trying:
    largestodd(2,5,7)
Expecting:
    z is largest odd
ok
Trying:
    largestodd(5,2,7)
Expecting:
    z is largest odd
ok
Trying:
    largestodd(7,2,5)
Expecting:
    x is largest odd
ok
Trying:
    largestodd(7,9,2)
Expecting:
    y is largest odd
ok
Trying:
    largestodd(11,9,2)
Expecting:
    x is largest odd
ok
Trying:
    largestodd(11,2,2)
Expecting:
    x is largest odd
ok
Trying:
    largestodd(2,3,2)
Expecting:
    y is largest odd
ok
Trying:
    largestodd(2,2,23)
Expecting:
    z is largest odd
ok
Trying:
    largestodd(2,2,2)
Expecting:
    NONE of x y z are odd
ok
1 items had no tests:
    __main__
1 items passed all tests:
  13 tests in __main__.largestodd
13 tests in 2 items.
13 passed and 0 failed.
Test passed.
>>>

Argument passing

Okay, starting to hit the tutorial for 2.7 over at python.org, and wanted to work out argument passing:

2.1.1. Argument Passing

When known to the interpreter, the script name and additional arguments thereafter are turned into a list of strings and assigned to the argvvariable in the sys module. You can access this list by executing import sys. The length of the list is at least one; when no script and no arguments are given, sys.argv[0] is an empty string. When the script name is given as '-' (meaning standard input), sys.argv[0] is set to '-'. When -c command is used, sys.argv[0] is set to '-c'. When -m module is used, sys.argv[0] is set to the full name of the located module. Options found after -c command or -m module are not consumed by the Python interpreter’s option processing but left in sys.argv for the command or module to handle.

Also – quick shout out to: how can i run my python program directly from the shell

Right.  What’s that all mean? Here’s my program, “test.py”:

#!/usr/bin/env python2.7
import sys
print "i am test.py and sys.argv[0] is: %s\n" \
      "and len(sys.argv) is: %d\n" \
      "and sys.argv is:" \
      %(sys.argv[0], len(sys.argv)), \
      sys.argv

Note, it’s executable:

PY$ ls -las test.py
8 -rwxr-xr-x 1 mgh wheel 129 Jan 19 22:52 test.py

And some results:

PY$ python test.py
i am test.py and sys.argv[0] is: test.py
and  len(sys.argv) is: 1
and sys.argv is: ['test.py']

PY$ # one arg
PY$ python test.py 1st
i am test.py and sys.argv[0] is: test.py
and len(sys.argv) is: 2
and sys.argv is: ['test.py', '1st']

PY$ # without python
PY$ ./test.py 1st 2nd
i am test.py and sys.argv[0] is: ./test.py
and len(sys.argv) is: 3
and sys.argv is: ['./test.py', '1st', '2nd']

PY$ ./test.py 1 2 'it works!'
i am test.py and sys.argv[0] is: ./test.py
and len(sys.argv) is: 4
and sys.argv is: ['./test.py', '1', '2', 'it works!']
PY$

OH SNAP — that’s cool. I just realized that “pythonic year” abbreviates to “PY”. Honestly, I did NOT plan THAT! Neato.

Okay, here’s a bit of an improvement using multi-line strings with triple-quote: ”’

test2py:

#!/usr/bin/env python2.7
import sys
print '''i am test.py 
     and sys.argv[0] is: %s
     and len(sys.argv) is: %d 
     and sys.argv is: %s
     '''%(sys.argv[0], len(sys.argv), sys.argv)

And results:

PY$ ./test2.py 
i am test.py 
     and sys.argv[0] is: ./test2.py
     and len(sys.argv) is: 1 
     and sys.argv is: ['./test2.py']

PY$ ./test2.py 1 2 3 'str w/space'
i am test.py 
     and sys.argv[0] is: ./test2.py
     and len(sys.argv) is: 5 
     and sys.argv is: ['./test2.py', '1', '2', '3', 'str w/space']

PY$