Python Works-in-Progress


PyCon Presentations

I gave two presentations at the 2006 PyCon in Dallas, TX.

These links should display using S5.

Here are some of the projects I'm doing in Python.


Simple Matrix class

As an exercise (and to avoid the overhead of importing a large numerical analysis package just to do a matrix inversion), I put together a simple Matrix class that computes transpose, inverse, determinant, eigenvectors and eigenvalues of a matrix, and supports matrix addition and multiplication. Also supports a simple matrix initialization from a formatted string, similar to Matlab. (Also like Matlab, row/column references are 1-based, not 0-based.)

m = Matrix("""1 2 3 4
              5 11 20 3
              2 7 11 1
              0 5 3 1""")
m_inv = m.inverse()
print m
print m_inv
print m*m_inv
prints
1.0, 2.0, 3.0, 4.0
5.0, 11.0, 20.0, 3.0
2.0, 7.0, 11.0, 1.0
0.0, 5.0, 3.0, 1.0

-0.5, 1.167, -2.167, 0.667
-0.167, 0.241, -0.519, 0.463
0.167, -0.352, 0.796, -0.407
0.333, -0.148, 0.204, -0.093

1.0, 0.0, 0.0, 0.0
0.0, 1.0, 0.0, 0.0
0.0, 0.0, 1.0, 0.0
0.0, 0.0, 0.0, 1.0
It's not blazingly fast, but it is a simple small-footprint matrix class for simple equation solving and eigenvectors (up to about 10x10 matrices). This class also makes heavy use of memoizing, so that repeated calls to inverse() do not recalculate the matrix inverse every time.

O-O Text Parsing

This parsing module takes a different approach from the traditional lex/yacc method of creating parsers. This module defines several classes for constructing your grammar as a composed object directly within your program source code. As you define the grammar, you can associate parsing actions and tag names to the various grammar elements. Your code then uses this object to parse text strings, and as various elements in the grammar are matched, the parsing actions get invoked. After all parsing is completed, the resulting token strings are organized into lists, dictionaries, or named attributes. While this sounds complicated, the examples are actually quite simple.

Here is a grammar for a simple SQL parser.

    # define SQL tokens
    selectToken = CaselessLiteral( "select" )
    fromToken   = CaselessLiteral( "from" )
    starToken   = Literal( "*" )
    commaToken  = Literal( "," )
    dotToken    = Literal( "." )
    
    ident          = Word( alphas, alphanums + "_$" )
    columnName     = Upcase( ident )
    columnNameList = delimitedList( columnName )
    tableName      = Upcase( Combine( ident + Optional( dotToken + ident ) ) )
    tableNameList  = delimitedList( tableName )
    
    # define the grammar
    simpleSQL      = selectToken + \
                   ( starToken | columnNameList ).setResultsName( "columns" ) + \
                   fromToken + \
                   tableNameList.setResultsName( "tables" )
(Note that by default, the parser ignores any extra whitespace between tokens, so the grammar does not have to be cluttered with lots of "ws" elements.)

Here is the code that uses this grammar:

    def test( str ):
        print str,"->"
        try:
            tokens = simpleSQL.parseString( str )
            print "tokens = ",        tokens
            print "tokens.columns =", tokens.columns
            print "tokens.tables =",  tokens.tables
        except ParseException, err:
            print " "*err.loc + "^\n" + err.msg
            print err
        print
    
    test( "SELECT * from XYZZY, ABC" )
    test( "select * from SYS.XYZZY" )
    test( "Select A from Sys.dual" )
    test( "Select A,B,C from Sys.dual" )
    test( "Select A, B, C from Sys.dual" )
    test( "Select A, B, C from Sys.dual, Table2   " )
    test( "Xelect A, B, C from Sys.dual" )
    test( "Select A, B, C frox Sys.dual" )
Finally here is the output from this test program.
    SELECT * from XYZZY, ABC ->
    tokens =  ['select', '*', 'from', ['XYZZY', 'ABC']]
    tokens.columns = *
    tokens.tables = ['XYZZY', 'ABC']
    
    select * from SYS.XYZZY ->
    tokens =  ['select', '*', 'from', ['SYS.XYZZY']]
    tokens.columns = *
    tokens.tables = ['SYS.XYZZY']
    
    Select A from Sys.dual ->
    tokens =  ['select', ['A'], 'from', ['SYS.DUAL']]
    tokens.columns = ['A']
    tokens.tables = ['SYS.DUAL']
    
    Select A,B,C from Sys.dual ->
    tokens =  ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL']]
    tokens.columns = ['A', 'B', 'C']
    tokens.tables = ['SYS.DUAL']
    
    Select A, B, C from Sys.dual ->
    tokens =  ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL']]
    tokens.columns = ['A', 'B', 'C']
    tokens.tables = ['SYS.DUAL']
    
    Select A, B, C from Sys.dual, Table2    ->
    tokens =  ['select', ['A', 'B', 'C'], 'from', ['SYS.DUAL', 'TABLE2']]
    tokens.columns = ['A', 'B', 'C']
    tokens.tables = ['SYS.DUAL', 'TABLE2']
    
    Xelect A, B, C from Sys.dual ->
    ^
    Expected 'select'
    Expected 'select' (0), (1,1)
    
    Select A, B, C frox Sys.dual ->
                   ^
    Expected 'from'
    Expected 'from' (15), (1,16)

Here's another parsing example, of a 4-function infix notation algebraic parser.

This module is now available at SourceForge (http://sourceforge.net/projects/pyparsing/).

Thanks to Dave Kuhlman for converting my "how to" text to HTML.


Simple BMP File Writing

This is a simple module for creation of basic graphic in BMP format files, with or without RLE compression, if you want to display graphics but don't want all the overhead of a complex graphics package, such as PIL.

    bmp = BitMap( 400, 400, Color.TEAL.lighten() )
    bmp.drawSquare( 0, 0, 400 )
    
    # draw variety of colors
    colors = [ Color.BLACK, Color.RED, Color.GREEN, Color.BLUE, \
               Color.CYAN, Color.MAGENTA, Color.YELLOW, Color.BLUE, \
               Color.DKRED, Color.DKGREEN, Color.DKBLUE, Color.TEAL, \
               Color.PURPLE, Color.BROWN, Color.GRAY ]
    for i,c in enumerate(colors):
      bmp.setPenColor( c )
      for j in range(8):
        bmp.drawRect( i*25, j*45, 25, 45, True )
        bmp.setPenColor( bmp.getPenColor().lighten() )
      bmp.setDefaultPenColor()
      bmp.drawRect( i*25, 0, 25, 360, False )
  
    # test drawing lines at various angles
    bmp.setPenColor( Color.WHITE )
    bmp.drawSquare( 10, 10, 380 )
    bmp.drawSquare(  9,  9, 382 )
    bmp.drawLine( 10, 10, 389, 389 )
    bmp.drawLine( 10, 10, 70, 389 )
    bmp.drawLine( 10, 10, 389, 70 )
    bmp.drawLine( 10, 389, 389, 10 )
    bmp.drawLine( 10, 389,  70, 10 )
    bmp.drawLine( 10, 70, 389, 10 )
  
    # test saving and restoring pen color
    saveColor = bmp.setPenColor( Color.DKGREEN )
    bmp.drawRect( 90, 100, 40, 30, fill=True )
    bmp.setPenColor( saveColor )
    bmp.drawRect( 95, 105, 30, 20, fill=True )
  
    # test drawing circles
    bmp.setPenColor( Color.DKRED )
    bmp.drawCircle( 250, 150, 40, fill=True )
    bmp.setPenColor( Color.WHITE )
    bmp.drawCircle( 250, 150, 25, fill=True )
    bmp.setPenColor( Color.BLUE )
    bmp.drawCircle( 250, 150, 20, fill=True )
    bmp.setPenColor( Color.WHITE )
    bmp.drawCircle( 250, 150, 18, fill=True )
    bmp.setPenColor( Color.BLUE )
    bmp.drawCircle( 250, 150, 8 )
    
    # test lines of different types
    bmp.setPenColor( Color.BLACK )
    bmp.drawLine( 10, 380, 389, 380, BitMap.LINE_DASHED )
    bmp.drawLine( 10, 373, 389, 373, BitMap.LINE_DOTTED )
    bmp.drawLine( 10, 365, 389, 365, BitMap.LINE_DOT_DASH )
    bmp.drawLine( 10, 358, 389, 325, BitMap.LINE_DASHED )
    bmp.drawLine( 10, 353, 389, 320, BitMap.LINE_DOTTED )
    bmp.drawLine( 10, 348, 389, 315, BitMap.LINE_DOT_DASH )

    bmp.saveFile( "test.bmp" )



Calling Matlab from Python

Over the past few days I've been working with Matlab, calling it from Python through Matlab's COM interface. In this way, I can build data sets and test cases in Python, and then pass the data through to Matlab for running Matlab functions and matrix commands. As part of working this through, I developed a wrapper class, for handling Matlab's special API issues.


Back to my home page.