Open liviofetahu-betm opened 2 weeks ago
Another important note: regardless of the Python function arguments' types, the VBA Macro cannot be run when disabling the setting *WorkbookModule=".py"** in the xlOil.ini file. The reproducing code example I provided above simply happened to pick a case when the function takes kwargs. The same issue still occurs when the function argument is a pandas DataFrame, string etc.
This seems to be a limitation in Excel.
If no arguments are needed it is possible to call a global macro without quotes, however, if quotes or arguments are passed, Excel needs the macro to be defined in VBA. The "WorksheetModule" setting causes VBA stubs to be generated in the associated worksheet when a companion py file is found which explains why things work with this enabled.
One workaround is to define macros without arguments. It may also be possible to create VBA stubs in a xla addin to keep Excel happy.
Thanks for looking into this, Steven. This is one of the typical use cases of xloil
within my team.
So far, I'm keeping the setting *WorkbookModule=".py"** enabled, and I execute the macro with user-defined arguments in the workbook with the same name as the Python file.
Do you think there might be space within the xloil
library/framework for implementing logic that can globally (a.k.a. disabling *WorkbookModule=".py"**) expose macros which take user-defined inputs? It would be quite handy for a user to open a workbook with any filename, and be able to execute the macro with user-defined arguments.
I tested my proposed workaround above (creating an xla file) and this does work. To replicate this xloil would need to dynamically create and load an xla/xlam file and populate it with vba stubs. This may be possible, I need to investigate further.
Thank you very much for looking into this, Steven!
This feature would be a huge plus to users who want to bring the full power of function signatures to global Excel sessions.
Actually there's a much simpler approach here. Create an xlam addin with this function:
Public Sub Invoke(func As String, ParamArray P() As Variant)
Select Case UBound(P) + 1
Case 0: Application.Run func
Case 1: Application.Run func, P(0)
Case 2: Application.Run func, P(0), P(1)
Case 3: Application.Run func, P(0), P(1), P(2)
Case 4: Application.Run func, P(0), P(1), P(2), P(3)
Case 5: Application.Run func, P(0), P(1), P(2), P(3), P(4)
Case 6: Application.Run func, P(0), P(1), P(2), P(3), P(4), P(5)
Case 7: Application.Run func, P(0), P(1), P(2), P(3), P(4), P(5), P(6)
Case 8: Application.Run func, P(0), P(1), P(2), P(3), P(4), P(5), P(6), P(7)
Case 9: Application.Run func, P(0), P(1), P(2), P(3), P(4), P(5), P(6), P(7), P(8)
Case 10: Application.Run func, P(0), P(1), P(2), P(3), P(4), P(5), P(6), P(7), P(8), P(9)
End Select
End Sub
Now you can run
'Invoke "write_single_kwarg_to_active_worksheet", [{"username","liviofetahu-betm";"",""}]'
Where this doesn't work is trying to assign a macro to a button - there seems to be a one argument limit.
Of course I can distribute the above addin with xlOil - I'll look into that for a future release
That would be great. We've continuously upgraded xloil
since we started implementing with it.
Our use case for globally-enabled macros was a function that took a pandas DataFrame, a string, and kwargs, which we were able to call like
'get_exposure Evaluate("A41:BV43"),"Annual",[{"target_date","2024-09-11";"",""}]'
when we used the setting *WorkbookModule=".py"**.
Are you able to test the above to see if it works for you?
Issue Description.
When one defines a Python function which takes input arguments and decorates it with
xloil.func(macro=True, command=True)
so that it can be executed as an Excel VBA Macro in a Macro-Enabled Worksheet File (.xlsm), one is forced to use the setting WorkbookModule="*.py" in the xlOil.ini file in order for the Python function to be exposed as an Excel VBA Macro successfully. If one needs this Python function to be exposed globally to Excel sessions (not just the workbook with the same filename as the Python module file), disabling the setting WorkbookModule="*.py" leads to the Python function not being recognized as a VBA Macro when one supplies the input arguments to the function in the Excel Developer Macros dialog box. The article at (https://www.teachexcel.com/excel-tutorial/1893/pass-arguments-to-a-macro-called-from-a-button-or-sheet-in-excel#:~:text=We%20must%20type%20in%20the,to%20send%20to%20the%20macro.&text=Note%3A%20the%20text%20is%20surrounded,surrounded%20by%20single%20quotation%20marks.) provides instructions on how to execute Excel VBA Macros which take input arguments from the Developer ribbon, Macros dialog box. Regarding the example given below, the full literal string to run the macro would be'write_single_kwarg_to_active_worksheet [{"username","liviofetahu-betm";"",""}]'
and note that the single quote characters at the beginning and at the end are required.Reproducing Code Example
Error message
When using the setting WorkbookModule="*.py" in the xlOil.ini file, the Run button in the Macros dialog box appears enabled and clicking it results in writing to the 2 cells in the active worksheet. However, when the setting WorkbookModule="*.py" is disabled, the Run button is still frozen even after typing the call to the function in the Macro name text box.
xloil/Python/Excel/Windows version information
0.19.1 / sys.version_info(major=3, minor=11, micro=3, releaselevel='final', serial=0) / Version 2407 Build 16.0.17830.20210 / 10.0.19045.4894