I am using Python to unit test Excel macros. When testing the following macro I need to pass a dictionary object to it.
code in testDict.xlsm:
Function GetItemCount(dict As Variant) As Integer
GetItemCount = dict.Count
End Function
My test code looks like this and is based on test_dict.py in the comtypes project:
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
When running the test, TypeError is raised.
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\[..]\AppData\Local\Temp\gen_py\3.9\00020813-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\[..]\venv\lib\site-packages\win32com\client\__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.
I have tried removing dynamic=True
from the call to CreateObject. Then the test runs, but I get an exception in Excel:
Run-time error '424':
Object required
When debugging in the Excel VBA IDE and running TypeName(dict), the result is "Variant()".
How do I pass the dictionary to the macro in a way that it is properly recognized?
As a workaround I will attempt to generate the dictionary in a macro, return it to Python and pass it to the macro that I want to test. I would however like to avoid this convoluted method if possible.
The code above is mixing two different libraries for creating COM objects.
Replace
with
and dispense with comtypes, unless it is needed for some other feature.