#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, если это не требуется для какой-либо другой функции.