Source code for tpycl.tpycl

#!/usr/bin/env python

#
# tpycl.py is the python support code to allow calling of python-wrapped
# vtk code from tcl scripts
#
# the main class is tpycl, and scripts can 
#

import sys
import os

if not 'sphinx' in sys.modules:
  import Tkinter
  from __main__ import slicer
  import qt

[docs]class tpycl(object): def __init__(self): self.verbose = False # when python is initialized inside slicer there is no argv # so create a fake one if needed try: argv0 = sys.argv[0] except AttributeError: sys.argv = [] sys.argv.append("") self.tcl = Tkinter.Tcl() self.tcl.createcommand("py_eval", self.py_eval) self.tcl.createcommand("py_package", self.py_package) self.tcl.createcommand("py_type", self.py_type) self.tcl.createcommand("py_del", self.py_del) self.tcl.createcommand("py_puts", self.py_puts) self.tcl.createcommand("py_after", self.py_after) self.tcl.createcommand("py_vtkInstanceName", self.py_vtkInstanceName) self.timer = qt.QTimer() self.timer.setSingleShot(True) self.timer.setInterval(0) self.timer.connect('timeout()', self.after_callback) if sys.platform == 'win32': # Update environment variables set by application - unlike other platforms, # on windows this does not happen automatically so we do it here # Note that subsquent env changes will not be reflected for key in os.environ.keys(): self.tcl_putenv(key, os.environ[key]) # This path is Slicer-specific self.tcl.eval('source "%s/bin/Python/tpycl/tpycl.tcl"' % slicer.app.slicerHome)
[docs] def usage(self): print "tpycl [options] [file.tcl] [arg] [arg]" print "-v --verbose : debugging info while parsing" print "-h --help : extra help info" print "" print "tpycl is a tcl shell implemented in python that" print "allows you to import and execute python code from" print "inside tcl (hence the name - an homage to jcw's typcl which" print "allows you to call tcl from python)." print "Not all python constructs supported, but tpycl should be" print "adequate to call many packages." exit()
[docs] def dprint(self, *args): """ debug print """ if self.verbose: for arg in args: print arg, print ""
[docs] def py_package(self, packageName): """ imports a vtk-wrapped python package """ self.dprint ("importing %s as a package" % packageName) if packageName == 'vtk': import vtk globals()[packageName] = vtk for name in dir(vtk): self.tcl.eval("::tpycl::registerClass %s %s.%s" % (name, packageName, name) ) return package = globals()[packageName] = __import__(packageName) for name in dir(package): self.tcl.eval("::tpycl::registerClass %s %s.%s" % (name, packageName, name) )
[docs] def py_type(self,string): """ return true if the string represents a valid python type such as an int or an instanced variable """ try: exec( "type(%s)"%string, globals() ) except: return 0 return 1
[docs] def py_vtkInstanceName(self,instance): """ make a unique name for an instance using the classname and pointer in hex .. note:: Assumes the string form of the instance will end with hex \ encoding of the pointer. \ For example: ``'(vtkImageData)0x2a9a750'`` """ # used to work with vtk 5.6 #return "%s%s" % (instance.GetClassName(), repr(instance).split()[-1][:-1]) # now just strip off the parens return repr(instance).replace('(','').replace(')','')
[docs] def py_del(self,instanceName): """ deletes a named instance """ # only delete if the instanceName exists if globals().has_key(instanceName): exec( "del(%s)"%instanceName, globals() ) return None
[docs] def py_puts(self, noNewLine, message): """ print into the python shell """ print(message) if noNewLine == "0": print("\n")
[docs] def py_after(self): """ sets the QTimer to call the callback """ self.timer.start()
[docs] def after_callback(self): """ what gets called when the after timeout happens """ self.tcl.eval('::after_callback') self.timer.stop()
[docs] def py_eval(self,cmd): """ evaluated the python command string and returns the result - if the result is a vtk object instance, it is registered in the tcl interp - if the result is a tuple, it is converted to a tcl-style list """ cmd = "__tpycl_result = " + cmd try: exec( cmd, globals() ) except: print( "Error executing %s" % cmd ) print( sys.exc_info() ) raise evalResult = globals()["__tpycl_result"] try: if evalResult.IsA("vtkObject"): instanceName = self.py_vtkInstanceName(evalResult) if self.tcl_eval("info command %s" % instanceName) == "": exec ("%s = globals()['__tpycl_result']" % instanceName, globals()) self.tcl_eval( "proc ::%s {args} {tpycl::methodCaller %s %s $args}" % (instanceName, instanceName, instanceName) ) return( instanceName ) except AttributeError: pass try: if evalResult.__class__.__name__ == 'tuple': returnValue = evalResult[0] for element in evalResult[1:]: returnValue = "%s %s" % (returnValue, element) return( returnValue ) except AttributeError: pass return( repr(evalResult) )
[docs] def tcl_callback(self, cmd): """ evaluate tcl code string but don't return the result (only prints error messages) """ self.dprint("callback command is <%s>" % cmd) try: result = self.tcl.eval(cmd) except Tkinter.TclError,error: print (error) errorInfo = self.tcl.eval("set ::errorInfo") print (errorInfo)
[docs] def tcl_eval(self, cmd): """ evaluate tcl code string and return the result - py_package is a special string to import python code into tcl - py_eval goes back from tcl into python """ self.dprint("command is <%s>" % cmd) if cmd == 'exit': exit() if cmd.startswith("py_package "): self.py_package( cmd[10:] ) return() if cmd.startswith("py_eval "): self.py_eval( cmd[len("py_eval "):] ) return() try: result = self.tcl.eval(cmd) except Tkinter.TclError,error: print (error) errorInfo = self.tcl.eval("set ::errorInfo") print (errorInfo) return(None) return(result)
[docs] def tcl_putenv(self, key, value): """ Set environment variable """ import re self.tcl.eval("global env; set env(%s) \"%s\""%(key, re.escape(value)))
[docs] def main(self, argv): """ main loop for the interpreter shell """ # parse command line options self.file = "" self.args = [] while argv != []: arg = argv.pop(0) if arg == "-v" or arg == "--verbose": self.verbose = True continue if arg == "-h" or arg == "--help": self.usage() if not self.file: self.file = arg else: self.args.append(arg) self.dprint("file", self.file) self.dprint("args", self.args) # if given a file, run it if self.file != "": fp = open(self.file) while 1: cmd = fp.readline() if cmd == "": break self.tcl_eval( cmd[:-1] ) # evaluate stdin until eof while 1: sys.stdout.write( "% " ) cmd = sys.stdin.readline()[:-1] if cmd != "": result = self.tcl_eval( cmd ) if result != None: print result
if __name__ == "__main__": tp = tpycl() tp.main(sys.argv[1:])