Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Defining a Context Manager Class

While the file example in the previous section shows an object which is both the Context Manager and the Working Object. We'll show the two as separate class definitions in order to clearly separate the two elements of the design pattern.

A Context Manager must implement two methods to collaborate properly with the with statement.

__enter__

This method is called on entry to the with statement. The value returned by this method function will be the value assigned to the as variable.

__exit__( type , value , traceback )

This method is called on exit from the with statement. If the type , value or traceback parameters have values other than None, then an exception occured. If the type , value or traceback parameters have values of None, then this is a normal conclusion of the with statement.

Example Context Manager. Let's assume we must produce a file which has a proper final line, irrespective of errors encountered during the file's production. For example, we could be producing a file with a secure hash like an MD5 digest of the contents, This secure digest can be used to detect processing errors or attempted tampering with the file.

We'll look at our working object first, then we'll look at a Context Manager for that object. This is the working object, SecureLog. This is a class which writes to a file, as well as accumulate a secure digest using the MD5 algorithm.

import hashlib
class SecureLog( object ):
    def __init__( self, someFile, marker="-----HASH-----" ):
        self.theFile= someFile
        self.marker= marker
        self.hash= hashlib.md5()
    def write( self, aLine ):
        self.theFile.write( aLine )
        self.hash.update(aLine)
    def finalize( self ):
        self.theFile.write( "%s\n%s\n" % ( self.marker, self.hash.hexdigest(), ) )
    def close( self ):
        pass

If this class is used correctly, the file will end with a marker line and the MD5 digest value. Other programs use the same MD5 algorithm when reading the file to confirm that the expected digest is the actual digest.

Here is a Context Manager, named SecureLogManager, which incorporates the SecureLog class. To be a context manager, this class implements the required __enter__ and __exit__ methods.

class SecureLogManager( object ):
    def __init__( self, someFile ):
        self.theFile= someFile
    def __enter__( self ):
        self.transLog= SecureLog( self.theFile )
        return self.transLog
    def __exit__( self, type, value, tb ):
        if type is not None:
            pass # Exception occurred
        self.transLog.finalize()
        self.transLog.close()
        self.theFile.close()
1

The __enter__ method creates the SecureLog and returns it so that the as clause will assign the log to a variable.

2

The __exit__ method checks to see if it is ending with an exception. In this case, we don't do any special processing for exceptions raised within the with statement. The __exit__ method, however, uses the SecureLog's finalize method to be absolutely sure that a proper digest is written to the log file before it is closed.

The overall main program can have the following structure. We don't need to make special arrangements in the main program to be sure that the log is finalized correctly. We have delegated those special arrangements to the context manager object, leaving us with an uncluttered main program.

from __future__ import with_statement

result= open( 'log.log', 'w' )
with SecureLogManager( result ) as log:
    log.write( "Some Configuration\n" )
    source= open('source.dat','rU')
    for line in source:
        log.write( line )
    source.close()
1

Until Python 2.6 arrives, we must add the with statement to Python with the from __future__ import statement. This statement must be one of the first statements in the program.

2

The with statement does several things. First, it creates an instance of SecureLogManager, which is our context manager. Then the __enter__ method is evaluated, which returns an instance of SecureLog for use by the suite inside the with statement.

After this initialization, the suite of statements is executed. Once the suite of statements finishes, the SecureLogManager's __exit__ method is evaluated. This final step will finalize and close the log file.


 
 
  Published under the terms of the Open Publication License Design by Interspire