Python and JTcl

Calling Python code from Tcl is either a Joke ( TIP #365 ) or a serious effort Elmer. In either case, doing this is quite easy with JTcl

Just place Jython on your class path,

export CLASSPATH=/PathToJython/jython.jar

start JTcl, and source the following:

namespace eval ::py  {
    variable engine
    set engManager [java::new javax.script.ScriptEngineManager]
    set engine [$engManager getEngineByName python]
}
proc ::py::getResult {value} {
    variable engine
    if {[java::isnull $value]} {
        set result ""
    } else {
        set class [lindex [[$value getClass] toString] end]
        switch -exact $class {
            "java.lang.Integer" {
                set value [java::cast $class $value]
                set result [$value intValue]
            }
            "java.lang.Double" {
                set value [java::cast $class $value]
                set result [$value doubleValue]
            }
            "java.lang.Float" {
                set value [java::cast $class $value]
                set result [$value doubleValue]
            }
            "java.lang.Long" {
                set value [java::cast $class $value]
                set result [$value longValue]
            }
            "org.python.core.PyTuple" {
                set value [java::cast $class $value]
                set size [$value size]
                set result [list]
                for {set i 0} {$i < $size} {incr i} {
                    lappend result [getResult [$value get $i]]
                }
            }
            default {
                set result [$value toString]
            }
        }
    }
    return $result
}
proc ::py::do {script} {
    variable engine
    return [getResult [$engine eval $script]]
}
proc  ::py::get {var} {
    variable engine
    return [getResult [$engine get $var]]
}
proc ::py::put {var value} {
    variable engine
    if {[string is integer -strict $value]} {
        $engine put $var [java::new java.lang.Integer $value]
    } elseif {[string is double -strict $value]} {
        $engine put $var [java::new java.lang.Double $value]
    } else {
        $engine put $var $value
    }
}

proc ::py::lput {var valueList} {
    variable engine
    set nElems [llength $valueList]
    #set array [java::new {org.python.core.PyObject[]} $nElems $valueList]
    set array [java::new {org.python.core.PyObject[]} $nElems]
    set i 0
    foreach elem $valueList {
        if {[string is integer -strict $elem]} {
            set jvalue [java::new org.python.core.PyLong $elem]
        } elseif {[string is double -strict $elem]} {
            set jvalue [java::new org.python.core.PyDouble $elem]
        } else {
            set jvalue [java::new org.python.core.PyString $elem]
        }
        $array set $i $jvalue
        incr i
    }
    set pyTuple [java::new org.python.core.PyTuple $array]
    $engine put $var $pyTuple
}
proc ::py::alias {name} {
        proc ::$name args "
           set pargs \[join \$args ,\]
           return \[::py::do ${name}(\$pargs)\]
    "
}

Then you can do things like::

py::put a 3
py::put b 4
py::do "x = a + b"
puts [py::get x]

py::do {def fib(n):
    a, b = 0, 1
    while a < n:
        print a,
        a, b = b, a+b
}
py::do {fib(100)}


py::alias fib
fib 100