Presents a console permitting inspection.  Input as well as output
saved in Python-readable form.
Python 2.5.1 memoryconsole4.py logging to My Documents\console.log
>>> class A:
...     def f( self ):
...             print 2
...
>>> a=A()
>>> import inspect
>>> inspect.getsource( a.f )
'\tdef f( self ):\n\t\tprint 2\n'

This enabled by a log file, optionally set to console.log.  Contents
are:

#Mon May 07 2007 06:33:42 PM Python win32 2.5.1 in memoryconsole4.py
class A:
        def f( self ):
                print 2

a=A()
import inspect
inspect.getsource( a.f )
#fb: '\tdef f( self ):\n\t\tprint 2\n'

Line 10 Microsoft Win32 convenience binding; line 49 a little
confusing.  Give it a shot.

from code import InteractiveConsole
import sys
from os import environ
from datetime import datetime
from StringIO import StringIO
from re import sub
from os.path import join,split,abspath

class LoggedStdOut(StringIO):
        deflog= environ['USERPROFILE']+\
                '\\My Documents\\console.log'
        def __init__( self, log=None ):
                StringIO.__init__( self )
                self.stdout= None
                self.trip,self.head= True,''
                self.logname= log or LoggedStdOut.deflog
                self.prettyname=join(split(split(abspath(
                        self.logname))[0])[1],split(abspath(self.logname))[1])
                for x,_ in enumerate( open( self.logname,'r' ) ): continue
                self._lineno= x #can use linecache
                self._log= open( self.logname,'a' )
        def catch( self,head='#fb: ' ):
                self.stdout= sys.stdout
                sys.stdout= self
                self.head= head
                self.trip= True
        def throw( self ):
                sys.stdout= self.stdout
                self.stdout= None
        def getlineno( self ):
                return self._lineno
        def logwrite( self, data ):
                self._log.write( data )
                self._lineno+= data.count('\n')
        def logflush( self ):
                self._log.flush()
        def write( self, data ):
                datal= sub( '\n([^$])','\n%s\\1'%self.head,data )
                if self.trip: self.logwrite( self.head )
                self.logwrite( datal )
                self.trip= data.endswith('\n')
                return self.stdout.write( data )
        def writelines( self, data ):
                raise 'Branch uncoded'

class LoggedInteractiveConsole(InteractiveConsole):
        def __init__( self,log=None,locals=None,filename=None ):
                self.out= LoggedStdOut( log )
                if filename is None: filename= split(self.out.logname)[1]
                InteractiveConsole.__init__( self,locals,filename )
                self.locals.update( __logname__= abspath(
                        self.out.logname ) )
        def push( self,line ):
                self.out.logwrite( '%s\n'%line )
                self.out.logflush()
                self.out.catch()
                more= InteractiveConsole.push( self,line )
                self.out.throw()
                return more
        def write( self,data ):
                return sys.stdout.write( data )
        def interact( self,banner=None,*args ):
                self.out.logwrite( '\n#%s Python %s %s in %s\n'%\
                        ( datetime.now().strftime(
                                '%a %b %d %Y %I:%M:%S %p' ),
                                sys.platform,sys.version.split()[0],
                                split(sys.argv[0])[1] ) )
                if banner is None: banner=\
                        "Python %s %s logging to %s"%\
                        ( sys.version.split()[0],split(sys.argv[0])[1],
                        self.out.prettyname )
                return InteractiveConsole.interact( self,banner,*args )


import compiler
import linecache
class NotatedConsole(LoggedInteractiveConsole):
        """-Code object- intercepted in runsource, and rerun with
        stored source before runsource.  Built-in runsource
        does not modify source between call and runcode."""
        def runsource( self,sc,filename='<input>',*args ):
                self._runsourceargs= sc,filename
                return LoggedInteractiveConsole.runsource( self,sc,
                        filename,*args )
        def runcode( self,*args ):
                sc,filename= self._runsourceargs
                linecache.checkcache( filename )
                #custom second compile (fourth actually)
                t= compiler.parse( sc )
                compiler.misc.set_filename( filename,t )
                def set_lineno( tree, initlineno ):
                        worklist= [ tree ]
                        while worklist:
                                node= worklist.pop( 0 )
                                if node.lineno is not None:
                                        node.lineno+= initlineno
                                worklist.extend( node.getChildNodes() )
                set_lineno( t,self.out.getlineno()-len( self.buffer )+1 )
                code= compiler.pycodegen.\
                        InteractiveCodeGenerator( t ).getCode()
                LoggedInteractiveConsole.runcode( self,code )
                linecache.checkcache( filename )

if __name__=='__main__':
        console= NotatedConsole()
        console.interact()

-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to