JMP9自动化错误——解决方法



我在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自动化对象具有属性NameFullNamePath,这些属性应该反映相关联的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

我想出了一个变通办法,但这是一个非常尴尬的办法。为了获得自动化表的名称,我现在这样做:

  1. 通过运行JSL代码获取列表中所有JMP表的名称
  2. 使用app.GetJSLValue将此列表导入自动化应用程序
  3. 逐个循环浏览名称列表,使用app.GetTableHandleFromName按名称查找自动化表对象
  4. 然后,我使用丑陋的拼凑来将每个表的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

最新更新