Languages as Tools
Languages are just programming tools
Just as most sophisticated programming tools are really little languages
Theoretically equivalent to one another
Anything you can do in one, you can do in another
Although some things may be easier or harder
Take a look at how Python implements some of the things we've seen in Java
Graphs in Python
Same basic concept: a map of nodes to sets of reachable nodes
Represent sets in Python using dictionaries
Keys are set elements
All values are None (or zero, or something like that)
Many languages use this trick
class Graph:
def __init__(self):
self.data = {}
def getNodes(self):
return self.data.keys()
def hasNode(self, node):
return node in self.data
def addNode(self, node, arcs=[]):
self.addEmptyNode(node)
self.addArcs(node, arcs)
def removeNode(self, node):
del self.data[node]
for key in self.data:
self.removeArc(key, node)
...etc...
def __len__(self):
return len(self.data)
Unit Testing
PyUnit is a Python version of JUnit
Test cases, test suites, GUI and text runners, etc.
To use:
Import unittest
Derive test classes from unittest.TestCase
Write testXYZ() methods using assert, failIf(), and failUnless()
Override setUp() and tearDown() if necessary
Sound familiar?
One difference: use unittest.main() to run all tests in a file
import sys, unittest
class SimpleTests(unittest.TestCase):
def testLowerLower(self):
assert 'a' < 'z'
def testLowerUpper(self):
assert 'a' < 'Z'
def testUpperUpper(self):
assert 'A' < 'Z'
def testUpperLower(self):
assert 'A' < 'a'
if __name__ == "__main__":
unittest.main()
.F..
======================================================================
FAIL: testLowerUpper (__main__.SimpleTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "testing.py", line 14, in testLowerUpper
assert 'a' < 'Z'
AssertionError
----------------------------------------------------------------------
Ran 4 tests in 0.000s
FAILED (failures=1)
Working With the Filesystem
Scripting languages like Python often used for:
Manipulating files
Running other programs
Can do all of these things with shell scripts
That is, by saving shell commands in a file, and executing that
But:
The shell doesn't offer much in the way of data structures
Unix shell scripts and Windows batch files are closely tied to particular operating systems
Compare Python:
Rich data structures
Its os module hides (most of) the differences between different operating systems
Constants In os Module
| Constant | Unix | Windows | Mac | Meaning |
name |
"posix" |
"nt" |
"mac" |
O/S name |
curdir |
"." |
"." |
":" |
Current directory |
pardir |
".." |
".." |
"::" |
Parent directory |
sep |
"/" |
"\\" |
"?" |
Path separator |
linesep |
"\n" |
"\r\n" |
"\r" |
Line separator |
Functions in os Module
chdir(path) |
Change current directory |
listdir(path) |
List contents of directory |
mkdir(path) |
Make a new directory |
rmdir(path) |
Remove a directory |
remove(path) |
Remove a file |
rename(old, new) |
Rename a file or directory |
The os.path Sub-module
split(path) |
Return front and last component of path |
exists(path) |
Does something called path exist? |
isdir(path) |
True if path is a directory |
isfile(path) |
True if path is a file |
getatime(path) |
Get last access time |
getmtime(path) |
Get last modification time |
getsize(path) |
Get size in bytes |
Report Missing Files
Prints out command line arguments that aren't files
import sys, os
for path in sys.argv[1:]:
if not os.path.exists(path) or not os.path.isfile(path):
print path
Deleting Temporary Files
Given a list of directory names on the command line, deletes *.tmp in those directories
import sys, os
for dir in sys.argv[1:]:
os.chdir(dir)
contents = os.listdir(os.curdir)
for name in contents:
if os.path.isfile(name) and name[-4:].lower() == ".tmp":
os.remove(name)
Another Way to Delete Temporary Files
Create full path name rather than changing directory
import sys, os
for dir in sys.argv[1:]:
contents = os.listdir(dir)
for name in contents:
name = os.path.join(dir, name)
if os.path.isfile(name) and name[-4:].lower() == ".tmp":
os.remove(name)
Find Old Files
Lists files that are older than N days
Where N is specified on the command line
And "older" means "haven't been accessed"
Uses time module to get the current time
And exceptions
Just like Java
import sys, os, time
try:
days = int(sys.argv[1])
except IndexError:
print >> sys.stderr, "Usage: oldfiles numdays dirs..."
sys.exit(1)
except ValueError:
print >> sys.stderr, "Can't parse '" + sys.argv[1] + "' as integer"
sys.exit(1)
now = int(time.time())
cutoff = now - (days * 24 * 60 * 60)
for arg in sys.argv[2:]:
if os.path.isdir(arg):
contents = os.listdir(arg)
for name in contents:
name = os.path.join(arg, name)
if os.path.isfile(name):
if os.path.getatime(name) <= cutoff:
print name
An Exercise for the Reader
This script prints out files that are:
Older than N days if -o N used
Newer than N days if -n N used
New features:
Uses getopt module to parse command-line options
Assigns functions to variables
After all, a function is just a block of bytes...
from module import name to get specific functions
Your mission: understand how this script works
import sys, time, getopt
from os import listdir
from os.path import isdir, isfile, join, getatime
def older(t, cutoff):
return t <= cutoff
def newer(t, cutoff):
return t >= cutoff
days = 1
compare = older
optlist, dirs = getopt.getopt(sys.argv[1:], "o:n:")
for (opt, arg) in optlist:
if opt == "-o":
compare = older
days = int(arg)
elif opt == "-n":
compare = newer
days = int(arg)
now = int(time.time())
cutoff = now - (days * 24 * 60 * 60)
for d in dirs:
if isdir(d):
contents = listdir(d)
for path in contents:
path = join(d, path)
if isfile(path) and compare(getatime(path), cutoff):
print path
Running Other Programs
One program can run another
Make does this
So does the shell
And so can Python
This will be a major topic of 209
Give you a sneak preview here
Reading from a Sub-Command
Goal: run a program, and read its output as if it were a file
from os import popen
input = popen("ls", "r")
for line in input.readlines():
print line
deletejoin.py
deletetemp.py
etc...
Note: double-spaced because the lines we are reading have carriage returns
Can write to a sub-command by opening with "w" instead of "r"
$Id: pytools.html,v 1.1.1.1 2004/01/04 05:02:31 reid Exp $