Skip to content

Commit 3db150a

Browse files
Development
+ Added variable arguments length UDFs + VBA7/64-bit `PtrSafe` bug fix in `xlpython.bas` + Bug fixes ericremoreynolds#12 and ericremoreynolds#14
1 parent ef25a0b commit 3db150a

File tree

5 files changed

+80
-32
lines changed

5 files changed

+80
-32
lines changed

addin/xlpython.xlam

971 Bytes
Binary file not shown.

addin/xlpython/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ def inner(f):
1515
xlf["xlwings"] = kwargs.get("xlwings", None)
1616
xlargs = xlf["args"] = []
1717
xlargmap = xlf["argmap"] = {}
18-
for vpos, vname in enumerate(f.__code__.co_varnames[:f.__code__.co_argcount]):
18+
nArgs = f.__code__.co_argcount
19+
if f.__code__.co_flags & 4: # function has an '*args' argument
20+
nArgs += 1
21+
for vpos, vname in enumerate(f.__code__.co_varnames[:nArgs]):
1922
xlargs.append({
2023
"name": vname,
2124
"pos": vpos,
@@ -24,7 +27,8 @@ def inner(f):
2427
"range": False,
2528
"dtype": None,
2629
"dims": -1,
27-
"doc": "Positional argument " + str(vpos+1)
30+
"doc": "Positional argument " + str(vpos+1),
31+
"vararg": True if vpos == f.__code__.co_argcount else False
2832
})
2933
xlargmap[vname] = xlargs[-1]
3034
xlf["ret"] = {

addin/xlpython/xlpython.bas

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,29 @@ Attribute VB_Name = "xlpython"
22
Option Private Module
33
Option Explicit
44

5-
#If win64 Then
6-
Const XLPyDLLName As String = "xlpython64-2.0.5.dll"
7-
Declare Function XLPyDLLActivate Lib "xlpython64-2.0.5.dll" (ByRef result As Variant, Optional ByVal config As String = "") As Long
8-
Declare Function XLPyDLLNDims Lib "xlpython64-2.0.5.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
5+
#If VBA7 Then
6+
#If win64 Then
7+
Const XLPyDLLName As String = "xlpython64-2.0.6.dll"
8+
Declare Function PtrSafe XLPyDLLActivate Lib "xlpython64-2.0.6.dll" (ByRef result As Variant, Optional ByVal config As String = "") As Long
9+
Declare Function PtrSafe XLPyDLLNDims Lib "xlpython64-2.0.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
10+
#Else
11+
Private Const XLPyDLLName As String = "xlpython32-2.0.6.dll"
12+
Private Declare PtrSafe Function XLPyDLLActivate Lib "xlpython32-2.0.6.dll" (ByRef result As Variant, Optional ByVal config As String = "") As Long
13+
Private Declare PtrSafe Function XLPyDLLNDims Lib "xlpython32-2.0.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
14+
#End If
15+
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
916
#Else
10-
Private Const XLPyDLLName As String = "xlpython32-2.0.5.dll"
11-
Private Declare Function XLPyDLLActivate Lib "xlpython32-2.0.5.dll" (ByRef result As Variant, Optional ByVal config As String = "") As Long
12-
Private Declare Function XLPyDLLNDims Lib "xlpython32-2.0.5.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
13-
#End If
14-
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
17+
#If win64 Then
18+
Const XLPyDLLName As String = "xlpython64-2.0.6.dll"
19+
Declare Function XLPyDLLActivate Lib "xlpython64-2.0.6.dll" (ByRef result As Variant, Optional ByVal config As String = "") As Long
20+
Declare Function XLPyDLLNDims Lib "xlpython64-2.0.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
21+
#Else
22+
Private Const XLPyDLLName As String = "xlpython32-2.0.6.dll"
23+
Private Declare Function XLPyDLLActivate Lib "xlpython32-2.0.6.dll" (ByRef result As Variant, Optional ByVal config As String = "") As Long
24+
Private Declare Function XLPyDLLNDims Lib "xlpython32-2.0.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
25+
#End If
26+
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
27+
#EndIf
1528

1629
Private Function XLPyFolder() As String
1730
XLPyFolder = ThisWorkbook.Path + "\xlpython"

addin/xlpython_xlam_vba_code.bas

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,20 @@ Sub ImportPythonUDFs(control As IRibbonControl)
139139

140140
f.Write ftype + " " + fname + "("
141141
first = True
142+
vararg = ""
143+
nArgs = Py.Len(Py.GetItem(xlfunc, "args"))
142144
For Each arg In Py.GetItem(xlfunc, "args")
143145
If Not Py.Bool(Py.GetItem(arg, "vba")) Then
146+
argname = Py.Str(Py.GetItem(arg, "name"))
144147
If Not first Then f.Write ", "
145-
f.Write Py.Str(Py.GetItem(arg, "name"))
148+
If Py.Bool(Py.GetItem(arg, "vararg")) Then
149+
f.Write "ParamArray "
150+
vararg = argname
151+
End If
152+
f.Write argname
153+
If Py.Bool(Py.GetItem(arg, "vararg")) Then
154+
f.Write "()"
155+
End If
146156
first = False
147157
End If
148158
Next arg
@@ -151,9 +161,17 @@ Sub ImportPythonUDFs(control As IRibbonControl)
151161
f.WriteLine sTab + "If TypeOf Application.Caller Is Range Then On Error GoTo failed"
152162
End If
153163

164+
If vararg <> "" Then
165+
f.WriteLine sTab + "ReDim argsArray(1 to UBound(" + vararg + ") - LBound(" + vararg + ") + " + CStr(nArgs) + ")"
166+
End If
167+
j = 1
154168
For Each arg In Py.GetItem(xlfunc, "args")
155169
If Not Py.Bool(Py.GetItem(arg, "vba")) Then
156170
argname = Py.Str(Py.GetItem(arg, "name"))
171+
If Py.Bool(Py.GetItem(arg, "vararg")) Then
172+
f.WriteLine sTab + "For k = lbound(" + vararg + ") to ubound(" + vararg + ")"
173+
argname = vararg + "(k)"
174+
End If
157175
If Not Py.Var(Py.GetItem(arg, "range")) Then
158176
f.WriteLine sTab + "If TypeOf " + argname + " Is Range Then " + argname + " = " + argname + ".Value2"
159177
End If
@@ -176,21 +194,34 @@ Sub ImportPythonUDFs(control As IRibbonControl)
176194
End If
177195
f.WriteLine sTab + "End If"
178196
End If
197+
If Py.Bool(Py.GetItem(arg, "vararg")) Then
198+
f.WriteLine sTab + "argsArray(" + CStr(j) + " + k - LBound(" + vararg + ")) = " + argname
199+
f.WriteLine sTab + "Next k"
200+
Else
201+
If vararg <> "" Then
202+
f.WriteLine sTab + "argsArray(" + CStr(j) + ") = " + argname
203+
j = j + 1
204+
End If
205+
End If
179206
End If
180207
Next arg
181208

182-
f.Write sTab + "Set args = Py.Tuple("
183-
first = True
184-
For Each arg In Py.GetItem(xlfunc, "args")
185-
If Not first Then f.Write ", "
186-
If Not Py.Bool(Py.GetItem(arg, "vba")) Then
187-
f.Write Py.Str(Py.GetItem(arg, "name"))
188-
Else
189-
f.Write Py.Str(Py.GetItem(arg, "vba"))
190-
End If
191-
first = False
192-
Next arg
193-
f.WriteLine ")"
209+
If vararg <> "" Then
210+
f.WriteLine sTab + "Set args = Py.TupleFromArray(argsArray)"
211+
Else
212+
f.Write sTab + "Set args = Py.Tuple("
213+
first = True
214+
For Each arg In Py.GetItem(xlfunc, "args")
215+
If Not first Then f.Write ", "
216+
If Not Py.Bool(Py.GetItem(arg, "vba")) Then
217+
f.Write Py.Str(Py.GetItem(arg, "name"))
218+
Else
219+
f.Write Py.Str(Py.GetItem(arg, "vba"))
220+
End If
221+
first = False
222+
Next arg
223+
f.WriteLine ")"
224+
End If
194225

195226
If Py.Bool(Py.GetItem(xlfunc, "xlwings")) Then
196227
f.WriteLine sTab + "Py.SetAttr Py.GetAttr(Py.Module(""xlwings""), ""xlplatform""), ""xl_app_latest"", Application"
@@ -243,18 +274,18 @@ not_present:
243274
For Each arg In xlargs
244275
If Not Py.Bool(Py.GetItem(arg, "vba")) Then nArgs = nArgs + 1
245276
Next arg
246-
If nArgs > 0 And Application.Version >= 14 Then
277+
If nArgs > 0 And Val(Application.Version) >= 14 Then
247278
ReDim argdocs(1 To WorksheetFunction.Max(1, nArgs)) As String
248279
nArgs = 0
249280
For Each arg In xlargs
250281
If Not Py.Bool(Py.GetItem(arg, "vba")) Then
251282
nArgs = nArgs + 1
252-
argdocs(nArgs) = Py.Str(Py.GetItem(arg, "doc"))
283+
argdocs(nArgs) = Left$(Py.Str(Py.GetItem(arg, "doc")), 255)
253284
End If
254285
Next arg
255-
XLPMacroOptions2010 "'" + wb.name + "'!" + fname, fdoc, argdocs
286+
XLPMacroOptions2010 "'" + wb.name + "'!" + fname, Left$(fdoc, 255), argdocs
256287
Else
257-
Application.MacroOptions "'" + wb.name + "'!" + fname, Description:=fdoc
288+
Application.MacroOptions "'" + wb.name + "'!" + fname, Description:=Left$(fdoc, 255)
258289
End If
259290
End If
260291
Next svar

xlpython/xlpython.vcxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,25 @@
6666
<LinkIncremental>true</LinkIncremental>
6767
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
6868
<IntDir>$(Platform)\$(Configuration)\</IntDir>
69-
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.5</TargetName>
69+
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.6</TargetName>
7070
</PropertyGroup>
7171
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
7272
<LinkIncremental>true</LinkIncremental>
7373
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
7474
<IntDir>$(Platform)\$(Configuration)\</IntDir>
75-
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.5</TargetName>
75+
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.6</TargetName>
7676
</PropertyGroup>
7777
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
7878
<LinkIncremental>false</LinkIncremental>
7979
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
8080
<IntDir>$(Platform)\$(Configuration)\</IntDir>
81-
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.5</TargetName>
81+
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.6</TargetName>
8282
</PropertyGroup>
8383
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
8484
<LinkIncremental>false</LinkIncremental>
8585
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
8686
<IntDir>$(Platform)\$(Configuration)\</IntDir>
87-
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.5</TargetName>
87+
<TargetName>$(ProjectName)$(PlatformArchitecture)-2.0.6</TargetName>
8888
</PropertyGroup>
8989
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
9090
<ClCompile>

0 commit comments

Comments
 (0)