Tcl Calls¶
Note
This section assumes that you know Tcl. You may have learned some of it while using teek, but something like Learn Tcl in Y Minutes might be useful for you.
Teek does most things by calling commands in Tcl. You can also call Tcl commands yourself, which is useful if you want to do something that can be done in Tcl, but there is no other way to do it in teek.
There are two functions for doing this:
-
teek.
tcl_eval
(returntype, code)[source]¶ Run a string of Tcl code.
>>> teek.tcl_eval(None, 'proc add {a b} { return [expr $a + $b] }') >>> teek.tcl_eval(int, 'add 1 2') 3 >>> teek.tcl_call(int, 'add', 1, 2) # usually this is better, see below 3
-
teek.
tcl_call
(returntype, command, *arguments)[source]¶ Call a Tcl command.
The arguments are passed correctly, even if they contain spaces:
>>> teek.tcl_eval(None, 'puts "hello world thing"') # 1 arguments to puts # doctest: +SKIP hello world thing >>> message = 'hello world thing' >>> teek.tcl_eval(None, 'puts %s' % message) # 3 args to puts, tcl error Traceback (most recent call last): ... teek.TclError: wrong # args: should be "puts ?-nonewline? ?channelId? string" >>> teek.tcl_call(None, 'puts', message) # 1 arg to puts # doctest: +SKIP hello world thing
Both of these functions are ran so that they have access to Tcl’s global variables, and if they create more variables, they will also be global.
The None
means that the return value is ignored, and int
means that
it’s converted to a Python integer. There are more details about these
conversions below.
Tcl errors always raise the same Python exception:
Data Types¶
Everything is a string in Tcl. Teek converts Python objects to strings and strings to Python objects for you, but you need to tell teek what types of values you want to get. This section describes how.
Python to Tcl conversion¶
Arguments passed to tcl_call()
are handled like this:
- Strings are passed to Tcl as is.
- If the argument is None, an empty string is passed to Tcl because Tcl uses an empty string in many places where Python uses None.
- If the argument is a dictionary-like object (more precisely,
collections.abc.Mapping
), it is turned into a list of pairs. This is because{'a': 'b', 'c': 'd'}
and['a', 'b', 'c', 'd']
are represented the same way in Tcl. True
andFalse
are converted to1
and0
, respectively.- Integers, floats and other real numbers (
numbers.Real
) are converted to strings withstr()
. - If the value has a
to_tcl()
method, it’s called with no arguments. It should return a string that will be passed to Tcl. - Anything else is treated as an iterable. Every element of the iterable is converted as described here, and the result is a Tcl list.
Conversions should raise ValueError
or TclError
when they
fail.
Type Specifications¶
Teek also has type specifications for converting from a Tcl object to a Python object. Here is a list of valid type specifications:
str
(that is, literallystr
, not e.g.'hello'
) means that a string is returned.None
means that the value will be ignored entirely, and the Python value is always None.bool
means that the value is treated as a Tcl boolean. All valid Tcl booleans specified in Tcl_GetBoolean(3tcl) are supported.int
,float
or any other subclass ofnumbers.Real
means that the value will be converted to that class by first converting to string as ifstr
was used, and then calling the class with the stringed value as an argument. However, if the stringed value is the empty string, None is returned and the class isn’t called.- If the type specification is a class with a
from_tcl()
classmethod, that will be called with one argument, the value converted to a string. If the stringed value is an empty string, None is returned andfrom_tcl()
is not called.
The type specifications can be also combined in the following ways. These
examples use str
, int
and float
, but all other valid specifications
work as well. The return types can be nested arbitrarily; for example,
[(int, float)]
means a value like [(12, 3.4), (56, 7.8)]
.
[str]
means a list of strings, of any length.(str, int)
means a tuple of a string followed by an integer. This allows you to create a sequence with different kinds of items in it. For example,(str, str, str)
is like[str]
except that it also makes sure that the length of the result is 3, and returns a tuple instead of a list.{'a': int, 'b': float}
means a dictionary with string keys. If the Tcl dictionary happens to have a key nameda
orb
, it is converted toint
orfloat
respectively; other keys will be strings. This means that{}
is a dictionary with all keys as strings and values as integers. There is no way to work with dictionaries that have non-string keys.
Examples:
>>> teek.tcl_call([str], 'list', 'a', 'b', 'c')
['a', 'b', 'c']
>>> teek.tcl_call((str, int, float), 'list', 'hello', '3', '3.14')
('hello', 3, 3.14)
>>> teek.tcl_call([bool], 'list', 'yes', 'ye', 'true', 't', 'on', '1')
[True, True, True, True, True, True]
>>> teek.tcl_call({}, 'dict', 'create', 'a', 1, 'b', 2) # doctest: +SKIP
{'a': '1', 'b': '2'}
>>> teek.tcl_call([str], 'list', 123, 3.14, None, 'hello')
['123', '3.14', '', 'hello']
Creating Tcl Commands¶
It’s possible to create Tcl commands that Tcl code can call. For example, when
a button is clicked, Tcl invokes a command that the Button
class
created with create_command()
.
-
teek.
create_command
(func, arg_type_specs=(), *, extra_args_type=None)[source]¶ Create a Tcl command that calls
func
.Here is a simple example:
>>> tcl_print = teek.create_command(print, [str]) # calls print(a_string) >>> tcl_print # doctest: +SKIP 'teek_command_1' >>> teek.tcl_call(None, tcl_print, 'hello world') hello world >>> teek.tcl_eval(None, '%s "hello world"' % tcl_print) hello world
Created commands should be deleted with
delete_command()
when they are no longer needed.The function will take
len(arg_type_specs)
arguments, and the arguments are converted to Python objects usingarg_type_specs
. Thearg_type_specs
must be a sequence of type specifications.If
extra_args_type
is given, the function can also take more thanlen(arg_type_specs)
arguments, and the type of each extra argument will be extra_args_type. For example:>>> def func(a, b, *args): ... print(a - b) ... for arg in args: ... print(arg) ... >>> command = teek.create_command(func, [int, int], extra_args_type=str) >>> teek.tcl_call(None, command, 123, 23, 'asd', 'toot', 'boom boom') 100 asd toot boom boom
The return value from the Python function is converted to a string for Tcl.
If the function raises an exception, a traceback will be printed. However, the Tcl command returns an empty string on errors and does not raise an error in Tcl. Be sure to return a non-empty value on success if you want to do error handling in Tcl code.
-
teek.
delete_command
(name)[source]¶ Delete a Tcl command by name.
You can delete commands returned from
create_command()
to avoid memory leaks.