Ошибка автоматизации 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 ответ
Я нашел обходной путь, но он мучительно неловкий. Чтобы получить имя таблицы автоматизации, я теперь делаю это:
- Получить имена всех таблиц JMP в списке, запустив код JSL.
- использование
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