aidanhs / libtclpy

Other
41 stars 10 forks source link

libtclpy

This is a Tcl extension to effortlessly to call bidirectionally between Tcl and Python, targeting Tcl >= 8.5 and Python 3.6+

The extension is available under the 3-clause BSD license (see "LICENSE").

Tcl users may also want to consider using pyman, a Tcl package that provides a higher level of abstraction on top of tclpy.

USAGE

You can import the libtclpy in either a Tcl or Python parent interpreter. Doing so will initialise an interpreter for the other language and insert all libtclpy methods. This means you can call backwards and forwards between interpreters.

FROM TCL

General notes:

Reference:

example tclsh session:

% load ./libtclpy.so
%
% py eval {def mk(dir): os.mkdir(dir)}
% py eval {def rm(dir): os.rmdir(dir); return 15}
% py import os
% set a [py eval {print "creating 'testdir'"; mk('testdir')}]
creating 'testdir'
% set b [py call rm testdir]
15
%
% py import StringIO
% py eval {sio = StringIO.StringIO()}
% py call sio.write someinput
% set c [py call sio.getvalue]
someinput
%
% py eval {divide = lambda x: 1.0/int(x)}
% set d [py call divide 16]
0.0625
% list [catch {py call divide 0} err] $err
1 {ZeroDivisionError: float division by zero
  File "<string>", line 1, in <lambda>
----- tcl -> python interface -----}
%
% py import json
% py eval {
def jobj(*args):
    d = {}
    for i in range(len(args)/2):
        d[args[2*i]] = args[2*i+1]
    return json.dumps(d)
}
% set e [dict create]
% dict set e {t"est} "11{24"
t\"est 11\{24
% dict set e 6 5
t\"est 11\{24 6 5
% set e [py call jobj {*}$e]
{"t\"est": "11{24", "6": "5"}
%
% py import sqlite3
% py eval {b = sqlite3.connect(":memory:").cursor()}
% py eval {def exe(sql, *args): b.execute(sql, args)}
% py call exe "create table x(y integer, z integer)"
% py call exe "insert into x values (?,?)" 1 5
% py call exe "insert into x values (?,?)" 7 9
% py call exe "select avg(y), min(z) from x"
% py call b.fetchone
4.0 5
% py call exe "select * from x"
% set f [py call b.fetchall]
{1 5} {7 9}
%
% puts "a: $a, b: $b, c: $c, d: $d, e: $e, f: $f"
a: , b: 15, c: someinput, d: 0.0625, e: {"t\"est": "11{24", "6": "5"}, f: {1 5} {7 9}

FROM PYTHON

Reference:

example python session:

>>> import tclpy
>>> a = tclpy.eval('list 1 [list 2 4 5] 3')
>>> print a
1 {2 4 5} 3

UNIX BUILD

It is assumed that you

The build process fairly simple:

On Ubuntu the default tclConfig.sh path is correct:

$ sudo apt-get install -y python-dev tcl-dev
$ cd libtclpy
$ make

For other distros you may need give the path of tclConfig.sh. E.g. CentOS 6.5:

$ sudo yum install -y python-devel tcl-devel make gcc
$ cd libtclpy
$ make TCLCONFIG=/usr/lib64/tclConfig.sh

Now try it out:

$ TCLLIBPATH=. tclsh
% package require tclpy
0.3
% py import random
% py call random.random
0.507094977417

TESTS

Run the tests with

$ make test

GOTCHAS

  1. Be very careful when putting unicode characters into a inside a py eval call - they are decoded by the tcl parser and passed as literal bytes to the python interpreter. So if we directly have the character "ಠ", it is decoded to a utf-8 byte sequence and becomes u"\xe0\xb2\xa0" (where the \xXY are literal bytes) as seen by the Python interpreter.
  2. Escape sequences (e.g. \x00) inside py eval may be interpreted by tcl - use {} quoting to avoid this.

TODO

In order of priority: