Ошибка автоматизации JMP 9 - обходные пути?

Я использую 64-битную JMP 9.0.3 под Windows 7 и автоматизирую ее из Python (РЕДАКТИРОВАТЬ: я подтвердил, что ошибка может быть в равной степени воспроизведена с помощью автоматизации VBScript, и все еще существует в JMP 11.0.0). Мой код автоматизации основан на Руководстве по автоматизации JMP 9. Все файлы JMP9 PDF, похоже, исчезли с сайта.

Этот баг становится для меня настоящей заглушкой. Мне довольно часто приходится манипулировать таблицами в коде автоматизации, а затем обмениваться именами таблиц с кодом JSL, и эта ошибка делает невозможным надежную работу. Кто-нибудь еще сталкивался с этим? Любые известные исправления или обходные пути?

(Я не видел много вопросов о JMP/JSL по Stackru, но я публикую здесь о том, что есть некоторые скрывающиеся от использования JMP скрытности. Первоначально опубликовано на форуме SAS по JMP: https://community.jmp.com/message/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

1 ответ

Решение

Я нашел обходной путь, но он мучительно неловкий. Чтобы получить имя таблицы автоматизации, я теперь делаю это:

  1. Получить имена всех таблиц JMP в списке, запустив код JSL.
  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
Другие вопросы по тегам