I'm using JMP 9.0.3 64-bit under Windows 7 and automating it from Python (EDIT: I've confirmed that the bug can equally be reproduced with VBScript automation, and still exists in JMP 11.0.0). My automation code is based on the JMP 9 Automation Guide. All the JMP9 PDFs seem now to have disappeared from the website.
This bug is becoming quite a show-stopper for me. I quite frequently need to manipulate tables in automation code and then exchange the table names with JSL code, and this bug makes it impossible to do so reliably. Has anyone else encountered it? Any known fixes or workarounds?
(I haven't seen many JMP/JSL questions on StackOverflow, but I'm posting here on the off-chance that there are some JMP-using lurkers. Originally posted on SAS's JMP forum: https://community.jmp.com/message/213132#213132)
the Document
automation object has properties Name
, FullName
, and Path
which are supposed to reflect the table name or file name of the associated JMP table. However, in many cases these properties turn out to be blank, despite the table having a non-blank name which can be accessed from JSL code, and despite the fact that the table automation object can in fact be retrieved using this name.
Here's some Python code that demonstrates the bug. It creates a table using JSL, saves the name of this table, and looks up the table's automation object by name. It then checks whether table.Document.Name
matches the known name of the table--which was just used to look it up!--and reports the cases where this doesn't hold. It does this 100 times and typically the name starts coming back blank after the first 2-4 iterations:
from win32com.client import gencache
mod = gencache.GetModuleForProgID("JMP.Application")
app = mod.Application()
okay_table = [None]*100
for ii in range(len(okay_table)):
# Create a table in JMP
app.RunCommand("show(%d); ::dt=New Table(); ::retval=dt<<Get Name()" % ii)
# Retrieve the name of that just-created table from the JSL variable
retval = app.GetJSLValue("retval")
# Retrieve the automation object for that table, by name
table = app.GetTableHandleFromName(retval)
# Now, table.Document.Name **SHOULD** match retval, but
# it may be blank due to the bug.
if not any((table.Document.Name, table.Document.Path, table.Document.FullName)):
print "table %d: got blank table.Document.Name=%s, Path=%s, FullName=%s" % (ii,
table.Document.Name, table.Document.Path, table.Document.FullName)
app.RunCommand("close(DataTable(::retval), nosave)")
okay_table[ii]=False
else:
print "table %d: looks okay; Name=%s, FullName=%s, Path=%s" % (ii,
table.Document.Name, table.Document.FullName, table.Document.Path)
app.RunCommand('close(DataTable("%s"), nosave)' % table.Document.Name)
okay_table[ii]=True
print "Number of bad tables: %d" % okay_table.count(False)
Typical output:
table 0: looks okay; Name=Untitled 304, FullName=Untitled 304.jmp, Path=Untitled 304.jmp
table 1: looks okay; Name=Untitled 305, FullName=Untitled 305.jmp, Path=Untitled 305.jmp
table 2: got blank table.Document.Name=, Path=, FullName=
table 3: got blank table.Document.Name=, Path=, FullName=
table 4: got blank table.Document.Name=, Path=, FullName=
...
table 98: got blank table.Document.Name=, Path=, FullName=
table 99: got blank table.Document.Name=, Path=, FullName=
Number of bad tables: 98
I've come up with a workaround, but it's an excruciatingly awkward one. In order to get the name of an automation table, I now do this:
app.GetJSLValue
to get this list into the automating application.app.GetTableHandleFromName
Code for my horrible ugly workaround:
def GetTableName(app, table):
if table.Document.Name:
return table.Document.Name
else:
# Get names of all JMP tables
app.RunCommand("""
NamesDefaultToHere(1);
::_retval={};
for(ii=1, ii<=NTable(), ii++,
InsertInto(::_retval, DataTable(ii)<<GetName())
)""")
tns = app.GetJSLValue("_retval")
# See this thread for why == works here (http://thread.gmane.org/gmane.comp.python.windows/12977/focus=12978)
for tn in tns:
if table == self.app.GetTableHandleFromName(tn)
return tn
else:
raise Exception