On May 7, 6:52 pm, [EMAIL PROTECTED] 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() -- http://mail.python.org/mailman/listinfo/python-list