Author Topic: Подписка на событие в скрипте на pythonе  (Read 255 times)

Offline sth

  • Registered User
  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
Добрый день.
Попробовал использовать python для написания скриптов для HE
Установил python, pywin32
начал с простого - примеров в документации.
пример test.pys с кодом alert("Hello HippoEDIT!") - работает
далее попробовал подписаться на событие. Опять же по примеру из документации. Конечно doc_save_handler.js с кодом
    function myDocumentSaveHandler() {
        alert("Some document was Saved!");
    }
    Application.onNewDocument = myDocumentSaveHandler;

прекрасно работает

далее python
примера нет, поэтому сделал так:

def myDocumentSaveHandler():
    alert("Some document was Saved!");

Application.onNewDocument = myDocumentSaveHandler;

при запуске этого кода получаю трассировку:
Traceback(most recent call last): File "<Script Block >", line 4, in <module>  Application.onNewDocument = myDocumentSaveHandler; File "...\Python\Python36\Lib\site-packages\win32comext\axscript\client\pyscript.py", line 113 in __setattr__ return setattr(self.__scriptItem__.dispatchContainer, attr, value)
File "...\Python\Python36\Lib\site-packages\win32com\client\dynamic.py", line 575 in __setattr__ self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
TypeError: Objects of type 'function' can not be converted to a COM VARIANT

может быть есть какие-то особенности использования pythona именно с событиями? Или это проблема уже pywin32?

Offline alex

  • Developer
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2214
  • Karma: +37/-3
    • HippoEDIT
Блин, я когда то попробовал скриптинг с Python, написал "tutorial" и забыл :)
Так что, я тот еще эксперт...
Но все что в моих силах, со стороны HippоEDIT сделаю.

Похоже что это больше трабла Python как такового. Ошибка понятна.

Подписка на события в HippoEDIT это в общем то установка callback на функцию из скрипта.
Переменная Application которая принимает call back, имеет тип COM VARIANT (такой COM тип принимающий все).
Так как у python пожестче с типами, он не может делать implicit type conversion.
Надо попробовать сконвертить вручную. Нашел вот такой совет (еще сам не попробовал)

https://stackoverflow.com/questions/24345405/com-object-variant-parameters-in-comtypes-python

Т.е., как я понимаю:
Code: Python
  1. from ctypes import *
  2. from comtypes import automation
  3.  
  4. def myDocumentSaveHandler():
  5.     alert("Some document was Saved!");
  6.  
  7. Application.onNewDocument = automation.VARIANT(myDocumentSaveHandler)
  8.  
« Last Edit: May 08, 2018, 11:36:20 AM by alex »

Offline sth

  • Registered User
  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
Да, очевидно это особенности pythona

вот следующий код. Выполняется в IDLE, вовсе не в HE
>>> def t():
   pass

>>> print(type(t))
<class 'function'>
>>> from comtypes import automation
>>> automation.VARIANT(t)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    automation.VARIANT(t)
  File "...\Python\Python36\lib\site-packages\comtypes\automation.py", line 187, in __init__
    self.value = args[0]
  File "...\Programs\Python\Python36\lib\site-packages\comtypes\automation.py", line 365, in _set_value
    raise TypeError("Cannot put %r in VARIANT" % value)
TypeError: Cannot put <function t at 0x0000000001D11E18> in VARIANT
>>>
то есть нужно привести функцию pythona к com variant, а не получается

вот часть кода из automation.py (как раз та самая функция _set_value_, где исключение)

        elif isinstance(value, VARIANT):
            _VariantCopy(self, value)
        elif isinstance(value, c_ubyte):
            self._.VT_UI1 = value
            self.vt = VT_UI1
        elif isinstance(value, c_char):
        .....
        elif isinstance(value, _Pointer):
            ref = value.contents
            self._.c_void_p = addressof(ref)
            self.__keepref = value
            self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
        else:
            raise TypeError("Cannot put %r in VARIANT" % value)

непонятно чем не устраивает isinstance(value, VARIANT) ....

ну ладно.

спасибо за такую оперативную реакцию на мои сообщения.
« Last Edit: May 08, 2018, 01:10:13 PM by sth »

Offline alex

  • Developer
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2214
  • Karma: +37/-3
    • HippoEDIT
Надо в документации к pywin32 покопаться. Точно должно что то быть.
Как то же должно быть возможно вызвать функцию из Python.
Если найдем, смогу написать вспомогательный обьект для python который поможет оборачивать функцию, для передачи в COM VARIANT.

Это конечно, если поддержка Python предпочтительней JavaScript.
Нужно учитывать еще, что в ActiveScripting все еще используется старый JavaScript, так что python может быть быстрее.

Offline sth

  • Registered User
  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
попробую почитать документацию на pywin32. По мере наличия свободного времени.
А там видно будет.

Offline sth

  • Registered User
  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
вот что начитал в доке к pywin32 про variant

The VARIANT object lives in win32com.client. The constructor takes 2 parameters - the 'variant type' and the value. The 'variant type' is an integer and can be one or more of the pythoncom.VT_* values, possibly or'd together.
For example, to create a VARIANT object which defines a byref array of 32bit integers, you could use:

>>> from win32com.client import VARIANT
>>> import pythoncom
>>> v = VARIANT(pythoncom.VT_BYREF | pythoncom.VT_ARRAY | pythoncom.VT_I4,
...             [1,2,3,4])
>>> v
win32com.client.VARIANT(24579, [1, 2, 3, 4])

пробовал делать как описано. Использовал несколько разных значений констант VT_* (не все конечно, а показавшихся мне наиболее подходящими по смыслу), и в IDLE исключений не было.
но при попытке сделать то же самое в примере в HE получил в некоторых случаях ту же диагностику, что и ранее, а в части случаев тоже исключение, но другое

Offline alex

  • Developer
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2214
  • Karma: +37/-3
    • HippoEDIT
Да я седня тоже подядочно покопался (в документации и примерах в инете), но пока без результатно.
Правильным и ожидаемым со стороны HippoEDIT должен быть (как приходит от JavaScript):
 v = VARIANT(pythoncom.VT_DISPATCH, myDocumentSaveHandler)
но это не работает, потому как Python funciton не матчит свою внутреннюю функцию на IDispatch.

Искал вообще примеры как передать Python function object в COM, но пока ничего не нашел.
Тема старая  и похоже не сильно используемая.