我在Windows 7下使用JMP 9.0.3 64位,并从Python中自动执行它(EDIT:我已经确认,使用VBScript自动化同样可以重现该错误,并且在JMP 11.0.0中仍然存在)。我的自动化代码基于JMP 9 automation Guide。所有JMP9 PDF现在似乎都从网站上消失了。
这个错误正在成为我的一个障碍。我经常需要在自动化代码中操作表,然后用JSL代码交换表名,而这个错误使我无法可靠地做到这一点其他人遇到过吗?有已知的修复或解决方法吗
(我在StackOverflow上没有看到很多JMP/JSL问题,但我在这里发帖是为了避免出现一些使用潜伏器的JMP。最初发布在SAS的JMP论坛上:https://community.jmp.com/message/213132#213132)
问题
Document
自动化对象具有属性Name
、FullName
和Path
,这些属性应该反映相关联的JMP表的表名或文件名。然而,在许多情况下,这些属性都是空的,尽管表有一个非空名称,可以从JSL代码、和访问,尽管事实上可以使用这个名称检索表自动化对象。
演示代码
下面是一些Python代码来演示这个错误。它使用JSL创建一个表,保存该表的名称,并按名称查找表的自动化对象。然后它检查table.Document.Name
是否与表的已知名称匹配——这只是用来查找它的--并报告不适用的情况。它这样做了100次,通常在前2-4次迭代后,名称开始变为空白:
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)
典型输出:
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
我想出了一个变通办法,但这是一个非常尴尬的办法。为了获得自动化表的名称,我现在这样做:
- 通过运行JSL代码获取列表中所有JMP表的名称
- 使用
app.GetJSLValue
将此列表导入自动化应用程序 - 逐个循环浏览名称列表,使用
app.GetTableHandleFromName
按名称查找自动化表对象 - 然后,我
使用丑陋的拼凑来将每个表的OLE对象标识与目标表的OLE目标标识进行比较。如果它们匹配,我会返回我用来查找的名称
我可怕的丑陋解决方案的代码:
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