inspected console

castironpi at gmail.com castironpi at gmail.com
Mon May 7 19:52:30 EDT 2007


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()




More information about the Python-list mailing list