JMP 9自动化错误 - 解决方法?

时间:2014-09-26 17:16:17

标签: python-2.7 win32com com+ sas-jmp jsl

我在Windows 7下使用64位JMP 9.0.3并从Python自动化它(编辑:我已经确认可以使用VBScript自动化同样重现该错误,仍然存在于JMP 11.0.0中)。我的自动化代码基于 JMP 9自动化指南。所有JMP9 PDFs seem now to have disappeared from the website

这个bug对我来说变得非常有吸引力。我经常需要在自动化代码中操作表,然后用JSL代码交换表名,这个bug使得无法可靠地执行此操作。 还有其他人遇到过吗?任何已知的修复或解决方法?

(我还没有在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 个答案:

答案 0 :(得分:0)

我想出了一个解决方法,但这是一个令人难以忍受的尴尬。为了获得自动化表的名称,我现在这样做:

  1. 通过运行JSL代码获取列表中所有JMP表的名称。
  2. 使用app.GetJSLValue将此列表添加到自动化应用程序中。
  3. 逐个遍历名称列表,使用app.GetTableHandleFromName按名称查找自动化表对象
  4. 然后我use an ugly kludge to compare the OLE object identity of each table到目标表的OLE对象标识。如果匹配,我会返回我用来查找的名称。
  5. 我可怕的丑陋工作的代码:

    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