inspected console

castironpi at gmail.com castironpi at gmail.com
Mon May 7 20:59:18 EDT 2007


On May 7, 6:52 pm, castiro... at gmail.com wrote:
> 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()

Console-defined objects can be pickled as well.  ">>>edit()" opens
console.log.  Editor objects are pickled between statements.

Python 2.5.1 furtherconsoles-display.py logging to My Documents
\console.log
>>> class A:
...     b=0
...
>>> from pickle import loads,dumps
>>> loads(dumps(A))
<class workmodule.A at 0x00B28030>
>>> loads(dumps(A)).b
0
>>> edit()
Loaded ok

and the few lines from console.log:
#Mon May 07 2007 07:55:30 PM Python win32 2.5.1 in furtherconsoles-
display.py
class A:
	b=0

from pickle import loads,dumps
loads(dumps(A))
#fb: <class workmodule.A at 0x00B28030>
loads(dumps(A)).b
#fb: 0
edit()

Hard coded paths on lines 24 and 67.  Hope that's copy-and-pasteable

import memoryconsole4 as memoryconsole
from os.path import join,exists,split,abspath
from os import environ
from sys import argv
import sys
import cPickle as pickle
from subprocess import Popen
from datetime import datetime,timedelta

class Editors:
	"""Pickled after every statement."""
	def edit( self,filename=None ):
		assert hasattr( self,'_cmdlinestr' ) and hasattr( self,'console' )
		if filename is None: filename= abspath( self.console.out.logname )
		parms= { 'filename': filename, 'loglen': self.console.out.getlineno()
+len(self.console.buffer)+1 }
		Popen( self._cmdlinestr % parms )
		print >>sys.stderr, "Loaded ok"
	def __repr__( self ):
		return '<%s at %i: %s>'%(self.__class__,id(self),repr( [ x for x in
dir(self) if not x.startswith('__') ] ))
	def __call__( self,*args ):
		self.edit( *args )#what find default?

class EditorsConsole(memoryconsole.NotatedConsole):
	defdat= join( environ['USERPROFILE'],'My Documents\
\consoleeditor.pickle' )
	def __init__( self,cmdlinestr,datname=None,*args,**kwargs ):
		memoryconsole.NotatedConsole.__init__( self,*args,**kwargs )
		self._datname= datname or self.defdat
		if exists( self._datname ): self.edit=
pickle.load( open( self._datname,'rb' ) )
		else: self.edit= Editors()
		self.edit._cmdlinestr= cmdlinestr
		self.locals.update( edit=self.edit )
		self.edit.console= self
		self.lasttimestamp= datetime.now()
	def push( self,*args ):
		more= memoryconsole.NotatedConsole.push( self,*args )
		if not more and datetime.now()- self.lasttimestamp >
timedelta( minutes= 25 ):
			self.lasttimestamp= datetime.now()
			self.out.logwrite( '#%s in %s\n'%\
				( self.lasttimestamp.strftime( '%a %b %d %Y %I:%M:%S
%p' ),split(argv[0])[1] ) )
		del self.edit.console
		pickle.dump( self.edit,open( self._datname,'wb' ) ) #don't pickle me
		self.edit.console= self
		return more
	def __repr__( self ):
		return '<%s at %i: %s>'%(self.__class__,id(self),repr( [ x for x in
dir(self) if not x.startswith('__') ] ))

import compiler as c
from memory import Memory
import imp
from sys import modules

class ModuleConsole(EditorsConsole):
	def __init__( self,log=None,locals=None,filename=None ):
		EditorsConsole.__init__( self,log,locals,filename )
		self.workmodule= imp.new_module( 'workmodule' )
		self.workmodule.__file__= self.out.logname
		modules[self.workmodule.__name__]= self.workmodule
		self.locals.update( workmodule=self.workmodule,
__name__=self.workmodule.__name__ )
		self.locals.update( __file__=self.workmodule.__file__ )#may omit
__logname__
		del self.locals['__logname__']
	def runcode( self,*args ):
		EditorsConsole.runcode( self,*args )
		for k,v in self.locals.iteritems():
			setattr( self.workmodule,k,v )

if __name__=='__main__':
	editorscmdlinestr= '"%s" "%%(filename)s" -cursor %%(loglen)i:
1'%join(environ['PROGRAMFILES'],'editplus 2\\editplus.exe')
	console= ModuleConsole(editorscmdlinestr)
	console.interact()




More information about the Python-list mailing list