Документ взят из кэша поисковой машины. Адрес
оригинального документа
: http://www.apo.nmsu.edu/35m_operations/TUI/Scripts/ScriptingManual.html
Дата изменения: Tue Sep 22 21:29:34 2015 Дата индексирования: Sun Apr 10 02:08:04 2016 Кодировка: Поисковые слова: п п п п п п п п |
TUI scripts are a way to automate tasks you perform frequently.
Scripts are written in Python. If you are not familiar with python, I strongly recommend the python tutorial at Python's home. A knowledge of python's basics will make script writing much easier.
Once you have the basics of python, I recommend looking through the Scripting Tutorial. It offers many simple example scripts. Other scripts may be found in <tui_root>/TUI/Scripts.
A TUI script must be a text file whose name ends in ".py". The file must include either a ScriptClass class or a run function. I strongly suggest you use a ScriptClass for all but the very simplest of scripts.
A class with the following special methods:
run(sr)
) ends for any reason, whether it succeeded, failed or was cancelled. It may NOT contain a "yield", and thus may not wait for anything.
In addition, ScriptClass may contain any other methods and any variables you like. For examples, see the Scripting Tutorial.
For very simple scripts, you may prefer to just define a run(sr)
function. Your script may also contain init(sr)
and/or end(sr)
functions, and all work the same as the ScriptClass methods discussed above. However, if your script needs init and/or end, I strongly recommend writing it as a ScriptClass, so data can more easily be passed around.
To report an error, raise sr.ScriptError
. For example:
def run(sr): ... if expTime <= 0: raise sr.ScriptError("Specify exposure time")
This will print the specified message to the status bar and halt the script. Other exceptions do this, as well, but also print a traceback to the error log. Thus other exceptions are ideal for internal bug checks, but sr.ScriptError
is best for reporting "normal" errors.
The run
function (as well as init
and end
, if supplied) is passed a ScriptRunner object. This script runner provides support for your script, including:
init
, run
and end
functions.
The following methods wait, so a yield is required:
getKeyVar(keyVar, ind, defVal)
Return the current value of a keyword variable.
Note: if you want to be sure the keyword data was in response to a particular command that you sent, then use the keyVars argument of startCmd or waitCmd, instead.
Inputs:
keyVar
: the keyword variable of interestind
: the index of the desired value. If None then the whole list of values is returned.defVal
: the default value to return if the keyVar's data is invalid (this can happen if it was not supplied by the hub since the last time you connected). If defVar is omitted then the script fails if the keyVar's data is invalid.A keyword variable contains data read from an instrument, the telescope or other "actor". Although you can create your own keyword variables, you rarely have to do so. Every actor has an associated model in TUI containing most or all of the useful keyword variables for that device.
Every keyword variable contains a list of 0 or more values. Often you only want one particular value. Thus the "ind" argument.
See also waitKeyVar, which can wait for a value.
showMsg(msg, severity=RO.Constants.sevNormal)
Display a message on the status bar.
Inputs:
msg
: string to display, without a final "\n"severity
: one of RO.Constants.sevNormal (default), sevWarning or sevErrorNote that the status bar also shows the execution status of the script; for instance it says "Done" when the script finishes successfully. If you want more permanent output, consider adding a text or label widget and writing your message to that.
startCmd( actor = "", cmdStr = "", timeLim = 0, callFunc = None, callTypes = RO.KeyVariable.DoneTypes, timeLimKeyword = None, abortCmdStr = None, keyVars = None, checkFail = True, )
Start a command using the same arguments as waitCmd.
Returns a command variable that you can wait for using waitCmdVars.
waitCmd( actor="", cmdStr = "", timeLim = 0, callFunc=None, callTypes = RO.KeyVariable.DoneTypes, timeLimKeyword = None, abortCmdStr = None, keyVars = None, checkFail = True, )
Start a command and wait for it to finish. A yield is required. If you want to read any data that must only be in response to this command and no other then be sure to use the
keyVars
argument.Inputs:
actor
: the name of the device which issued the keywordcmdStr
: the command; no terminating \n wantedtimeLim
: maximum time before command expires, in sec; 0 for no limit (which is normally what you want).callFunc
: rarely needed; see RO.KeyVariable.CmdVar for detailscallTypes
: rarely needed; see RO.KeyVariable.CmdVar for detailstimeLimKeyword
: rarely needed; see RO.KeyVariable.CmdVar for detailsabortCmdStr
: a command string that will abort the command. This string is sent to the actor if the command is aborted, e.g. if the script is cancelled while the command is executing.keyVars
: a sequence of 0 or more keyword variables to monitor. Any data for those variables that arrives in response to this command is saved and can be retrieved using cmdVar.getKeyVarData or cmdVar.getLastKeyVarData, where cmdVar is returned in sr.value.checkFail
: check for command failure? If True (the default) command failure will halt your script.See also startCmd and waitCmdVars.
Wait for one or more command variables (returned by startCmd) to finish. A yield is required.
Inputs:
cmdVars
: one or more commands (RO.KeyVariable.CmdVar)Returns successfully once all commands succeed, but fails as soon as any command fails.
waitKeyVar(keyVar, ind=0, defVal=Exception, waitNext=False)
Get data from a keyword variable. A yield is required.
Inputs:
- keyVar keyword variable
- ind which value is wanted? (None for all values)
- defVal value to return if value cannot be determined (if omitted, the script halts)
- waitNext if True, ignores the current value and waits for the next transition.
The data is returned in sr.value.
If the value is currently unknown or if waitNext is true, wait for the variable to be updated.
See also getKeyVar (which does not wait).
Wait for a period of time specified in milliseconds. A yield is required.
Inputs:
msec
number of milliseconds to pause
waitThread(func, *args, **kargs)
Run a function as a background thread and wait for completion. A yield is required.
Inputs:
func
: the function to run as a background thread- any additional arguments are passed to func
Any value returned by func is put into sr.value.
Warning: func must NOT interact with Tkinter widgets or variables (not even reading them) because Tkinter is not thread-safe. (The only thing I'm sure a background thread can safely do with Tkinter is generate an event, a technique that is used to detect end of thread).
For more information, see RO.ScriptRunner.
Whenever your script calls an sr.wait... function (i.e. wants to wait for anything), it must use yield, as in:
yield sr.wait...(...)
This is a painful, but it could be much worse. Most languages would force you to break code into many small functions, each of which is registered as a separate callback function. That sort of programming is fine for GUIs (and is used extensively in TUI), but it is not a nice way to write a script.
If you forget the "yield", your script will plow ahead instead of waiting, which is a recipe for trouble. However, TUI will catch this problem the next time you use an sr.wait...() function, at which point it will kill your script, print a message to the status bar and print details to the error log.
Repetitive tasks can be separated out into sub-tasks. If you find your script running the same bit of code more than once, you may want to move that bit into a separate function.
To execute a sub-task that contains yield
you must use yield
. To remind yourself, I suggest using a name that starts with "wait". For example:
class ScriptClass(object): def run(self, sr): #... yield self.waitDumbTask(sr, 3, 1000) #... def waitDumbTask(self, sr, nreps, dtime): for n in range(nreps): sr.showMsg("Wait %d" % n) yield sr.waitMS(dtime)
Only call a function with yield
if the function contains yield
. Note that __init__
and end
cannot contain yield
(cannot wait), so they cannot call functions that contain yield
.
To make a script show up in the Scripts menu, put it into TUIAdditions/Scripts (or a subdirectory of that). If TUIAdditions or TUIAdditions/Scripts doesn't exist, create it. Details:
TUIAdditions/Scripts/NICFPS/Dither/foo.py
will show up under Scripts as NICFPS>Dither>foo
.
The script runner includes a basic debug mode which is enabled by putting sr.debug = True
in your script. In debug mode, getKeyVar
, startCmd
and all the wait...
commands print a diagnostic message to the error log when they run. Also:
To reload a script (i.e. after modifying it), select Reload from the contextual pop-up menu for any of the control buttons (Start, Pause or Cancel).
Warnings:
print statements will print to to the error log. sr.showMsg is an alternative if standard output is not convenient for your platform.
APO Documentation contains pointers to manuals for the various instruments, the hub and the TCC.
The manual TUI Programming contains much information about the internals of TUI. Some of it is made simpler by using the scripting interface, but much of it is relevant -- especially if you want your script to use widgets (i.e. for user input or output).