Передать словарь в макрос Excel с помощью win32com и comtypes

#python #excel #com #win32com #comtypes

Вопрос:

Я использую Python для модульного тестирования макросов Excel. При тестировании следующего макроса мне нужно передать ему объект словаря.

код в файле testDict.xlsm:

 Function GetItemCount(dict As Variant) As Integer
    GetItemCount = dict.Count
End Function
 

Мой тестовый код выглядит следующим образом и основан на test_dict.py в проекте comtypes:

test_comtypes_w_dict.py

 from comtypes.client import CreateObject
import win32com.client as win32

d = CreateObject("Scripting.Dictionary", dynamic=True)

d.Add("Test", "An item")

filename = 'testDict.xlsm'
xl = win32.Dispatch("Excel.Application")
wb = xl.Workbooks.Open(filename)
count = xl.Application.Run(filename '!Module1.GetItemCount', d)

assert count == 1
 

При запуске теста возникает ошибка ввода.

 Traceback (most recent call last):
    File "C:Users[..]test_comtypes_w_dict.py", line 11, in <module>
        count = xl.Application.Run(filename '!Module1.GetItemCount', d)
    File "C:Users[..]AppDataLocalTempgen_py3.90020813-0000-0000-C000-000000000046x0x1x9.py", line 44654, in Run
        return self._ApplyTypes_(259, 1, (12, 0), ((12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17), (12, 17)), 'Run', None,Macro
File "C:Users[..]venvlibsite-packageswin32comclient__init__.py", line 467, in _ApplyTypes_
        self._oleobj_.InvokeTypes(dispid, 0, wFlags, retType, argTypes, *args), TypeError: Objects for SAFEARRAYS must be sequences (of sequences), or a buffer object.
 

Я попытался удалить dynamic=True из вызова CreateObject. Затем запускается тест, но я получаю исключение в Excel:

Ошибка во время выполнения «424»:

Требуемый объект

При отладке в среде IDE Excel VBA и запуске TypeName(dict) результатом является «Variant ()».

Как передать словарь макросу таким образом, чтобы он был правильно распознан?

В качестве обходного пути я попытаюсь сгенерировать словарь в макросе, вернуть его в Python и передать макро, который я хочу протестировать. Однако я хотел бы по возможности избежать этого запутанного метода.

Комментарии:

1. Если это не глупый вопрос, то почему вы используете два разных метода (comtypes и win32com) для создания интерфейсов отправки? Если вместо вызова CreateObject я использую win32.dispatch(«Сценарии. Словарь»), моя версия вашего кода работает нормально, правильно передает словарь в тестовую функцию Excel и возвращает количество 1.

2. @DS_London Не глупый вопрос. Я начал с win32com, но не нашел в нем CreateObject. Входит ли это в стоимость?

3. Вы уже используете метод …. метод win32.Dispatch() либо создает новый объект, либо присоединяется к уже запущенному.

Ответ №1:

Приведенный выше код смешивает две разные библиотеки для создания COM-объектов.

Заменять

 d = CreateObject("Scripting.Dictionary", dynamic=True)
 

с

 d = win32.Dispatch('Scripting.Dictionary')
 

и обойдитесь без типов com, если это не требуется для какой-либо другой функции.