Creating Extensions
To create a Vocola extension, create a .py
file in the Vocola extension directory whose name starts with
"vocola_ext_". Define one or more top-level Python routines and then
add a special comment immediately before each of them that should be
callable from Vocola to tell Vocola that they are extension
functions/procedures and what name should be used to call them from
Vocola. Here's a simple example:
1 2 3 4 5 6 7 8 9 10 11
|
import os
# Vocola function: Env.Get
def get(name):
return os.environ[name]
# Vocola procedure: File.Append
def append(filename, line):
f = open(filename, 'a')
f.write(line + "\n")
f.close()
|
Here we have defined an extension function, Env.Get, with 1 argument that returns the value of
the environment variable with that name and an extension procedure,
File.Append, with 2 arguments that appends the
contents of its second argument to the file with the pathname of its
first argument. To keep the example simple, we have omitted any error
handling.
Vocola can usually infer how many arguments your routine takes, but
you must tell it explicitly when your routine takes a variable number of
arguments or your argument list takes up multiple lines. Here's another
example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
import os
# Vocola function: Env.Get,1-2
def get(name, if_undefined=None):
try:
return os.environ[name]
except KeyError:
if if_undefined!=None:
return if_undefined
else:
raise
# Vocola function: Math.Mult,0-
def product(*numbers):
p = 1
for n in numbers:
p = p * long(n)
return p
# Vocola function: Polynomial.Eval,3
def polynomial(x, y,
z):
# compute x^2 + 3y + z:
return long(x)**2 + long(y)*3 + long(z)
|
Here, we have an improved version of Env.Get that can take 1 or 2 arguments; if no
environment variable with the given name exists, then it throws a
runtime error unless it was given a second argument, in which case it
just returns that argument instead. The second function, Math.Mult, takes any number of arguments (even zero)
and multiplies them together. We had to explicitly give the number of
arguments (3) in the last case, Polynomial.Eval, only because its argument list is
spread across multiple lines.
Internally all values in Vocola 2 are strings. Extension routines
are passed strings (note the use of long(-) in
the second example to convert the arguments to long integers) and the
results of extension functions are converted back to strings via str(-).
Raising Exceptions
As you can see in the improved Env.Get
example, extensions can simply raise normal Python exceptions and Vocola
will treat them as a runtime error, stopping the current command
sequence and printing an error message to the Messages from NatLink
window. If you want to stop the current command sequence without
printing an error message (perhaps you have already printed your own
somewhere else), you can [as of version 2.8.5]
raise VocolaRuntimeAbort, which you import
from VocolaUtils.
Dealing with Python versions
Unfortunately, your extension will be run using the Python version
that NatLink is using. Today that is Python 2.7 for recent installers
but hopefully future installers will use a version of Python 3.
Accordingly, you should strive to make your extension work with both
Python 2.7 and recent versions of Python 3.
One complication is that Vocola strings are of
type str; in Python 2.7, this is a sequence of
Windows-1252 bytes while in Python 3 it is a string of Unicode
characters.
Note that while internally Vocola using Python 3 can pass around Unicode
strings, Dragon still does not understand non-Windows-1252 characters;
this means, for example, you will not be able to use them with
SendDragonKeys.
Modifying Extensions
Once Vocola has loaded an extension, it continues to use its loaded
version and thus will not see any changes you make to your extension.
To explicitly cause Vocola to load a new version of your extension, use
the "Load [Voice] Extensions" command. Note that that command does not
reload non-extension modules (i.e., modules whose name does not start
with vocola_ext_).