tdrpa.tdworker 1.2.13.2__py312-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. tdrpa/_tdxlwings/__init__.py +193 -0
  2. tdrpa/_tdxlwings/__pycache__/__init__.cpython-311.pyc +0 -0
  3. tdrpa/_tdxlwings/__pycache__/__init__.cpython-38.pyc +0 -0
  4. tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-311.pyc +0 -0
  5. tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-38.pyc +0 -0
  6. tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-311.pyc +0 -0
  7. tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-38.pyc +0 -0
  8. tdrpa/_tdxlwings/__pycache__/apps.cpython-311.pyc +0 -0
  9. tdrpa/_tdxlwings/__pycache__/apps.cpython-38.pyc +0 -0
  10. tdrpa/_tdxlwings/__pycache__/base_classes.cpython-311.pyc +0 -0
  11. tdrpa/_tdxlwings/__pycache__/base_classes.cpython-38.pyc +0 -0
  12. tdrpa/_tdxlwings/__pycache__/com_server.cpython-311.pyc +0 -0
  13. tdrpa/_tdxlwings/__pycache__/com_server.cpython-38.pyc +0 -0
  14. tdrpa/_tdxlwings/__pycache__/constants.cpython-311.pyc +0 -0
  15. tdrpa/_tdxlwings/__pycache__/constants.cpython-38.pyc +0 -0
  16. tdrpa/_tdxlwings/__pycache__/expansion.cpython-311.pyc +0 -0
  17. tdrpa/_tdxlwings/__pycache__/expansion.cpython-38.pyc +0 -0
  18. tdrpa/_tdxlwings/__pycache__/main.cpython-311.pyc +0 -0
  19. tdrpa/_tdxlwings/__pycache__/main.cpython-38.pyc +0 -0
  20. tdrpa/_tdxlwings/__pycache__/udfs.cpython-311.pyc +0 -0
  21. tdrpa/_tdxlwings/__pycache__/udfs.cpython-38.pyc +0 -0
  22. tdrpa/_tdxlwings/__pycache__/utils.cpython-311.pyc +0 -0
  23. tdrpa/_tdxlwings/__pycache__/utils.cpython-38.pyc +0 -0
  24. tdrpa/_tdxlwings/_win32patch.py +90 -0
  25. tdrpa/_tdxlwings/_xlmac.py +2240 -0
  26. tdrpa/_tdxlwings/_xlwindows.py +2518 -0
  27. tdrpa/_tdxlwings/addin/Dictionary.cls +474 -0
  28. tdrpa/_tdxlwings/addin/IWebAuthenticator.cls +71 -0
  29. tdrpa/_tdxlwings/addin/WebClient.cls +772 -0
  30. tdrpa/_tdxlwings/addin/WebHelpers.bas +3203 -0
  31. tdrpa/_tdxlwings/addin/WebRequest.cls +875 -0
  32. tdrpa/_tdxlwings/addin/WebResponse.cls +453 -0
  33. tdrpa/_tdxlwings/addin/xlwings.xlam +0 -0
  34. tdrpa/_tdxlwings/apps.py +35 -0
  35. tdrpa/_tdxlwings/base_classes.py +1092 -0
  36. tdrpa/_tdxlwings/cli.py +1306 -0
  37. tdrpa/_tdxlwings/com_server.py +385 -0
  38. tdrpa/_tdxlwings/constants.py +3080 -0
  39. tdrpa/_tdxlwings/conversion/__init__.py +103 -0
  40. tdrpa/_tdxlwings/conversion/framework.py +147 -0
  41. tdrpa/_tdxlwings/conversion/numpy_conv.py +34 -0
  42. tdrpa/_tdxlwings/conversion/pandas_conv.py +184 -0
  43. tdrpa/_tdxlwings/conversion/standard.py +321 -0
  44. tdrpa/_tdxlwings/expansion.py +83 -0
  45. tdrpa/_tdxlwings/ext/__init__.py +3 -0
  46. tdrpa/_tdxlwings/ext/sql.py +73 -0
  47. tdrpa/_tdxlwings/html/xlwings-alert.html +71 -0
  48. tdrpa/_tdxlwings/js/xlwings.js +577 -0
  49. tdrpa/_tdxlwings/js/xlwings.ts +729 -0
  50. tdrpa/_tdxlwings/mac_dict.py +6399 -0
  51. tdrpa/_tdxlwings/main.py +5205 -0
  52. tdrpa/_tdxlwings/mistune/__init__.py +63 -0
  53. tdrpa/_tdxlwings/mistune/block_parser.py +366 -0
  54. tdrpa/_tdxlwings/mistune/inline_parser.py +216 -0
  55. tdrpa/_tdxlwings/mistune/markdown.py +84 -0
  56. tdrpa/_tdxlwings/mistune/renderers.py +220 -0
  57. tdrpa/_tdxlwings/mistune/scanner.py +121 -0
  58. tdrpa/_tdxlwings/mistune/util.py +41 -0
  59. tdrpa/_tdxlwings/pro/__init__.py +40 -0
  60. tdrpa/_tdxlwings/pro/_xlcalamine.py +536 -0
  61. tdrpa/_tdxlwings/pro/_xlofficejs.py +146 -0
  62. tdrpa/_tdxlwings/pro/_xlremote.py +1293 -0
  63. tdrpa/_tdxlwings/pro/custom_functions_code.js +150 -0
  64. tdrpa/_tdxlwings/pro/embedded_code.py +60 -0
  65. tdrpa/_tdxlwings/pro/udfs_officejs.py +549 -0
  66. tdrpa/_tdxlwings/pro/utils.py +199 -0
  67. tdrpa/_tdxlwings/quickstart.xlsm +0 -0
  68. tdrpa/_tdxlwings/quickstart_addin.xlam +0 -0
  69. tdrpa/_tdxlwings/quickstart_addin_ribbon.xlam +0 -0
  70. tdrpa/_tdxlwings/quickstart_fastapi/main.py +47 -0
  71. tdrpa/_tdxlwings/quickstart_fastapi/requirements.txt +3 -0
  72. tdrpa/_tdxlwings/quickstart_standalone.xlsm +0 -0
  73. tdrpa/_tdxlwings/reports.py +12 -0
  74. tdrpa/_tdxlwings/rest/__init__.py +1 -0
  75. tdrpa/_tdxlwings/rest/api.py +368 -0
  76. tdrpa/_tdxlwings/rest/serializers.py +103 -0
  77. tdrpa/_tdxlwings/server.py +14 -0
  78. tdrpa/_tdxlwings/udfs.py +775 -0
  79. tdrpa/_tdxlwings/utils.py +777 -0
  80. tdrpa/_tdxlwings/xlwings-0.31.6.applescript +30 -0
  81. tdrpa/_tdxlwings/xlwings.bas +2061 -0
  82. tdrpa/_tdxlwings/xlwings_custom_addin.bas +2042 -0
  83. tdrpa/_tdxlwings/xlwingslib.cp38-win_amd64.pyd +0 -0
  84. tdrpa/tdworker/__init__.pyi +12 -0
  85. tdrpa/tdworker/_clip.pyi +50 -0
  86. tdrpa/tdworker/_excel.pyi +743 -0
  87. tdrpa/tdworker/_file.pyi +77 -0
  88. tdrpa/tdworker/_img.pyi +226 -0
  89. tdrpa/tdworker/_network.pyi +94 -0
  90. tdrpa/tdworker/_os.pyi +47 -0
  91. tdrpa/tdworker/_sp.pyi +21 -0
  92. tdrpa/tdworker/_w.pyi +129 -0
  93. tdrpa/tdworker/_web.pyi +995 -0
  94. tdrpa/tdworker/_winE.pyi +228 -0
  95. tdrpa/tdworker/_winK.pyi +74 -0
  96. tdrpa/tdworker/_winM.pyi +117 -0
  97. tdrpa/tdworker.cp312-win_amd64.pyd +0 -0
  98. tdrpa_tdworker-1.2.13.2.dist-info/METADATA +38 -0
  99. tdrpa_tdworker-1.2.13.2.dist-info/RECORD +101 -0
  100. tdrpa_tdworker-1.2.13.2.dist-info/WHEEL +5 -0
  101. tdrpa_tdworker-1.2.13.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2061 @@
1
+ Attribute VB_Name = "xlwings"
2
+ #Const App = "Microsoft Excel" 'Adjust when using outside of Excel
3
+ 'Version: 0.31.6
4
+
5
+ 'xlwings is distributed under a BSD 3-clause license.
6
+ '
7
+ 'Copyright (C) 2014-present, Zoomer Analytics LLC.
8
+ 'All rights reserved.
9
+ '
10
+ 'Redistribution and use in source and binary forms, with or without modification,
11
+ 'are permitted provided that the following conditions are met:
12
+ '
13
+ '* Redistributions of source code must retain the above copyright notice, this
14
+ ' list of conditions and the following disclaimer.
15
+ '
16
+ '* Redistributions in binary form must reproduce the above copyright notice, this
17
+ ' list of conditions and the following disclaimer in the documentation and/or
18
+ ' other materials provided with the distribution.
19
+ '
20
+ '* Neither the name of the copyright holder nor the names of its
21
+ ' contributors may be used to endorse or promote products derived from
22
+ ' this software without specific prior written permission.
23
+ '
24
+ 'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25
+ 'ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26
+ 'WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
+ 'DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28
+ 'ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29
+ '(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
+ 'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31
+ 'ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
+ '(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33
+ 'SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ 'Attribute VB_Name = "Main"
36
+
37
+
38
+
39
+ #If VBA7 Then
40
+ #If Mac Then
41
+ Private Declare PtrSafe Function system Lib "libc.dylib" (ByVal Command As String) As Long
42
+ #End If
43
+ #If Win64 Then
44
+ Const XLPyDLLName As String = "xlwings64-0.31.6.dll"
45
+ Declare PtrSafe Function XLPyDLLActivateAuto Lib "xlwings64-0.31.6.dll" (ByRef Result As Variant, Optional ByVal Config As String = "", Optional ByVal mode As Long = 1) As Long
46
+ Declare PtrSafe Function XLPyDLLNDims Lib "xlwings64-0.31.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
47
+ Declare PtrSafe Function XLPyDLLVersion Lib "xlwings64-0.31.6.dll" (tag As String, VERSION As Double, arch As String) As Long
48
+ #Else
49
+ Private Const XLPyDLLName As String = "xlwings32-0.31.6.dll"
50
+ Declare PtrSafe Function XLPyDLLActivateAuto Lib "xlwings32-0.31.6.dll" (ByRef Result As Variant, Optional ByVal Config As String = "", Optional ByVal mode As Long = 1) As Long
51
+ Private Declare PtrSafe Function XLPyDLLNDims Lib "xlwings32-0.31.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
52
+ Private Declare PtrSafe Function XLPyDLLVersion Lib "xlwings32-0.31.6.dll" (tag As String, VERSION As Double, arch As String) As Long
53
+ #End If
54
+ Private Declare PtrSafe Function LoadLibrary Lib "KERNEL32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
55
+ #Else
56
+ #If Mac Then
57
+ Private Declare Function system Lib "libc.dylib" (ByVal Command As String) As Long
58
+ #End If
59
+ Private Const XLPyDLLName As String = "xlwings32-0.31.6.dll"
60
+ Private Declare Function XLPyDLLActivateAuto Lib "xlwings32-0.31.6.dll" (ByRef Result As Variant, Optional ByVal Config As String = "", Optional ByVal mode As Long = 1) As Long
61
+ Private Declare Function XLPyDLLNDims Lib "xlwings32-0.31.6.dll" (ByRef src As Variant, ByRef dims As Long, ByRef transpose As Boolean, ByRef dest As Variant) As Long
62
+ Private Declare Function LoadLibrary Lib "KERNEL32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
63
+ Declare Function XLPyDLLVersion Lib "xlwings32-0.31.6.dll" (tag As String, VERSION As Double, arch As String) As Long
64
+ #End If
65
+
66
+ Public Const XLWINGS_VERSION As String = "0.31.6"
67
+ Public Const PROJECT_NAME As String = "xlwings"
68
+
69
+ Public Function RunPython(PythonCommand As String)
70
+ ' Public API: Runs the Python command, e.g.: to run the function foo() in module bar, call the function like this:
71
+ ' RunPython "import bar; bar.foo()"
72
+
73
+ Dim i As Integer
74
+ Dim SourcePythonCommand As String, interpreter As String, PYTHONPATH As String, licenseKey, ActiveFullName As String, ThisFullName As String, AddExcelDir As String
75
+ Dim OPTIMIZED_CONNECTION As Boolean, uses_embedded_code As Boolean
76
+ Dim wb As Workbook
77
+ Dim sht As Worksheet
78
+
79
+ SourcePythonCommand = PythonCommand
80
+
81
+ #If Mac Then
82
+ interpreter = GetConfig("INTERPRETER_MAC", "")
83
+ #Else
84
+ interpreter = GetConfig("INTERPRETER_WIN", "")
85
+ #End If
86
+ If interpreter = "" Then
87
+ ' Legacy
88
+ interpreter = GetConfig("INTERPRETER", "python")
89
+ End If
90
+
91
+ ' Check for embedded Python code
92
+ uses_embedded_code = False
93
+ For i = 1 To 2
94
+ If i = 1 Then
95
+ Set wb = ThisWorkbook
96
+ Else
97
+ Set wb = ThisWorkbook
98
+ End If
99
+ For Each sht In wb.Worksheets
100
+ If Right$(sht.Name, 3) = ".py" Then
101
+ uses_embedded_code = True
102
+ Exit For
103
+ End If
104
+ Next
105
+ Next i
106
+
107
+ If uses_embedded_code = True Then
108
+ AddExcelDir = "false"
109
+ Else
110
+ AddExcelDir = GetConfig("ADD_WORKBOOK_TO_PYTHONPATH", "true")
111
+ End If
112
+
113
+ ' The first 5 args are not technically part of the PYTHONPATH, but it's just easier to add it here (used by xlwings.utils.prepare_sys_path)
114
+ #If Mac Then
115
+ If InStr(ThisWorkbook.FullName, "://") = 0 Then
116
+ ActiveFullName = ToPosixPath(ThisWorkbook.FullName)
117
+ ThisFullName = ToPosixPath(ThisWorkbook.FullName)
118
+ Else
119
+ ActiveFullName = ThisWorkbook.FullName
120
+ ThisFullName = ThisWorkbook.FullName
121
+ End If
122
+ #Else
123
+ ActiveFullName = ThisWorkbook.FullName
124
+ ThisFullName = ThisWorkbook.FullName
125
+ #End If
126
+
127
+ #If Mac Then
128
+ PYTHONPATH = AddExcelDir & ";" & ActiveFullName & ";" & ThisFullName & ";" & GetConfig("ONEDRIVE_CONSUMER_MAC") & ";" & GetConfig("ONEDRIVE_COMMERCIAL_MAC") & ";" & GetConfig("SHAREPOINT_MAC") & ";" & GetConfig("PYTHONPATH")
129
+ #Else
130
+ PYTHONPATH = AddExcelDir & ";" & ActiveFullName & ";" & ThisFullName & ";" & GetConfig("ONEDRIVE_CONSUMER_WIN") & ";" & GetConfig("ONEDRIVE_COMMERCIAL_WIN") & ";" & GetConfig("SHAREPOINT_WIN") & ";" & GetConfig("PYTHONPATH")
131
+ #End If
132
+
133
+ OPTIMIZED_CONNECTION = GetConfig("USE UDF SERVER", False)
134
+
135
+ ' PythonCommand with embedded code
136
+ If uses_embedded_code = True Then
137
+ licenseKey = GetConfig("LICENSE_KEY")
138
+ If licenseKey = "" Then
139
+ MsgBox "Embedded code requires a valid LICENSE_KEY."
140
+ Exit Function
141
+ Else
142
+ PythonCommand = "import xlwings.pro;xlwings.pro.runpython_embedded_code('" & SourcePythonCommand & "')"
143
+ End If
144
+ End If
145
+
146
+ ' Call Python platform-dependent
147
+ #If Mac Then
148
+ Application.StatusBar = "Running..." ' Non-blocking way of giving feedback that something is happening
149
+ ExecuteMac PythonCommand, interpreter, PYTHONPATH
150
+ #Else
151
+ If OPTIMIZED_CONNECTION = True Then
152
+ XLPy.SetAttr XLPy.Module("xlwings._xlwindows"), "BOOK_CALLER", ThisWorkbook
153
+
154
+ On Error GoTo err_handling
155
+
156
+ XLPy.Exec "" & PythonCommand & ""
157
+ GoTo end_err_handling
158
+ err_handling:
159
+ ShowError "", Err.Description
160
+ RunPython = -1
161
+ On Error GoTo 0
162
+ end_err_handling:
163
+ Else
164
+ RunPython = ExecuteWindows(False, PythonCommand, interpreter, PYTHONPATH)
165
+ End If
166
+ #End If
167
+ End Function
168
+
169
+
170
+ Sub ExecuteMac(PythonCommand As String, PYTHON_MAC As String, Optional PYTHONPATH As String)
171
+ #If Mac Then
172
+ Dim PythonInterpreter As String, RunCommand As String, Log As String
173
+ Dim ParameterString As String, ExitCode As String, CondaCmd As String, CondaPath As String, CondaEnv As String, LOG_FILE As String
174
+
175
+ ' Transform paths
176
+ PYTHONPATH = Replace(PYTHONPATH, "'", "\'") ' Escaping quotes
177
+
178
+ If PYTHON_MAC <> "" Then
179
+ If PYTHON_MAC <> "python" And PYTHON_MAC <> "pythonw" Then
180
+ PythonInterpreter = ToPosixPath(PYTHON_MAC)
181
+ Else
182
+ PythonInterpreter = PYTHON_MAC
183
+ End If
184
+ Else
185
+ PythonInterpreter = "python"
186
+ End If
187
+
188
+ ' Sandbox location that requires no file access confirmation
189
+ ' TODO: Use same logic with GUID like for Windows. Only here the GUID will need to be passed back to CleanUp()
190
+ LOG_FILE = Environ("HOME") + "/xlwings.log" '/Users/<User>/Library/Containers/com.microsoft.Excel/Data/xlwings.log
191
+
192
+ ' Delete Log file just to make sure we don't show an old error
193
+ On Error Resume Next
194
+ Kill LOG_FILE
195
+ On Error GoTo 0
196
+
197
+ ' ParameterSting with all paramters (AppleScriptTask only accepts a single parameter)
198
+ ParameterString = PYTHONPATH + ";"
199
+ ParameterString = ParameterString + "|" + PythonInterpreter
200
+ ParameterString = ParameterString + "|" + PythonCommand
201
+ ParameterString = ParameterString + "|" + ThisWorkbook.Name
202
+ ParameterString = ParameterString + "|" + Left(Application.Path, Len(Application.Path) - 4)
203
+ ParameterString = ParameterString + "|" + LOG_FILE
204
+
205
+ On Error GoTo AppleScriptErrorHandler
206
+ ExitCode = AppleScriptTask("xlwings-" & XLWINGS_VERSION & ".applescript", "VbaHandler", ParameterString)
207
+ On Error GoTo 0
208
+
209
+ ' If there's a log at this point (normally that will be from the shell only, not Python) show it and reset the StatusBar
210
+ On Error Resume Next
211
+ Log = ReadFile(LOG_FILE)
212
+ If Log = "" Then
213
+ Exit Sub
214
+ Else
215
+ ShowError (LOG_FILE)
216
+ Application.StatusBar = False
217
+ End If
218
+ Exit Sub
219
+ On Error GoTo 0
220
+
221
+ AppleScriptErrorHandler:
222
+ MsgBox "To enable RunPython, please run 'xlwings runpython install' in a terminal once and try again.", vbCritical
223
+ #End If
224
+ End Sub
225
+
226
+ Function ExecuteWindows(IsFrozen As Boolean, PythonCommand As String, PYTHON_WIN As String, _
227
+ Optional PYTHONPATH As String, Optional FrozenArgs As String) As Integer
228
+ ' Call a command window and change to the directory of the Python installation or frozen executable
229
+ ' Note: If Python is called from a different directory with the fully qualified path, pywintypesXX.dll won't be found.
230
+ ' This seems to be a general issue with pywin32, see http://stackoverflow.com/q/7238403/918626
231
+ Dim ShowConsole As Integer
232
+ Dim TempDir As String
233
+ If GetConfig("SHOW CONSOLE", False) = True Then
234
+ ShowConsole = 1
235
+ Else
236
+ ShowConsole = 0
237
+ End If
238
+
239
+ Dim WaitOnReturn As Boolean: WaitOnReturn = True
240
+ Dim WindowStyle As Integer: WindowStyle = ShowConsole
241
+ Dim DriveCommand As String, RunCommand, condaExcecutable As String
242
+ Dim PythonInterpreter As String, PythonDir As String, CondaCmd As String, CondaPath As String, CondaEnv As String
243
+ Dim ExitCode As Long
244
+ Dim LOG_FILE As String
245
+
246
+ TempDir = GetConfig("TEMP DIR", Environ("Temp")) 'undocumented setting
247
+
248
+ LOG_FILE = TempDir & "\xlwings-" & CreateGUID() & ".log"
249
+
250
+ If Not IsFrozen And (PYTHON_WIN <> "python" And PYTHON_WIN <> "pythonw") Then
251
+ If FileExists(PYTHON_WIN) Then
252
+ PythonDir = ParentFolder(PYTHON_WIN)
253
+ Else
254
+ MsgBox "Could not find Interpreter!", vbCritical
255
+ Exit Function
256
+ End If
257
+ Else
258
+ PythonDir = "" ' TODO: hack
259
+ End If
260
+
261
+ If Left$(PYTHON_WIN, 2) Like "[A-Za-z]:" Then
262
+ ' If Python is installed on a mapped or local drive, change to drive, then cd to path
263
+ DriveCommand = Left$(PYTHON_WIN, 2) & " & cd """ & PythonDir & """ & "
264
+ ElseIf Left$(PYTHON_WIN, 2) = "\\" Then
265
+ ' If Python is installed on a UNC path, temporarily mount and activate a drive letter with pushd
266
+ DriveCommand = "pushd """ & PythonDir & """ & "
267
+ End If
268
+
269
+ ' Run Python with the "-c" command line switch: add the path of the python file and run the
270
+ ' Command as first argument, then provide the Name and "from_xl" as 2nd and 3rd arguments.
271
+ ' Then redirect stderr to the LOG_FILE and wait for the call to return.
272
+
273
+ If PYTHON_WIN <> "python" And PYTHON_WIN <> "pythonw" Then
274
+ PythonInterpreter = Chr(34) & PYTHON_WIN & Chr(34)
275
+ Else
276
+ PythonInterpreter = "python"
277
+ End If
278
+
279
+ CondaPath = GetConfig("CONDA PATH")
280
+ CondaEnv = GetConfig("CONDA ENV")
281
+
282
+ ' Handle spaces in path (for UDFs, this is handled via nested quotes instead, see XLPyCommand)
283
+ CondaPath = Replace(CondaPath, " ", "^ ")
284
+
285
+ ' Handle ampersands and backslashes in file paths
286
+ PYTHONPATH = Replace(PYTHONPATH, "&", "^&")
287
+ PYTHONPATH = Replace(PYTHONPATH, "\", "\\")
288
+
289
+ If CondaPath <> "" And CondaEnv <> "" Then
290
+ If CheckConda(CondaPath) = False Then
291
+ Exit Function
292
+ End If
293
+ CondaCmd = CondaPath & "\condabin\conda activate " & CondaEnv & " && "
294
+ Else
295
+ CondaCmd = ""
296
+ End If
297
+
298
+ If IsFrozen = False Then
299
+ RunCommand = CondaCmd & PythonInterpreter & " -B -c ""import xlwings.utils;xlwings.utils.prepare_sys_path(\""" & PYTHONPATH & "\""); " & PythonCommand & """ "
300
+ ElseIf IsFrozen = True Then
301
+ RunCommand = Chr(34) & PythonCommand & Chr(34) & " " & FrozenArgs & " "
302
+ End If
303
+
304
+ ExitCode = WScript.Run("cmd.exe /C " & DriveCommand & _
305
+ RunCommand & _
306
+ " --wb=" & """" & ThisWorkbook.Name & """ --from_xl=1" & " --app=" & Chr(34) & _
307
+ Application.Path & "\" & Application.Name & Chr(34) & " --hwnd=" & Chr(34) & Application.Hwnd & Chr(34) & _
308
+ " 2> """ & LOG_FILE & """ ", _
309
+ WindowStyle, WaitOnReturn)
310
+
311
+ 'If ExitCode <> 0 then there's something wrong
312
+ If ExitCode <> 0 Then
313
+ Call ShowError(LOG_FILE)
314
+ ExecuteWindows = -1
315
+ End If
316
+
317
+ ' Delete file after the error message has been shown
318
+ On Error Resume Next
319
+ Kill LOG_FILE
320
+ On Error GoTo 0
321
+ End Function
322
+
323
+ Public Function RunFrozenPython(Executable As String, Optional Args As String)
324
+ ' Runs a Python executable that has been frozen by PyInstaller and the like. Call the function like this:
325
+ ' RunFrozenPython "C:\path\to\frozen_executable.exe", "arg1 arg2". Currently not implemented for Mac.
326
+
327
+ ' Call Python
328
+ #If Mac Then
329
+ MsgBox "This functionality is not yet supported on Mac." & vbNewLine & _
330
+ "Please run your scripts directly in Python!", vbCritical + vbOKOnly, "Unsupported Feature"
331
+ #Else
332
+ ExecuteWindows True, Executable, ParentFolder(Executable), , Args
333
+ #End If
334
+ End Function
335
+
336
+ #If App = "Microsoft Excel" Then
337
+ Function GetUdfModules(Optional wb As Workbook) As String
338
+ #Else
339
+ Function GetUdfModules(Optional wb As Variant) As String
340
+ #End If
341
+ Dim i As Integer
342
+ Dim UDF_MODULES As String
343
+ Dim sht As Worksheet
344
+
345
+ GetUdfModules = GetConfig("UDF MODULES")
346
+ ' Remove trailing ";"
347
+ If Right$(GetUdfModules, 1) = ";" Then
348
+ GetUdfModules = Left$(GetUdfModules, Len(GetUdfModules) - 1)
349
+ End If
350
+
351
+ ' Automatically add embedded code sheets
352
+ For Each sht In wb.Worksheets
353
+ If Right$(sht.Name, 3) = ".py" Then
354
+ If GetUdfModules = "" Then
355
+ GetUdfModules = Left$(sht.Name, Len(sht.Name) - 3)
356
+ Else
357
+ GetUdfModules = GetUdfModules & ";" & Left$(sht.Name, Len(sht.Name) - 3)
358
+ End If
359
+ End If
360
+ Next
361
+
362
+ ' Default
363
+ If GetUdfModules = "" Then
364
+ GetUdfModules = Left$(wb.Name, Len(wb.Name) - 5) ' assume that it ends in .xls*
365
+ End If
366
+
367
+ End Function
368
+
369
+ Private Sub CleanUp()
370
+ 'On Mac only, this function is being called after Python is done (using Python's atexit handler)
371
+ Dim LOG_FILE As String
372
+
373
+ #If MAC_OFFICE_VERSION >= 15 Then
374
+ LOG_FILE = Environ("HOME") + "/xlwings.log" '~/Library/Containers/com.microsoft.Excel/Data/xlwings.log
375
+ #Else
376
+ LOG_FILE = "/tmp/xlwings.log"
377
+ #End If
378
+
379
+ 'Show the LOG_FILE as MsgBox if not empty
380
+ On Error Resume Next
381
+ If ReadFile(LOG_FILE) <> "" Then
382
+ Call ShowError(LOG_FILE)
383
+ End If
384
+ On Error GoTo 0
385
+
386
+ 'Clean up
387
+ Application.StatusBar = False
388
+ Application.ScreenUpdating = True
389
+ On Error Resume Next
390
+ #If MAC_OFFICE_VERSION >= 15 Then
391
+ Kill LOG_FILE
392
+ #Else
393
+ KillFileOnMac ToMacPath(ToPosixPath(LOG_FILE))
394
+ #End If
395
+ On Error GoTo 0
396
+ End Sub
397
+
398
+ Function XLPyCommand()
399
+ 'TODO: the whole python vs. pythonw should be obsolete now that the console is shown/hidden by the dll
400
+ Dim PYTHON_WIN As String, PYTHONPATH As String, LOG_FILE As String, tail As String, licenseKey As String, LicenseKeyEnvString As String, AddExcelDir As String
401
+ Dim CondaCmd As String, CondaPath As String, CondaEnv As String, ConsoleSwitch As String, FName As String
402
+
403
+ Dim DEBUG_UDFS As Boolean
404
+ #If App = "Microsoft Excel" Then
405
+ Dim wb As Workbook
406
+ #End If
407
+
408
+ ' TODO: Doesn't automatically check if code is embedded
409
+ AddExcelDir = GetConfig("ADD_WORKBOOK_TO_PYTHONPATH", "true")
410
+
411
+ ' The first 6 args are not technically part of the PYTHONPATH, but it's just easier to add it here (used by xlwings.utils.prepare_sys_path)
412
+ #If App = "Microsoft Excel" Then
413
+ PYTHONPATH = AddExcelDir & ";" & ThisWorkbook.FullName & ";" & ThisWorkbook.FullName & ";" & GetConfig("ONEDRIVE_CONSUMER_WIN") & ";" & GetConfig("ONEDRIVE_COMMERCIAL_WIN") & ";" & GetConfig("SHAREPOINT_WIN") & ";" & GetConfig("PYTHONPATH")
414
+ #Else
415
+ ' Other office apps
416
+ #If App = "Microsoft Word" Then
417
+ FName = ThisDocument.FullName
418
+ #ElseIf App = "Microsoft Access" Then
419
+ FName = CurrentProject.FullName
420
+ #ElseIf App = "Microsoft PowerPoint" Then
421
+ FName = ActivePresentation.FullName
422
+ #End If
423
+ PYTHONPATH = FName & ";" & ";" & GetConfig("ONEDRIVE_CONSUMER_WIN") & ";" & GetConfig("ONEDRIVE_COMMERCIAL_WIN") & ";" & GetConfig("SHAREPOINT_WIN") & ";" & GetConfig("PYTHONPATH")
424
+ #End If
425
+
426
+ ' Escaping backslashes and quotes
427
+ PYTHONPATH = Replace(PYTHONPATH, "\", "\\")
428
+ PYTHONPATH = Replace(PYTHONPATH, "'", "\'")
429
+ PYTHONPATH = Replace(PYTHONPATH, "&", "^&")
430
+
431
+ PYTHON_WIN = GetConfig("INTERPRETER_WIN", "")
432
+ If PYTHON_WIN = "" Then
433
+ ' Legacy
434
+ PYTHON_WIN = GetConfig("INTERPRETER", "pythonw")
435
+ End If
436
+ DEBUG_UDFS = GetConfig("DEBUG UDFS", False)
437
+
438
+ ' /showconsole is a fictitious command line switch that's ignored by cmd.exe but used by CreateProcessA in the dll
439
+ ' It's the only setting that's sent over like this at the moment
440
+ If GetConfig("SHOW CONSOLE", False) = True Then
441
+ ConsoleSwitch = "/showconsole"
442
+ Else
443
+ ConsoleSwitch = ""
444
+ End If
445
+
446
+ CondaPath = GetConfig("CONDA PATH")
447
+ CondaEnv = GetConfig("CONDA ENV")
448
+
449
+ If (PYTHON_WIN = "python" Or PYTHON_WIN = "pythonw") And (CondaPath <> "" And CondaEnv <> "") Then
450
+ CondaCmd = Chr(34) & Chr(34) & CondaPath & "\condabin\conda" & Chr(34) & " activate " & CondaEnv & " && "
451
+ PYTHON_WIN = "cmd.exe " & ConsoleSwitch & " /K " & CondaCmd & "python"
452
+ Else
453
+ PYTHON_WIN = "cmd.exe " & ConsoleSwitch & " /K " & Chr(34) & Chr(34) & PYTHON_WIN & Chr(34)
454
+ End If
455
+
456
+ licenseKey = GetConfig("LICENSE_KEY", "")
457
+ If licenseKey <> "" Then
458
+ LicenseKeyEnvString = "os.environ['XLWINGS_LICENSE_KEY']='" & licenseKey & "';"
459
+ Else
460
+ LicenseKeyEnvString = ""
461
+ End If
462
+
463
+ If DEBUG_UDFS = True Then
464
+ XLPyCommand = "{506e67c3-55b5-48c3-a035-eed5deea7d6d}"
465
+ Else
466
+ ' Spaces in path of python.exe require quote around path AND quotes around whole command, see:
467
+ ' https://stackoverflow.com/questions/6376113/how-do-i-use-spaces-in-the-command-prompt
468
+ tail = " -B -c ""import sys, os;" & LicenseKeyEnvString & "import xlwings.utils;xlwings.utils.prepare_sys_path(\""" & PYTHONPATH & "\"");import xlwings; xlwings.serve('$(CLSID)')"""
469
+ XLPyCommand = PYTHON_WIN & tail & Chr(34)
470
+ End If
471
+ End Function
472
+
473
+ Private Sub XLPyLoadDLL()
474
+ Dim PYTHON_WIN As String, CondaCmd As String, CondaPath As String, CondaEnv As String
475
+
476
+ PYTHON_WIN = GetConfig("INTERPRETER_WIN", "")
477
+ If PYTHON_WIN = "" Then
478
+ ' Legacy
479
+ PYTHON_WIN = GetConfig("INTERPRETER", "pythonw")
480
+ End If
481
+ CondaPath = GetConfig("CONDA PATH")
482
+ CondaEnv = GetConfig("CONDA ENV")
483
+
484
+ If (PYTHON_WIN = "python" Or PYTHON_WIN = "pythonw") And (CondaPath <> "" And CondaEnv <> "") Then
485
+ ' This only works if the envs are in their default location
486
+ ' Otherwise you'll have to add the full path for the interpreter in addition to the conda infos
487
+ If CondaEnv = "base" Then
488
+ PYTHON_WIN = CondaPath & "\" & PYTHON_WIN
489
+ Else
490
+ PYTHON_WIN = CondaPath & "\envs\" & CondaEnv & "\" & PYTHON_WIN
491
+ End If
492
+ End If
493
+
494
+ If (PYTHON_WIN <> "python" And PYTHON_WIN <> "pythonw") Or (CondaPath <> "" And CondaEnv <> "") Then
495
+ If LoadLibrary(ParentFolder(PYTHON_WIN) + "\" + XLPyDLLName) = 0 Then ' Standard installation
496
+ If LoadLibrary(ParentFolder(ParentFolder(PYTHON_WIN)) + "\" + XLPyDLLName) = 0 Then ' Virtualenv
497
+ Err.Raise 1, Description:= _
498
+ "Could not load " + XLPyDLLName + " from either of the following folders: " _
499
+ + vbCrLf + ParentFolder(PYTHON_WIN) _
500
+ + vbCrLf + ", " + ParentFolder(ParentFolder(PYTHON_WIN))
501
+ End If
502
+ End If
503
+ End If
504
+ End Sub
505
+
506
+ Function NDims(ByRef src As Variant, dims As Long, Optional transpose As Boolean = False)
507
+ XLPyLoadDLL
508
+ If 0 <> XLPyDLLNDims(src, dims, transpose, NDims) Then Err.Raise 1001, Description:=NDims
509
+ End Function
510
+
511
+ Function XLPy()
512
+ XLPyLoadDLL
513
+ If 0 <> XLPyDLLActivateAuto(XLPy, XLPyCommand, 1) Then Err.Raise 1000, Description:=XLPy
514
+ End Function
515
+
516
+ Sub KillPy()
517
+ XLPyLoadDLL
518
+ Dim unused
519
+ If 0 <> XLPyDLLActivateAuto(unused, XLPyCommand, -1) Then Err.Raise 1000, Description:=unused
520
+ End Sub
521
+
522
+ Sub ImportPythonUDFsBase(Optional addin As Boolean = False)
523
+ ' This is called from the Ribbon button
524
+ Dim tempPath As String, errorMsg As String
525
+ Dim wb As Workbook
526
+
527
+ If GetConfig("CONDA PATH") <> "" And CheckConda(GetConfig("CONDA PATH")) = False Then
528
+ Exit Sub
529
+ End If
530
+
531
+ If addin = True Then
532
+ Set wb = ThisWorkbook
533
+ Else
534
+ Set wb = ThisWorkbook
535
+ End If
536
+
537
+ On Error GoTo ImportError
538
+ tempPath = XLPy.Str(XLPy.Call(XLPy.Module("xlwings"), "import_udfs", XLPy.Tuple(GetUdfModules(wb), wb)))
539
+ Exit Sub
540
+ ImportError:
541
+ errorMsg = Err.Description & " " & Err.Number
542
+ ShowError "", errorMsg
543
+ End Sub
544
+
545
+ Sub ImportPythonUDFs()
546
+ ImportPythonUDFsBase
547
+ End Sub
548
+
549
+ Sub ImportPythonUDFsToAddin()
550
+ ImportPythonUDFsBase addin:=True
551
+ End Sub
552
+
553
+ Sub ImportXlwingsUdfsModule(tf As String)
554
+ ' Fallback: This is called from Python as direct pywin32 calls were sometimes failing, see comments in the Python code
555
+ On Error Resume Next
556
+ ThisWorkbook.VBProject.VBComponents.Remove ThisWorkbook.VBProject.VBComponents("xlwings_udfs")
557
+ On Error GoTo 0
558
+ ThisWorkbook.VBProject.VBComponents.Import tf
559
+ End Sub
560
+
561
+ Private Sub GetDLLVersion()
562
+ ' Currently only for testing
563
+ Dim tag As String, arch As String
564
+ Dim ver As Double
565
+ XLPyDLLVersion tag, ver, arch
566
+ Debug.Print tag
567
+ Debug.Print ver
568
+ Debug.Print arch
569
+ End Sub
570
+
571
+
572
+
573
+ 'Attribute VB_Name = "Config"
574
+
575
+
576
+
577
+ #If App = "Microsoft Excel" Then
578
+ Function GetDirectoryPath(Optional wb As Workbook) As String
579
+ #Else
580
+ Function GetDirectoryPath(Optional wb As Variant) As String
581
+ #End If
582
+ ' Leaving this here for now because we currently don't have #Const App in Utils
583
+ Dim Path As String
584
+ #If App = "Microsoft Excel" Then
585
+ On Error Resume Next 'On Mac, this is called when exiting the Python interpreter
586
+ Path = GetDirectory(GetFullName(wb))
587
+ On Error GoTo 0
588
+ #ElseIf App = "Microsoft Word" Then
589
+ Path = ThisDocument.Path
590
+ #ElseIf App = "Microsoft Access" Then
591
+ Path = CurrentProject.Path ' Won't be transformed for standalone module as ThisProject doesn't exit
592
+ #ElseIf App = "Microsoft PowerPoint" Then
593
+ Path = ActivePresentation.Path ' Won't be transformed for standalone module ThisPresentation doesn't exist
594
+ #Else
595
+ Exit Function
596
+ #End If
597
+ GetDirectoryPath = Path
598
+ End Function
599
+
600
+ Function GetConfigFilePath() As String
601
+ #If Mac Then
602
+ ' ~/Library/Containers/com.microsoft.Excel/Data/xlwings.conf
603
+ GetConfigFilePath = GetMacDir("$HOME", False) & "/" & PROJECT_NAME & ".conf"
604
+ #Else
605
+ GetConfigFilePath = Environ("USERPROFILE") & "\." & PROJECT_NAME & "\" & PROJECT_NAME & ".conf"
606
+ #End If
607
+ End Function
608
+
609
+ Function GetDirectoryConfigFilePath() As String
610
+ Dim pathSeparator As String
611
+
612
+ #If Mac Then ' Application.PathSeparator doesn't seem to exist in Access...
613
+ pathSeparator = "/"
614
+ #Else
615
+ pathSeparator = "\"
616
+ #End If
617
+
618
+ GetDirectoryConfigFilePath = GetDirectoryPath(ThisWorkbook) & pathSeparator & PROJECT_NAME & ".conf"
619
+ End Function
620
+
621
+ #If App = "Microsoft Excel" Then
622
+ Function GetConfigFromSheet(wb As Workbook)
623
+ Dim lastCell As Range, cell As Range
624
+ #If Mac Then
625
+ Dim d As Dictionary
626
+ Set d = New Dictionary
627
+ #Else
628
+ Dim d As Object
629
+ Set d = CreateObject("Scripting.Dictionary")
630
+ #End If
631
+ Dim sht As Worksheet
632
+
633
+ Set sht = wb.Sheets(PROJECT_NAME & ".conf")
634
+
635
+ If sht.Range("A2") = "" Then
636
+ Set lastCell = sht.Range("A1")
637
+ Else
638
+ Set lastCell = sht.Range("A1").End(xlDown)
639
+ End If
640
+
641
+ For Each cell In Range(sht.Range("A1"), lastCell)
642
+ d.Add UCase(cell.Value), cell.Offset(0, 1).Value
643
+ Next cell
644
+ Set GetConfigFromSheet = d
645
+ End Function
646
+ #End If
647
+
648
+ Function GetConfig(configKey As String, Optional default As String = "", Optional source As String = "") As Variant
649
+ ' If source is provided, returns the value from this source only, otherwise it goes through all layers until
650
+ ' it finds a value (sheet -> directory -> user -> default)
651
+ ' An entry in xlwings.conf sheet overrides the config file/ribbon
652
+ Dim configValue As String
653
+
654
+ ' Sheet
655
+ #If App = "Microsoft Excel" Then
656
+ If source = "" Or source = "sheet" Then
657
+ If Application.Name = "Microsoft Excel" Then
658
+ 'Workbook Sheet Config
659
+ If SheetExists(ThisWorkbook, PROJECT_NAME & ".conf") = True Then
660
+ If GetConfigFromSheet(ThisWorkbook).Exists(configKey) = True Then
661
+ GetConfig = GetConfigFromSheet(ThisWorkbook).Item(configKey)
662
+ GetConfig = ExpandEnvironmentStrings(GetConfig)
663
+ Exit Function
664
+ End If
665
+ End If
666
+
667
+ 'Add-in Sheet Config (only for custom add-ins, unused by xlwings add-in)
668
+ If SheetExists(ThisWorkbook, PROJECT_NAME & ".conf") = True Then
669
+ If GetConfigFromSheet(ThisWorkbook).Exists(configKey) = True Then
670
+ GetConfig = GetConfigFromSheet(ThisWorkbook).Item(configKey)
671
+ GetConfig = ExpandEnvironmentStrings(GetConfig)
672
+ Exit Function
673
+ End If
674
+ End If
675
+ End If
676
+ End If
677
+ #End If
678
+
679
+ ' Directory Config
680
+ If source = "" Or source = "directory" Then
681
+ #If App = "Microsoft Excel" Then
682
+ If GetFullName(ThisWorkbook) <> "" Then ' Empty if local dir can't be figured out (e.g. SharePoint)
683
+ #Else
684
+ If InStr(GetDirectoryPath(), "://") = 0 Then ' Other Office apps: skip for synced SharePoint/OneDrive files
685
+ #End If
686
+ If FileExists(GetDirectoryConfigFilePath()) = True Then
687
+ If GetConfigFromFile(GetDirectoryConfigFilePath(), configKey, configValue) Then
688
+ GetConfig = configValue
689
+ GetConfig = ExpandEnvironmentStrings(GetConfig)
690
+ Exit Function
691
+ End If
692
+ End If
693
+ End If
694
+ End If
695
+
696
+ ' User Config
697
+ If source = "" Or source = "user" Then
698
+ If FileExists(GetConfigFilePath()) = True Then
699
+ If GetConfigFromFile(GetConfigFilePath(), configKey, configValue) Then
700
+ GetConfig = configValue
701
+ GetConfig = ExpandEnvironmentStrings(GetConfig)
702
+ Exit Function
703
+ End If
704
+ End If
705
+ End If
706
+
707
+ ' Defaults
708
+ GetConfig = default
709
+ GetConfig = ExpandEnvironmentStrings(GetConfig)
710
+
711
+ End Function
712
+
713
+ Function SaveConfigToFile(sFileName As String, sName As String, Optional sValue As String) As Boolean
714
+ 'Adopted from http://peltiertech.com/save-retrieve-information-text-files/
715
+
716
+ Dim iFileNumA As Long, iFileNumB As Long, lErrLast As Long
717
+ Dim sFile As String, sXFile As String, sVarName As String, sVarValue As String
718
+
719
+
720
+ #If Mac Then
721
+ If Not FileOrFolderExistsOnMac(ParentFolder(sFileName)) Then
722
+ #Else
723
+ If Len(Dir(ParentFolder(sFileName), vbDirectory)) = 0 Then
724
+ #End If
725
+ MkDir ParentFolder(sFileName)
726
+ End If
727
+
728
+ ' assume false unless variable is successfully saved
729
+ SaveConfigToFile = False
730
+
731
+ ' temporary file
732
+ sFile = sFileName
733
+ sXFile = sFileName & "_temp"
734
+
735
+ ' open text file to read settings
736
+ If FileExists(sFile) Then
737
+ 'replace existing settings file
738
+ iFileNumA = FreeFile
739
+ Open sFile For Input As iFileNumA
740
+ iFileNumB = FreeFile
741
+ Open sXFile For Output As iFileNumB
742
+ Do While Not EOF(iFileNumA)
743
+ Input #iFileNumA, sVarName, sVarValue
744
+ If sVarName <> sName Then
745
+ Write #iFileNumB, sVarName, sVarValue
746
+ End If
747
+ Loop
748
+ Write #iFileNumB, sName, sValue
749
+ SaveConfigToFile = True
750
+ Close #iFileNumA
751
+ Close #iFileNumB
752
+ FileCopy sXFile, sFile
753
+ Kill sXFile
754
+ Else
755
+ ' make new file
756
+ iFileNumB = FreeFile
757
+ Open sFile For Output As iFileNumB
758
+ Write #iFileNumB, sName, sValue
759
+ SaveConfigToFile = True
760
+ Close #iFileNumB
761
+ End If
762
+
763
+ End Function
764
+
765
+ Function GetConfigFromFile(sFile As String, sName As String, Optional sValue As String) As Boolean
766
+ 'Based on http://peltiertech.com/save-retrieve-information-text-files/
767
+
768
+ Dim iFileNum As Long, lErrLast As Long
769
+ Dim sVarName As String, sVarValue As String
770
+
771
+
772
+ ' assume false unless variable is found
773
+ GetConfigFromFile = False
774
+
775
+ ' open text file to read settings
776
+ If FileExists(sFile) Then
777
+ iFileNum = FreeFile
778
+ Open sFile For Input As iFileNum
779
+ Do While Not EOF(iFileNum)
780
+ Input #iFileNum, sVarName, sVarValue
781
+ If LCase(sVarName) = LCase(sName) Then
782
+ sValue = sVarValue
783
+ GetConfigFromFile = True
784
+ Exit Do
785
+ End If
786
+ Loop
787
+ Close #iFileNum
788
+ End If
789
+
790
+ End Function
791
+
792
+ 'Attribute VB_Name = "Extensions"
793
+ Function sql(query, ParamArray tables())
794
+ If TypeOf Application.Caller Is Range Then On Error GoTo failed
795
+ ReDim argsArray(1 To UBound(tables) - LBound(tables) + 2)
796
+ argsArray(1) = query
797
+ For K = LBound(tables) To UBound(tables)
798
+ argsArray(2 + K - LBound(tables)) = tables(K)
799
+ Next K
800
+ If has_dynamic_array() Then
801
+ sql = XLPy.CallUDF("xlwings.ext", "sql_dynamic", argsArray, ThisWorkbook, Application.Caller)
802
+ Else
803
+ sql = XLPy.CallUDF("xlwings.ext", "sql", argsArray, ThisWorkbook, Application.Caller)
804
+ End If
805
+ Exit Function
806
+ failed:
807
+ sql = Err.Description
808
+ End Function
809
+
810
+
811
+ 'Attribute VB_Name = "Utils"
812
+
813
+
814
+
815
+ Function WScript(Optional CreateNew As Boolean) As Object
816
+ Static Value As Object
817
+ If CreateNew Or Value Is Nothing Then Set Value = CreateObject("WScript.Shell")
818
+ Set WScript = Value
819
+ End Function
820
+
821
+ Function IsFullName(sFile As String) As Boolean
822
+ ' if sFile includes path, it contains path separator "\" or "/"
823
+ IsFullName = InStr(sFile, "\") + InStr(sFile, "/") > 0
824
+ End Function
825
+
826
+ Function FileExists(ByVal FileSpec As String) As Boolean
827
+ #If Mac Then
828
+ FileExists = FileOrFolderExistsOnMac(FileSpec)
829
+ #Else
830
+ FileExists = FileExistsOnWindows(FileSpec)
831
+ #End If
832
+ End Function
833
+
834
+ Function FileExistsOnWindows(ByVal FileSpec As String) As Boolean
835
+ ' by Karl Peterson MS MVP VB
836
+ Dim Attr As Long
837
+ ' Guard against bad FileSpec by ignoring errors
838
+ ' retrieving its attributes.
839
+ On Error Resume Next
840
+ Attr = GetAttr(FileSpec)
841
+ If Err.Number = 0 Then
842
+ ' No error, so something was found.
843
+ ' If Directory attribute set, then not a file.
844
+ FileExistsOnWindows = Not ((Attr And vbDirectory) = vbDirectory)
845
+ End If
846
+ End Function
847
+
848
+
849
+ Function FileOrFolderExistsOnMac(FileOrFolderstr As String) As Boolean
850
+ 'Ron de Bruin : 26-June-2015
851
+ 'Function to test whether a file or folder exist on a Mac in office 2011 and up
852
+ 'Uses AppleScript to avoid the problem with long names in Office 2011,
853
+ 'limit is max 32 characters including the extension in 2011.
854
+ Dim ScriptToCheckFileFolder As String
855
+ Dim TestStr As String
856
+
857
+ #If Mac Then
858
+ If Val(Application.VERSION) < 15 Then
859
+ ScriptToCheckFileFolder = "tell application " & Chr(34) & "System Events" & Chr(34) & _
860
+ "to return exists disk item (" & Chr(34) & FileOrFolderstr & Chr(34) & " as string)"
861
+ FileOrFolderExistsOnMac = MacScript(ScriptToCheckFileFolder)
862
+ Else
863
+ On Error Resume Next
864
+ TestStr = Dir(FileOrFolderstr, vbDirectory)
865
+ On Error GoTo 0
866
+ If Not TestStr = vbNullString Then FileOrFolderExistsOnMac = True
867
+ End If
868
+ #End If
869
+ End Function
870
+
871
+ Function ParentFolder(ByVal Folder)
872
+ #If Mac Then
873
+ ParentFolder = Left$(Folder, InStrRev(Folder, "/") - 1)
874
+ #Else
875
+ ParentFolder = Left$(Folder, InStrRev(Folder, "\") - 1)
876
+ #End If
877
+ End Function
878
+
879
+ Function GetDirectory(Path)
880
+ #If Mac Then
881
+ GetDirectory = Left(Path, InStrRev(Path, "/"))
882
+ #Else
883
+ GetDirectory = Left(Path, InStrRev(Path, "\"))
884
+ #End If
885
+ End Function
886
+
887
+ Function KillFileOnMac(Filestr As String)
888
+ 'Ron de Bruin
889
+ '30-July-2012
890
+ 'Delete files from a Mac.
891
+ 'Uses AppleScript to avoid the problem with long file names (on 2011 only)
892
+
893
+ Dim ScriptToKillFile As String
894
+
895
+ #If Mac Then
896
+ ScriptToKillFile = "tell application " & Chr(34) & "Finder" & Chr(34) & Chr(13)
897
+ ScriptToKillFile = ScriptToKillFile & "do shell script ""rm "" & quoted form of posix path of " & Chr(34) & Filestr & Chr(34) & Chr(13)
898
+ ScriptToKillFile = ScriptToKillFile & "end tell"
899
+
900
+ On Error Resume Next
901
+ MacScript (ScriptToKillFile)
902
+ On Error GoTo 0
903
+ #End If
904
+ End Function
905
+
906
+ Function ToMacPath(PosixPath As String) As String
907
+ ' This function transforms a Posix Path into a MacOS Path
908
+ ' E.g. "/Users/<User>" --> "MacintoshHD:Users:<User>"
909
+ #If Mac Then
910
+ ToMacPath = MacScript("set mac_path to POSIX file " & Chr(34) & PosixPath & Chr(34) & " as string")
911
+ #End If
912
+ End Function
913
+
914
+ Function GetMacDir(Name As String, Normalize As Boolean) As String
915
+ #If Mac Then
916
+ Select Case Name
917
+ Case "$HOME"
918
+ Name = "home folder"
919
+ Case "$APPLICATIONS"
920
+ Name = "applications folder"
921
+ Case "$DOCUMENTS"
922
+ Name = "documents folder"
923
+ Case "$DOWNLOADS"
924
+ Name = "downloads folder"
925
+ Case "$DESKTOP"
926
+ Name = "desktop folder"
927
+ Case "$TMPDIR"
928
+ Name = "temporary items"
929
+ End Select
930
+ GetMacDir = MacScript("return POSIX path of (path to " & Name & ") as string")
931
+ If Normalize = True Then
932
+ 'Normalize Excel sandbox location
933
+ GetMacDir = Replace(GetMacDir, "/Library/Containers/com.microsoft.Excel/Data", "")
934
+ End If
935
+ #Else
936
+ #End If
937
+ End Function
938
+
939
+
940
+ Function ToPosixPath(ByVal MacPath As String) As String
941
+ 'This function accepts relative paths with backward and forward slashes: ThisWorkbook & "\test"
942
+ ' E.g. "MacintoshHD:Users:<User>" --> "/Users/<User>"
943
+
944
+ Dim s As String
945
+ Dim LeadingSlash As Boolean
946
+
947
+ #If Mac Then
948
+ If MacPath = "" Then
949
+ ToPosixPath = ""
950
+ Else
951
+ ToPosixPath = Replace(MacPath, "\", "/")
952
+ ToPosixPath = MacScript("return POSIX path of (" & Chr(34) & MacPath & Chr(34) & ") as string")
953
+ End If
954
+ #End If
955
+ End Function
956
+
957
+ Sub ShowError(FileName As String, Optional Message As String = "")
958
+ ' Shows a MsgBox with the content of a text file
959
+
960
+ Dim Content As String
961
+ Dim ErrorSheet As Worksheet
962
+
963
+ Const OK_BUTTON_ERROR = 16
964
+ Const AUTO_DISMISS = 0
965
+
966
+ If Message = "" Then
967
+ Content = ReadFile(FileName)
968
+ Else
969
+ Content = Message
970
+ End If
971
+
972
+
973
+ If GetConfig("SHOW_ERROR_POPUPS", "True") = "False" Then
974
+ If SheetExists(ThisWorkbook, "Error") = False Then
975
+ Set ErrorSheet = ThisWorkbook.Sheets.Add()
976
+ ErrorSheet.Name = "Error"
977
+ Else
978
+ Set ErrorSheet = ThisWorkbook.Sheets("Error")
979
+ End If
980
+ ErrorSheet.Range("A1").Value = Content
981
+ Else
982
+ #If Mac Then
983
+ MsgBox Content, vbCritical, "Error"
984
+ #Else
985
+ Content = Content & vbCrLf
986
+ Content = Content & "Press Ctrl+C to copy this message to the clipboard."
987
+
988
+ WScript.Popup Content, AUTO_DISMISS, "Error", OK_BUTTON_ERROR
989
+ #End If
990
+ End If
991
+ End Sub
992
+
993
+ Function ExpandEnvironmentStrings(ByVal s As String)
994
+ ' Expand environment variables
995
+ Dim EnvString As String
996
+ Dim PathParts As Variant
997
+ Dim i As Integer
998
+ #If Mac Then
999
+ If Left(s, 1) = "$" Then
1000
+ PathParts = Split(s, "/")
1001
+ EnvString = PathParts(0)
1002
+ ExpandEnvironmentStrings = GetMacDir(EnvString, True)
1003
+ For i = 1 To UBound(PathParts)
1004
+ If Right$(ExpandEnvironmentStrings, 1) = "/" Then
1005
+ ExpandEnvironmentStrings = ExpandEnvironmentStrings & PathParts(i)
1006
+ Else
1007
+ ExpandEnvironmentStrings = ExpandEnvironmentStrings & "/" & PathParts(i)
1008
+ End If
1009
+ Next i
1010
+ Else
1011
+ ExpandEnvironmentStrings = s
1012
+ End If
1013
+ #Else
1014
+ ExpandEnvironmentStrings = WScript.ExpandEnvironmentStrings(s)
1015
+ #End If
1016
+ End Function
1017
+
1018
+ Function ReadFile(ByVal FileName As String)
1019
+ ' Read a text file
1020
+
1021
+ Dim Content As String
1022
+ Dim Token As String
1023
+ Dim FileNum As Integer
1024
+ Dim objShell As Object
1025
+ Dim LineBreak As Variant
1026
+
1027
+ #If Mac Then
1028
+ FileName = ToMacPath(FileName)
1029
+ LineBreak = vbLf
1030
+ #Else
1031
+ FileName = ExpandEnvironmentStrings(FileName)
1032
+ LineBreak = vbCrLf
1033
+ #End If
1034
+
1035
+ FileNum = FreeFile
1036
+ Content = ""
1037
+
1038
+ ' Read Text File
1039
+ Open FileName For Input As #FileNum
1040
+ Do While Not EOF(FileNum)
1041
+ Line Input #FileNum, Token
1042
+ Content = Content & Token & LineBreak
1043
+ Loop
1044
+ Close #FileNum
1045
+
1046
+ ReadFile = Content
1047
+ End Function
1048
+
1049
+ #If App = "Microsoft Excel" Then
1050
+ Function SheetExists(wb As Workbook, sheetName As String) As Boolean
1051
+ Dim sht As Worksheet
1052
+ On Error Resume Next
1053
+ Set sht = wb.Sheets(sheetName)
1054
+ On Error GoTo 0
1055
+ SheetExists = Not sht Is Nothing
1056
+ End Function
1057
+ #End If
1058
+
1059
+ Function GetBaseName(wb As String) As String
1060
+ Dim extension As String
1061
+ extension = LCase$(Right$(wb, 4))
1062
+ If extension = ".xls" Or extension = ".xla" Or extension = ".xlt" Then
1063
+ GetBaseName = Left$(wb, Len(wb) - 4)
1064
+ Else
1065
+ GetBaseName = Left$(wb, Len(wb) - 5)
1066
+ End If
1067
+ End Function
1068
+
1069
+ Function has_dynamic_array() As Boolean
1070
+ has_dynamic_array = False
1071
+ On Error GoTo ErrHandler
1072
+ Application.WorksheetFunction.Unique ("dummy")
1073
+ has_dynamic_array = True
1074
+ Exit Function
1075
+ ErrHandler:
1076
+ has_dynamic_array = False
1077
+ End Function
1078
+
1079
+ Public Function CreateGUID() As String
1080
+ Randomize Timer() + Application.Hwnd
1081
+ ' https://stackoverflow.com/a/46474125/918626
1082
+ Do While Len(CreateGUID) < 32
1083
+ If Len(CreateGUID) = 16 Then
1084
+ '17th character holds version information
1085
+ CreateGUID = CreateGUID & Hex$(8 + CInt(Rnd * 3))
1086
+ End If
1087
+ CreateGUID = CreateGUID & Hex$(CInt(Rnd * 15))
1088
+ Loop
1089
+ CreateGUID = Mid(CreateGUID, 1, 8) & "-" & Mid(CreateGUID, 9, 4) & "-" & Mid(CreateGUID, 13, 4) & "-" & Mid(CreateGUID, 17, 4) & "-" & Mid(CreateGUID, 21, 12)
1090
+ End Function
1091
+
1092
+ Function CheckConda(CondaPath As String) As Boolean
1093
+ ' Check if the conda executable exists.
1094
+ ' If it doesn't, conda is too old and the Interpreter setting has to be used instead of Conda settings
1095
+ Dim condaExecutable As String
1096
+ Dim condaExists As Boolean
1097
+ #If Mac Then
1098
+ condaExecutable = CondaPath & "\condabin\conda"
1099
+ #Else
1100
+ condaExecutable = CondaPath & "\condabin\conda.bat"
1101
+ #End If
1102
+ ' Replace space escape character ^ to check if path exists
1103
+ condaExists = FileExists(Replace(condaExecutable, "^", ""))
1104
+ If condaExists = False And CondaPath <> "" Then
1105
+ MsgBox "Your Conda version seems to be too old for the Conda settings. Use the Interpreter setting instead."
1106
+ End If
1107
+ CheckConda = condaExists
1108
+ End Function
1109
+
1110
+ #If App = "Microsoft Excel" Then
1111
+ Function GetFullName(wb As Workbook) As String
1112
+ ' The only case where this is still used is for directory-based config files, otherwise this is now handled in Python
1113
+ ' Unlike the Python version, this doesn't work for SharePoint and will just ignore a directory-based config file silently
1114
+
1115
+ Dim total_found, i_parsing, i_env_var, slash_number As Integer
1116
+ Dim found_path, one_drive_path, full_path_name, this_found_path As String
1117
+
1118
+ ' In the majority of cases, ThisWorkbook.FullName will provide the path of the
1119
+ ' Excel workbook correctly. Unfortunately, when the user is using OneDrive
1120
+ ' this doesn't work. This function will attempt to find the LOCAL path.
1121
+ ' This uses code from Daniel Guetta and
1122
+ ' https://stackoverflow.com/questions/33734706/excels-fullname-property-with-onedrive
1123
+
1124
+ If InStr(wb.FullName, "://") = 0 Or wb.Path = "" Then
1125
+ GetFullName = wb.FullName
1126
+ Exit Function
1127
+ End If
1128
+
1129
+ ' According to the link above, there are three possible environment variables
1130
+ ' the user's OneDrive folder could be located in
1131
+ ' "OneDriveCommercial", "OneDriveConsumer", "OneDrive"
1132
+ '
1133
+ ' Furthermore, there are two possible formats for OneDrive URLs
1134
+ ' 1. "https://companyName-my.sharepoint.com/personal/userName_domain_com/Documents" & file.FullName
1135
+ ' 2. "https://d.docs.live.net/d7bbaa#######1/" & file.FullName
1136
+ ' In the first case, we can find the true path by just looking for everything after /Documents. In the
1137
+ ' second, we need to look for the fourth slash in the URL
1138
+ '
1139
+ ' The code below will try every combination of the three environment variables above, and
1140
+ ' each of the two methods of parsing the URL. The file is found in *exactly* one of those
1141
+ ' locations, then we're good to go.
1142
+ '
1143
+ ' Note that this still leaves a gap - if this file (file A) is in a location that is NOT covered by the
1144
+ ' eventualities above AND a file of the exact same name (file B) exists in one of the locations that is
1145
+ ' covered above, then this function will identify File B's location as the location of this workbook,
1146
+ ' which would be wrong
1147
+ total_found = 0
1148
+
1149
+ For i_parsing = 1 To 2
1150
+ If i_parsing = 1 Then
1151
+ ' Parse using method 1 above; find /Documents and take everything after, INCLUDING the
1152
+ ' leading slash
1153
+ If InStr(1, wb.FullName, "/Documents") Then
1154
+ full_path_name = Mid(wb.FullName, InStr(1, wb.FullName, "/Documents") + Len("/Documents"))
1155
+ Else
1156
+ full_path_name = ""
1157
+ End If
1158
+ Else
1159
+ ' Parse using method 2; find everything after the fourth slash, including that fourth
1160
+ ' slash
1161
+ Dim i_pos As Integer
1162
+
1163
+ ' Start at the last slash in https://
1164
+ i_pos = 8
1165
+
1166
+ For slash_number = 1 To 2
1167
+ i_pos = InStr(i_pos + 1, wb.FullName, "/")
1168
+ Next slash_number
1169
+
1170
+ full_path_name = Mid(wb.FullName, i_pos)
1171
+ End If
1172
+
1173
+ ' Replace forward slahes with backslashes on Windows
1174
+ full_path_name = Replace(full_path_name, "/", Application.pathSeparator)
1175
+
1176
+
1177
+ If full_path_name <> "" Then
1178
+ #If Not Mac Then
1179
+ For i_env_var = 1 To 3
1180
+ one_drive_path = Environ(Choose(i_env_var, "OneDriveCommercial", "OneDriveConsumer", "OneDrive"))
1181
+
1182
+ If (one_drive_path <> "") And FileExists(one_drive_path & full_path_name) Then
1183
+ this_found_path = one_drive_path & full_path_name
1184
+
1185
+ If this_found_path <> found_path Then
1186
+ total_found = total_found + 1
1187
+ found_path = this_found_path
1188
+ End If
1189
+ End If
1190
+ Next i_env_var
1191
+ #End If
1192
+ End If
1193
+ Next i_parsing
1194
+
1195
+ If total_found = 1 Then
1196
+ GetFullName = found_path
1197
+ Exit Function
1198
+ End If
1199
+
1200
+ End Function
1201
+ #End If
1202
+
1203
+ Function GetAzureAdAccessToken( _
1204
+ Optional tenantId As String, _
1205
+ Optional clientId As String, _
1206
+ Optional port As String, _
1207
+ Optional scopes As String, _
1208
+ Optional username As String, _
1209
+ Optional cliPath As String _
1210
+ )
1211
+ Dim nowTs As Long, expiresTs As Long
1212
+ Dim kwargs As String
1213
+
1214
+ If tenantId = "" Then
1215
+ tenantId = GetConfig("AZUREAD_TENANT_ID")
1216
+ End If
1217
+ If clientId = "" Then
1218
+ clientId = GetConfig("AZUREAD_CLIENT_ID")
1219
+ End If
1220
+ If port = "" Then
1221
+ port = GetConfig("AZUREAD_PORT")
1222
+ End If
1223
+ If scopes = "" Then
1224
+ scopes = GetConfig("AZUREAD_SCOPES")
1225
+ End If
1226
+ If username = "" Then
1227
+ username = GetConfig("AZUREAD_USERNAME")
1228
+ End If
1229
+ If cliPath = "" Then
1230
+ cliPath = GetConfig("CLI_PATH")
1231
+ End If
1232
+ If cliPath = "" Then
1233
+ kwargs = "tenant_id='" & tenantId & "', "
1234
+ kwargs = kwargs & "client_id='" & clientId & "', "
1235
+ If port <> "" Then
1236
+ kwargs = kwargs & "port='" & port & "', "
1237
+ End If
1238
+ If scopes <> "" Then
1239
+ kwargs = kwargs & "scopes='" & scopes & "', "
1240
+ End If
1241
+ If username <> "" Then
1242
+ kwargs = kwargs & "username='" & username & "', "
1243
+ End If
1244
+ Else
1245
+ kwargs = "--tenant_id=" & tenantId & " "
1246
+ kwargs = kwargs & "--client_id=" & clientId & " "
1247
+ If port <> "" Then
1248
+ kwargs = kwargs & "--port=" & port & " "
1249
+ End If
1250
+ If scopes <> "" Then
1251
+ kwargs = kwargs & "--scopes=" & scopes & " "
1252
+ End If
1253
+ If username <> "" Then
1254
+ kwargs = kwargs & "--username=" & username & " "
1255
+ End If
1256
+ End If
1257
+
1258
+ expiresTs = GetConfig("AZUREAD_ACCESS_TOKEN_EXPIRES_ON_" & clientId, 0)
1259
+ nowTs = DateDiff("s", #1/1/1970#, ConvertToUtc(Now()))
1260
+
1261
+ If (expiresTs > 0) And (nowTs < (expiresTs - 30)) Then
1262
+ GetAzureAdAccessToken = GetConfig("AZUREAD_ACCESS_TOKEN_" & clientId)
1263
+ Exit Function
1264
+ Else
1265
+ If cliPath <> "" Then
1266
+ RunFrozenPython cliPath, "auth azuread " & kwargs
1267
+ Else
1268
+ RunPython "from xlwings import cli;cli._auth_aad(" & kwargs & ")"
1269
+ End If
1270
+ #If Mac Then
1271
+ ' RunPython on macOS is async: 60s should be enough if you have to login from scratch
1272
+ Dim i As Integer
1273
+ For i = 1 To 60
1274
+ expiresTs = GetConfig("AZUREAD_ACCESS_TOKEN_EXPIRES_ON_" & clientId, 0)
1275
+ If (nowTs < (expiresTs - 30)) Then
1276
+ GetAzureAdAccessToken = GetConfig("AZUREAD_ACCESS_TOKEN_" & clientId)
1277
+ Exit Function
1278
+ End If
1279
+ Application.Wait (Now + TimeValue("0:00:01"))
1280
+ Next i
1281
+ #Else
1282
+ GetAzureAdAccessToken = GetConfig("AZUREAD_ACCESS_TOKEN_" & clientId)
1283
+ #End If
1284
+ End If
1285
+ End Function
1286
+
1287
+
1288
+
1289
+ 'Attribute VB_Name = "Remote"
1290
+
1291
+ Function RunRemotePython( _
1292
+ url As String, _
1293
+ Optional auth As String, _
1294
+ Optional apiKey As String, _
1295
+ Optional include As String, _
1296
+ Optional exclude As String, _
1297
+ Optional headers As Variant, _
1298
+ Optional timeout As Long, _
1299
+ Optional proxyServer As String, _
1300
+ Optional proxyBypassList As String, _
1301
+ Optional proxyUsername As String, _
1302
+ Optional proxyPassword As String, _
1303
+ Optional enableAutoProxy As String, _
1304
+ Optional insecure As String, _
1305
+ Optional followRedirects As String _
1306
+ )
1307
+
1308
+ Dim wb As Workbook
1309
+ Set wb = ThisWorkbook
1310
+
1311
+ ' Config
1312
+ ' takes the first value it finds in this order:
1313
+ ' func arg, sheet config, directory config, user config
1314
+ If include = "" Then
1315
+ include = GetConfig("INCLUDE")
1316
+ End If
1317
+ Dim includeArray() As String
1318
+ If include <> "" Then
1319
+ includeArray = Split(include, ",")
1320
+ End If
1321
+
1322
+ If exclude = "" Then
1323
+ exclude = GetConfig("EXCLUDE")
1324
+ End If
1325
+ Dim excludeArray() As String
1326
+ If exclude <> "" Then
1327
+ excludeArray = Split(exclude, ",")
1328
+ End If
1329
+
1330
+ If include <> "" And exclude <> "" Then
1331
+ MsgBox "Either use 'include' or 'exclude', but not both!", vbCritical
1332
+ Exit Function
1333
+ End If
1334
+
1335
+ If include <> "" Then
1336
+ Dim i As Integer
1337
+ For i = 1 To wb.Worksheets.Count
1338
+ If Not IsInArray(wb.Worksheets(i).Name, includeArray) Then
1339
+ ReDim Preserve excludeArray(0 To i)
1340
+ excludeArray(i) = wb.Worksheets(i).Name
1341
+ End If
1342
+ Next
1343
+ End If
1344
+
1345
+ If timeout = 0 Then
1346
+ timeout = GetConfig("TIMEOUT", 0)
1347
+ End If
1348
+ If enableAutoProxy = "" Then
1349
+ enableAutoProxy = GetConfig("ENABLE_AUTO_PROXY", False)
1350
+ End If
1351
+ If insecure = "" Then
1352
+ insecure = GetConfig("INSECURE", False)
1353
+ End If
1354
+ If followRedirects = "" Then
1355
+ followRedirects = GetConfig("FOLLOW_REDIRECTS", False)
1356
+ End If
1357
+ If proxyPassword = "" Then
1358
+ proxyPassword = GetConfig("PROXY_PASSWORD", "")
1359
+ End If
1360
+ If proxyUsername = "" Then
1361
+ proxyUsername = GetConfig("PROXY_USERNAME", "")
1362
+ End If
1363
+ If proxyServer = "" Then
1364
+ proxyServer = GetConfig("PROXY_SERVER", "")
1365
+ End If
1366
+ If proxyBypassList = "" Then
1367
+ proxyBypassList = GetConfig("PROXY_BYPASS_LIST", "")
1368
+ End If
1369
+ If apiKey = "" Then ' Deprecated: replaced by "auth"
1370
+ apiKey = GetConfig("API_KEY", "")
1371
+ End If
1372
+ If auth = "" Then
1373
+ auth = GetConfig("AUTH", "")
1374
+ End If
1375
+
1376
+ ' Request payload
1377
+ Dim payload As New Dictionary
1378
+ payload.Add "client", "VBA"
1379
+ payload.Add "version", XLWINGS_VERSION
1380
+
1381
+ Dim bookPayload As New Dictionary
1382
+ bookPayload.Add "name", ThisWorkbook.Name
1383
+ bookPayload.Add "active_sheet_index", ActiveSheet.Index - 1
1384
+ If TypeOf Selection Is Range Then
1385
+ bookPayload.Add "selection", Application.Selection.Address(False, False)
1386
+ Else
1387
+ bookPayload.Add "selection", Null
1388
+ End If
1389
+ payload.Add "book", bookPayload
1390
+
1391
+ ' Names
1392
+ Dim myname As Name
1393
+ Dim mynames() As Dictionary
1394
+ Dim nNames As Integer
1395
+ Dim namedRangeCount As Integer
1396
+ Dim iName As Integer
1397
+
1398
+ nNames = wb.Names.Count
1399
+ namedRangeCount = 0
1400
+
1401
+ If nNames > 0 Then
1402
+ For iName = 1 To nNames
1403
+ Set myname = wb.Names(iName)
1404
+ Dim nameDict As Dictionary
1405
+ Set nameDict = New Dictionary
1406
+ Dim isNamedRange As Boolean
1407
+ Dim testRange As Range
1408
+ Dim isBookScope As Boolean
1409
+ nameDict.Add "name", myname.Name
1410
+ isNamedRange = False
1411
+ On Error Resume Next
1412
+ Set testRange = myname.RefersToRange
1413
+ If Err.Number = 0 Then isNamedRange = True
1414
+ On Error GoTo 0
1415
+ If isNamedRange Then
1416
+ If TypeOf myname.Parent Is Workbook Then isBookScope = True Else isBookScope = False
1417
+ nameDict.Add "sheet_index", myname.RefersToRange.Parent.Index - 1
1418
+ nameDict.Add "address", myname.RefersToRange.Address(False, False)
1419
+ nameDict.Add "book_scope", isBookScope
1420
+ If isBookScope = True Then
1421
+ nameDict.Add "scope_sheet_name", Null
1422
+ nameDict.Add "scope_sheet_index", Null
1423
+ Else
1424
+ nameDict.Add "scope_sheet_name", myname.Parent.Name
1425
+ nameDict.Add "scope_sheet_index", myname.Parent.Index - 1
1426
+ End If
1427
+ ReDim Preserve mynames(namedRangeCount)
1428
+ Set mynames(namedRangeCount) = nameDict
1429
+ namedRangeCount = namedRangeCount + 1
1430
+ End If
1431
+ Next
1432
+ If namedRangeCount > 0 Then
1433
+ payload.Add "names", mynames
1434
+ Else
1435
+ payload.Add "names", Array()
1436
+ End If
1437
+ Else
1438
+ payload.Add "names", Array()
1439
+ End If
1440
+
1441
+ Dim sheetsPayload() As Dictionary
1442
+ ReDim sheetsPayload(wb.Worksheets.Count - 1)
1443
+ For i = 1 To wb.Worksheets.Count
1444
+ Dim sheetDict As Dictionary
1445
+ Set sheetDict = New Dictionary
1446
+ sheetDict.Add "name", wb.Worksheets(i).Name
1447
+
1448
+ ' Pictures
1449
+ Dim pic As Shape
1450
+ Dim pics() As Dictionary
1451
+ Dim nShapes As Integer
1452
+ Dim iShape As Integer
1453
+ Dim iPic As Integer
1454
+ nShapes = wb.Worksheets(i).Shapes.Count
1455
+ If (nShapes > 0) And Not (IsInArray(wb.Worksheets(i).Name, excludeArray)) Then
1456
+ iPic = 0
1457
+ For iShape = 1 To nShapes
1458
+ Set pic = wb.Worksheets(i).Shapes(iShape)
1459
+ If pic.Type = msoPicture Then
1460
+ ReDim Preserve pics(iPic)
1461
+ Dim picDict As Dictionary
1462
+ Set picDict = New Dictionary
1463
+ picDict.Add "name", pic.Name
1464
+ picDict.Add "height", pic.Height
1465
+ picDict.Add "width", pic.Width
1466
+ Set pics(iPic) = picDict
1467
+ iPic = iPic + 1
1468
+ End If
1469
+ Next
1470
+ sheetDict.Add "pictures", pics
1471
+ Else
1472
+ sheetDict.Add "pictures", Array()
1473
+ End If
1474
+
1475
+ ' Tables
1476
+ Dim table As ListObject
1477
+ Dim tables() As Dictionary
1478
+ Dim nTables As Integer
1479
+ Dim iTable As Integer
1480
+ nTables = wb.Worksheets(i).ListObjects.Count
1481
+ If (nTables > 0) And Not (IsInArray(wb.Worksheets(i).Name, excludeArray)) Then
1482
+ For iTable = 1 To nTables
1483
+ Set table = wb.Worksheets(i).ListObjects(iTable)
1484
+ ReDim Preserve tables(iTable - 1)
1485
+ Dim tableDict As Dictionary
1486
+ Set tableDict = New Dictionary
1487
+ tableDict.Add "name", table.Name
1488
+ tableDict.Add "range_address", table.Range.Address
1489
+ If table.ShowHeaders Then
1490
+ tableDict.Add "header_row_range_address", table.HeaderRowRange.Address
1491
+ Else
1492
+ tableDict.Add "header_row_range_address", Null
1493
+ End If
1494
+ If table.DataBodyRange Is Nothing Then
1495
+ tableDict.Add "data_body_range_address", Null
1496
+ Else
1497
+ tableDict.Add "data_body_range_address", table.DataBodyRange.Address
1498
+ End If
1499
+ If table.ShowTotals Then
1500
+ tableDict.Add "total_row_range_address", table.TotalsRowRange.Address
1501
+ Else
1502
+ tableDict.Add "total_row_range_address", Null
1503
+ End If
1504
+ tableDict.Add "show_headers", table.ShowHeaders
1505
+ tableDict.Add "show_totals", table.ShowTotals
1506
+ tableDict.Add "table_style", table.TableStyle.Name
1507
+ tableDict.Add "show_autofilter", table.ShowAutoFilter
1508
+ Set tables(iTable - 1) = tableDict
1509
+ Next
1510
+ sheetDict.Add "tables", tables
1511
+ Else
1512
+ sheetDict.Add "tables", Array()
1513
+ End If
1514
+
1515
+ ' Values
1516
+ Dim values As Variant
1517
+ If IsInArray(wb.Worksheets(i).Name, excludeArray) Then
1518
+ values = Array(Array())
1519
+ ElseIf IsEmpty(wb.Worksheets(i).UsedRange.Value) Then
1520
+ values = Array(Array())
1521
+ Else
1522
+ Dim startRow As Integer, startCol As Integer
1523
+ Dim nRows As Integer, nCols As Integer
1524
+ Dim myUsedRange As Range
1525
+ With wb.Worksheets(i).UsedRange
1526
+ startRow = .Row
1527
+ startCol = .Column
1528
+ nRows = .Rows.Count
1529
+ nCols = .Columns.Count
1530
+ End With
1531
+ With wb.Worksheets(i)
1532
+ Set myUsedRange = .Range( _
1533
+ .Cells(1, 1), _
1534
+ .Cells(startRow + nRows - 1, startCol + nCols - 1) _
1535
+ )
1536
+ values = myUsedRange.Value
1537
+ If myUsedRange.Count = 1 Then
1538
+ values = Array(Array(values))
1539
+ End If
1540
+ End With
1541
+ End If
1542
+ sheetDict.Add "values", values
1543
+ Set sheetsPayload(i - 1) = sheetDict
1544
+ Next
1545
+ payload.Add "sheets", sheetsPayload
1546
+
1547
+ Dim myRequest As New WebRequest
1548
+ Set myRequest.Body = payload
1549
+
1550
+ ' Debug.Print myRequest.Body
1551
+
1552
+ ' Headers
1553
+ ' Expected as Dictionary and currently not supported via xlwings.conf
1554
+ ' Providing the Authorization header will ignore the API_KEY
1555
+ Dim authHeader As Boolean
1556
+ authHeader = False
1557
+ If Not IsMissing(headers) Then
1558
+ Dim myKey As Variant
1559
+ For Each myKey In headers.Keys
1560
+ myRequest.AddHeader CStr(myKey), headers(myKey)
1561
+ Next
1562
+ If headers.Exists("Authorization") Then
1563
+ authHeader = True
1564
+ End If
1565
+ End If
1566
+
1567
+ If authHeader = False Then
1568
+ If apiKey <> "" Then ' Deprecated: replaced by "auth"
1569
+ myRequest.AddHeader "Authorization", apiKey
1570
+ End If
1571
+ If auth <> "" Then
1572
+ myRequest.AddHeader "Authorization", auth
1573
+ End If
1574
+ End If
1575
+
1576
+ ' API call
1577
+ myRequest.Method = WebMethod.HttpPost
1578
+ myRequest.Format = WebFormat.Json
1579
+
1580
+ Dim myClient As New WebClient
1581
+ myClient.BaseUrl = url
1582
+ If timeout <> 0 Then
1583
+ myClient.TimeoutMs = timeout
1584
+ Else
1585
+ myClient.TimeoutMs = 30000 ' Set default to 30s
1586
+ End If
1587
+ If proxyBypassList <> "" Then
1588
+ myClient.proxyBypassList = proxyBypassList
1589
+ End If
1590
+ If proxyServer <> "" Then
1591
+ myClient.proxyServer = proxyServer
1592
+ End If
1593
+ If proxyUsername <> "" Then
1594
+ myClient.proxyUsername = proxyUsername
1595
+ End If
1596
+ If proxyPassword <> "" Then
1597
+ myClient.proxyPassword = proxyPassword
1598
+ End If
1599
+ If enableAutoProxy <> False Then
1600
+ myClient.enableAutoProxy = enableAutoProxy
1601
+ End If
1602
+ If insecure <> False Then
1603
+ myClient.insecure = insecure
1604
+ End If
1605
+ If followRedirects <> False Then
1606
+ myClient.followRedirects = followRedirects
1607
+ End If
1608
+
1609
+ Dim myResponse As WebResponse
1610
+ Set myResponse = myClient.Execute(myRequest)
1611
+
1612
+ ' Debug.Print myResponse.Content
1613
+
1614
+ ' Parse JSON response and run functions
1615
+ If myResponse.StatusCode = WebStatusCode.Ok Then
1616
+ Dim action As Dictionary
1617
+ For Each action In myResponse.Data("actions")
1618
+ Application.Run action("func"), wb, action
1619
+ Next
1620
+ Else
1621
+ If myResponse.Content <> "" Then
1622
+ MsgBox myResponse.Content, vbCritical, "Error"
1623
+ Else
1624
+ MsgBox myResponse.StatusDescription & " (" & myResponse.StatusCode & ")", vbCritical, "Error"
1625
+ End If
1626
+ End If
1627
+
1628
+ End Function
1629
+
1630
+ ' Helpers
1631
+ Function GetRange(wb As Workbook, action As Dictionary)
1632
+ If action("row_count") = 1 And action("column_count") = 1 Then
1633
+ Set GetRange = wb.Worksheets( _
1634
+ action("sheet_position") + 1).Cells(action("start_row") + 1, _
1635
+ action("start_column") + 1 _
1636
+ )
1637
+ Else
1638
+ With wb.Worksheets(action("sheet_position") + 1)
1639
+ Set GetRange = .Range( _
1640
+ .Cells(action("start_row") + 1, action("start_column") + 1), _
1641
+ .Cells( _
1642
+ action("start_row") + action("row_count"), _
1643
+ action("start_column") + action("column_count") _
1644
+ ) _
1645
+ )
1646
+ End With
1647
+ End If
1648
+ End Function
1649
+
1650
+ Function Utf8ToUtf16(ByVal strText As String) As String
1651
+ ' macOs only: apparently, Excel uses UTF-16 to represent string literals
1652
+ ' Taken from https://stackoverflow.com/a/64624336/918626
1653
+ Dim i&, l1&, l2&, l3&, l4&, l&
1654
+ For i = 1 To Len(strText)
1655
+ l1 = Asc(Mid(strText, i, 1))
1656
+ If i + 1 <= Len(strText) Then l2 = Asc(Mid(strText, i + 1, 1))
1657
+ If i + 2 <= Len(strText) Then l3 = Asc(Mid(strText, i + 2, 1))
1658
+ If i + 3 <= Len(strText) Then l4 = Asc(Mid(strText, i + 3, 1))
1659
+ Select Case l1
1660
+ Case 1 To 127
1661
+ l = l1
1662
+ Case 194 To 223
1663
+ l = ((l1 And &H1F) * 2 ^ 6) Or (l2 And &H3F)
1664
+ i = i + 1
1665
+ Case 224 To 239
1666
+ l = ((l1 And &HF) * 2 ^ 12) Or ((l2 And &H3F) * 2 ^ 6) Or (l3 And &H3F)
1667
+ i = i + 2
1668
+ Case 240 To 255
1669
+ l = ((l1 And &H7) * 2 ^ 18) Or ((l2 And &H3F) * 2 ^ 12) Or ((l3 And &H3F) * 2 ^ 6) Or (l4 And &H3F)
1670
+ i = i + 4
1671
+ Case Else
1672
+ l = 63 ' question mark
1673
+ End Select
1674
+ Utf8ToUtf16 = Utf8ToUtf16 & IIf(l < 55296, WorksheetFunction.Unichar(l), "?")
1675
+ Next i
1676
+ End Function
1677
+
1678
+ Function HexToRgb(ByVal hexColor As String) As Variant
1679
+ ' Based on https://stackoverflow.com/a/63779233/918626
1680
+ Dim red As String, green As String, blue As String
1681
+ hexColor = Replace(hexColor, "#", "")
1682
+ red = Val("&H" & Mid(hexColor, 1, 2))
1683
+ green = Val("&H" & Mid(hexColor, 3, 2))
1684
+ blue = Val("&H" & Mid(hexColor, 5, 2))
1685
+ HexToRgb = RGB(red, green, blue)
1686
+ End Function
1687
+
1688
+ Function IsInArray(stringToBeFound As String, arr As Variant) As Boolean
1689
+ ' Based on https://stackoverflow.com/a/38268261/918626
1690
+ If IsEmpty(arr) Then
1691
+ IsInArray = False
1692
+ Exit Function
1693
+ End If
1694
+ Dim i As Integer
1695
+ On Error GoTo ErrHandler
1696
+ For i = LBound(arr) To UBound(arr)
1697
+ If Trim(arr(i)) = stringToBeFound Then
1698
+ IsInArray = True
1699
+ Exit Function
1700
+ End If
1701
+ Next i
1702
+ On Error GoTo 0
1703
+ IsInArray = False
1704
+ ErrHandler:
1705
+ IsInArray = False
1706
+ End Function
1707
+
1708
+ Function base64ToPic(base64string As Variant) As String
1709
+ Dim tempPath As String
1710
+ ' TODO: handle other image formats than png
1711
+ #If Mac Then
1712
+ tempPath = GetMacDir("$HOME", False) & "xlwings-" & CreateGUID() & ".png"
1713
+ Dim rv As Variant
1714
+ rv = ExecuteInShell("echo """ & base64string & """ | base64 -d > " & tempPath).Output
1715
+ #Else
1716
+ tempPath = Environ("Temp") & "\xlwings-" & CreateGUID() & ".png"
1717
+ Open tempPath For Binary As #1
1718
+ Put #1, 1, Base64Decode(base64string)
1719
+ Close #1
1720
+ #End If
1721
+ base64ToPic = tempPath
1722
+ End Function
1723
+
1724
+ ' Functions
1725
+ Sub setValues(wb As Workbook, action As Dictionary)
1726
+ Dim arr() As Variant
1727
+ Dim i As Long, j As Long
1728
+ Dim values As Collection, valueRow As Collection
1729
+
1730
+ Set values = action("values")
1731
+ ReDim arr(values.Count, values(1).Count)
1732
+
1733
+ For i = 1 To values.Count
1734
+ Set valueRow = values(i)
1735
+ For j = 1 To valueRow.Count
1736
+ On Error Resume Next
1737
+ ' TODO: will be replaced when backend sends location of dates
1738
+ arr(i - 1, j - 1) = WebHelpers.ParseIso(valueRow(j))
1739
+ If Err.Number <> 0 Then
1740
+ #If Mac Then
1741
+ If Application.IsText(valueRow(j)) Then
1742
+ arr(i - 1, j - 1) = Utf8ToUtf16(valueRow(j))
1743
+ Else
1744
+ arr(i - 1, j - 1) = valueRow(j)
1745
+ End If
1746
+ #Else
1747
+ arr(i - 1, j - 1) = valueRow(j)
1748
+ #End If
1749
+ End If
1750
+ On Error GoTo 0
1751
+ Next j
1752
+ Next i
1753
+ GetRange(wb, action).Value = arr
1754
+ End Sub
1755
+
1756
+ Sub rangeClearContents(wb As Workbook, action As Dictionary)
1757
+ GetRange(wb, action).ClearContents
1758
+ End Sub
1759
+
1760
+ Sub rangeClearFormats(wb As Workbook, action As Dictionary)
1761
+ GetRange(wb, action).ClearFormats
1762
+ End Sub
1763
+
1764
+ Sub rangeClear(wb As Workbook, action As Dictionary)
1765
+ GetRange(wb, action).Clear
1766
+ End Sub
1767
+
1768
+ Sub addSheet(wb As Workbook, action As Dictionary)
1769
+ Dim mysheet As Worksheet
1770
+ Set mysheet = wb.Sheets.Add
1771
+ mysheet.Move After:=Worksheets(action("args")(1) + 1)
1772
+ If Not IsNull(action("args")(2)) Then
1773
+ mysheet.Name = action("args")(2)
1774
+ End If
1775
+ End Sub
1776
+
1777
+ Sub setSheetName(wb As Workbook, action As Dictionary)
1778
+ wb.Sheets(action("sheet_position") + 1).Name = action("args")(1)
1779
+ End Sub
1780
+
1781
+ Sub setAutofit(wb As Workbook, action As Dictionary)
1782
+ If action("args")(1) = "columns" Then
1783
+ GetRange(wb, action).Columns.AutoFit
1784
+ Else
1785
+ GetRange(wb, action).Rows.AutoFit
1786
+ End If
1787
+ End Sub
1788
+
1789
+ Sub setRangeColor(wb As Workbook, action As Dictionary)
1790
+ GetRange(wb, action).Interior.Color = HexToRgb(action("args")(1))
1791
+ End Sub
1792
+
1793
+ Sub activateSheet(wb As Workbook, action As Dictionary)
1794
+ wb.Sheets(action("args")(1) + 1).Activate
1795
+ End Sub
1796
+
1797
+ Sub addHyperlink(wb As Workbook, action As Dictionary)
1798
+ GetRange(wb, action).Hyperlinks.Add _
1799
+ Anchor:=GetRange(wb, action), _
1800
+ Address:=action("args")(1), _
1801
+ TextToDisplay:=action("args")(2), _
1802
+ ScreenTip:=action("args")(3)
1803
+ End Sub
1804
+
1805
+ Sub setNumberFormat(wb As Workbook, action As Dictionary)
1806
+ GetRange(wb, action).NumberFormat = action("args")(1)
1807
+ End Sub
1808
+
1809
+ Sub setPictureName(wb As Workbook, action As Dictionary)
1810
+ wb.Sheets(action("sheet_position") + 1).Pictures(action("args")(1) + 1).Name = action("args")(2)
1811
+ End Sub
1812
+
1813
+ Sub setPictureHeight(wb As Workbook, action As Dictionary)
1814
+ wb.Sheets(action("sheet_position") + 1).Pictures(action("args")(1) + 1).Height = action("args")(2)
1815
+ End Sub
1816
+
1817
+ Sub setPictureWidth(wb As Workbook, action As Dictionary)
1818
+ wb.Sheets(action("sheet_position") + 1).Pictures(action("args")(1) + 1).Width = action("args")(2)
1819
+ End Sub
1820
+
1821
+ Sub deletePicture(wb As Workbook, action As Dictionary)
1822
+ wb.Sheets(action("sheet_position") + 1).Pictures(action("args")(1) + 1).Delete
1823
+ End Sub
1824
+
1825
+ Sub addPicture(wb As Workbook, action As Dictionary)
1826
+ Dim tempPath As String
1827
+ Dim anchorCell As Range
1828
+ Dim imgLeft, imgTop, imgWidth, imgHeight As Long
1829
+
1830
+ tempPath = base64ToPic(action("args")(1))
1831
+ With wb.Sheets(action("sheet_position") + 1)
1832
+ Set anchorCell = .Cells(action("args")(3) + 1, action("args")(2) + 1)
1833
+ End With
1834
+ If action("args")(4) > 0 Then
1835
+ imgLeft = action("args")(4)
1836
+ Else
1837
+ imgLeft = anchorCell.Left
1838
+ End If
1839
+ If action("args")(5) > 0 Then
1840
+ imgTop = action("args")(5)
1841
+ Else
1842
+ imgTop = anchorCell.Top
1843
+ End If
1844
+
1845
+ wb.Sheets(action("sheet_position") + 1).Shapes.addPicture tempPath, False, True, imgLeft, imgTop, -1, -1
1846
+ On Error Resume Next
1847
+ Kill tempPath
1848
+ On Error GoTo 0
1849
+ End Sub
1850
+
1851
+ Sub updatePicture(wb As Workbook, action As Dictionary)
1852
+ Dim img As Picture
1853
+ Dim newImg As Shape
1854
+ Dim tempPath, imgName As String
1855
+ Dim imgLeft, imgTop, imgWidth, imgHeight As Long
1856
+ tempPath = base64ToPic(action("args")(1))
1857
+ Set img = wb.Sheets(action("sheet_position") + 1).Pictures(action("args")(2) + 1)
1858
+ imgName = img.Name
1859
+ imgLeft = img.Left
1860
+ imgTop = img.Top
1861
+ imgWidth = img.Width
1862
+ imgHeight = img.Height
1863
+ img.Delete
1864
+ Set newImg = wb.Sheets(action("sheet_position") + 1).Shapes.addPicture(tempPath, False, True, imgLeft, imgTop, imgWidth, imgHeight)
1865
+ newImg.Name = imgName
1866
+ On Error Resume Next
1867
+ Kill tempPath
1868
+ On Error GoTo 0
1869
+ End Sub
1870
+
1871
+ Sub alert(wb As Workbook, action As Dictionary)
1872
+ Dim myPrompt As String, myTitle As String, myButtons As String, myMode As String, myCallback As String
1873
+ Dim myStyle As Integer, rv As Integer
1874
+ Dim buttonResult As String
1875
+
1876
+ myPrompt = action("args")(1)
1877
+ myTitle = action("args")(2)
1878
+ myButtons = action("args")(3)
1879
+ myMode = action("args")(4)
1880
+ myCallback = action("args")(5)
1881
+
1882
+ Select Case myButtons
1883
+ Case "ok"
1884
+ myStyle = VBA.vbOKOnly
1885
+ Case "ok_cancel"
1886
+ myStyle = VBA.vbOKCancel
1887
+ Case "yes_no"
1888
+ myStyle = VBA.vbYesNo
1889
+ Case "yes_no_cancel"
1890
+ myStyle = VBA.vbYesNoCancel
1891
+ End Select
1892
+
1893
+ If myMode = "info" Then
1894
+ myStyle = myStyle + VBA.vbInformation
1895
+ ElseIf myMode = "critical" Then
1896
+ myStyle = myStyle + VBA.vbCritical
1897
+ End If
1898
+
1899
+ rv = MsgBox(Prompt:=myPrompt, Title:=myTitle, Buttons:=myStyle)
1900
+
1901
+ Select Case rv
1902
+ Case 1
1903
+ buttonResult = "ok"
1904
+ Case 2
1905
+ buttonResult = "cancel"
1906
+ Case 6
1907
+ buttonResult = "yes"
1908
+ Case 7
1909
+ buttonResult = "no"
1910
+ End Select
1911
+
1912
+
1913
+ If myCallback <> "" Then
1914
+ Application.Run myCallback, buttonResult
1915
+ End If
1916
+
1917
+ End Sub
1918
+
1919
+ Sub setRangeName(wb As Workbook, action As Dictionary)
1920
+ GetRange(wb, action).Name = action("args")(1)
1921
+ End Sub
1922
+
1923
+ Sub namesAdd(wb As Workbook, action As Dictionary)
1924
+ If IsNull(action("sheet_position")) Then
1925
+ wb.Names.Add Name:=action("args")(1), RefersTo:=action("args")(2)
1926
+ Else
1927
+ wb.Worksheets(action("sheet_position") + 1).Names.Add Name:=action("args")(1), RefersTo:=action("args")(2)
1928
+ End If
1929
+ End Sub
1930
+
1931
+ Sub nameDelete(wb As Workbook, action As Dictionary)
1932
+ Dim myname As Name
1933
+ For Each myname In wb.Names()
1934
+ If (myname.Name = action("args")(1)) And (myname.RefersTo = action("args")(2)) Then
1935
+ myname.Delete
1936
+ Exit For
1937
+ End If
1938
+ Next
1939
+ End Sub
1940
+
1941
+ Sub runMacro(wb As Workbook, action As Dictionary)
1942
+ Dim nArgs As Integer
1943
+ nArgs = action("args").Count
1944
+ Select Case nArgs
1945
+ Case 1
1946
+ Application.Run action("args")(1), wb
1947
+ Case 2
1948
+ Application.Run action("args")(1), wb, action("args")(2)
1949
+ Case 3
1950
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3)
1951
+ Case 4
1952
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4)
1953
+ Case 5
1954
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5)
1955
+ Case 6
1956
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5), action("args")(6)
1957
+ Case 7
1958
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5), action("args")(6), action("args")(7)
1959
+ Case 8
1960
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5), action("args")(6), action("args")(7), action("args")(8)
1961
+ Case 9
1962
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5), action("args")(6), action("args")(7), action("args")(8), action("args")(9)
1963
+ Case 10
1964
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5), action("args")(6), action("args")(7), action("args")(8), action("args")(9), action("args")(10)
1965
+ Case 11
1966
+ Application.Run action("args")(1), wb, action("args")(2), action("args")(3), action("args")(4), action("args")(5), action("args")(6), action("args")(7), action("args")(8), action("args")(9), action("args")(10), action("args")(11)
1967
+ Case Else
1968
+ Err.Raise vbObjectError + 513, , "macro() only supports up to 10 arguments"
1969
+ End Select
1970
+ End Sub
1971
+
1972
+ Sub rangeDelete(wb As Workbook, action As Dictionary)
1973
+ Dim shift As String
1974
+ shift = action("args")(1)
1975
+ If shift = "up" Then
1976
+ GetRange(wb, action).Delete (XlDeleteShiftDirection.xlShiftUp)
1977
+ Else
1978
+ GetRange(wb, action).Delete (XlDeleteShiftDirection.xlShiftToLeft)
1979
+ End If
1980
+ End Sub
1981
+
1982
+ Sub rangeInsert(wb As Workbook, action As Dictionary)
1983
+ Dim shift As String
1984
+ shift = action("args")(1)
1985
+ If shift = "down" Then
1986
+ GetRange(wb, action).Insert (XlInsertShiftDirection.xlShiftDown)
1987
+ Else
1988
+ GetRange(wb, action).Insert (XlInsertShiftDirection.xlShiftToRight)
1989
+ End If
1990
+ End Sub
1991
+
1992
+ Sub rangeSelect(wb As Workbook, action As Dictionary)
1993
+ GetRange(wb, action).Select
1994
+ End Sub
1995
+
1996
+ Sub addTable(wb As Workbook, action As Dictionary)
1997
+ Dim hasHeaders As Integer
1998
+ If action("args")(2) = True Then
1999
+ hasHeaders = XlYesNoGuess.xlYes
2000
+ Else
2001
+ hasHeaders = XlYesNoGuess.xlNo
2002
+ End If
2003
+ Dim table As ListObject
2004
+ Set table = wb.Worksheets(action("sheet_position") + 1).ListObjects.Add(source:=wb.Worksheets(action("sheet_position") + 1).Range(action("args")(1)), XlListObjectHasHeaders:=hasHeaders, TableStyleName:=action("args")(3))
2005
+ If Not IsNull(action("args")(4)) Then
2006
+ table.Name = action("args")(4)
2007
+ End If
2008
+ End Sub
2009
+
2010
+ Sub setTableName(wb As Workbook, action As Dictionary)
2011
+ wb.Worksheets(action("sheet_position") + 1).ListObjects(action("args")(1) + 1).Name = action("args")(2)
2012
+ End Sub
2013
+
2014
+ Sub resizeTable(wb As Workbook, action As Dictionary)
2015
+ wb.Worksheets(action("sheet_position") + 1).ListObjects(action("args")(1) + 1).Resize (wb.Worksheets(action("sheet_position") + 1).Range(action("args")(2)))
2016
+ End Sub
2017
+
2018
+ Sub showAutofilterTable(wb As Workbook, action As Dictionary)
2019
+ wb.Worksheets(action("sheet_position") + 1).ListObjects(action("args")(1) + 1).ShowAutoFilter = action("args")(2)
2020
+ End Sub
2021
+
2022
+ Sub showHeadersTable(wb As Workbook, action As Dictionary)
2023
+ wb.Worksheets(action("sheet_position") + 1).ListObjects(action("args")(1) + 1).ShowHeaders = action("args")(2)
2024
+ End Sub
2025
+
2026
+ Sub showTotalsTable(wb As Workbook, action As Dictionary)
2027
+ wb.Worksheets(action("sheet_position") + 1).ListObjects(action("args")(1) + 1).ShowTotals = action("args")(2)
2028
+ End Sub
2029
+
2030
+ Sub setTableStyle(wb As Workbook, action As Dictionary)
2031
+ wb.Worksheets(action("sheet_position") + 1).ListObjects(action("args")(1) + 1).TableStyle = action("args")(2)
2032
+ End Sub
2033
+
2034
+ Sub copyRange(wb As Workbook, action As Dictionary)
2035
+ If IsNull(action("args")(1)) Then
2036
+ GetRange(wb, action).Copy
2037
+ Else
2038
+ GetRange(wb, action).Copy Destination:=wb.Worksheets(action("args")(1) + 1).Range(action("args")(2))
2039
+ End If
2040
+ End Sub
2041
+
2042
+ Sub sheetDelete(wb As Workbook, action As Dictionary)
2043
+ Dim displayAlertsState As Boolean
2044
+ displayAlertsState = Application.DisplayAlerts
2045
+ Application.DisplayAlerts = False
2046
+ wb.Worksheets(action("sheet_position") + 1).Delete
2047
+ Application.DisplayAlerts = displayAlertsState
2048
+ End Sub
2049
+
2050
+ Sub sheetClear(wb As Workbook, action As Dictionary)
2051
+ wb.Worksheets(action("sheet_position") + 1).Cells.Clear
2052
+ End Sub
2053
+
2054
+ Sub sheetClearContents(wb As Workbook, action As Dictionary)
2055
+ wb.Worksheets(action("sheet_position") + 1).Cells.ClearContents
2056
+ End Sub
2057
+
2058
+ Sub sheetClearFormats(wb As Workbook, action As Dictionary)
2059
+ wb.Worksheets(action("sheet_position") + 1).Cells.ClearFormats
2060
+ End Sub
2061
+