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.
- tdrpa/_tdxlwings/__init__.py +193 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/_win32patch.py +90 -0
- tdrpa/_tdxlwings/_xlmac.py +2240 -0
- tdrpa/_tdxlwings/_xlwindows.py +2518 -0
- tdrpa/_tdxlwings/addin/Dictionary.cls +474 -0
- tdrpa/_tdxlwings/addin/IWebAuthenticator.cls +71 -0
- tdrpa/_tdxlwings/addin/WebClient.cls +772 -0
- tdrpa/_tdxlwings/addin/WebHelpers.bas +3203 -0
- tdrpa/_tdxlwings/addin/WebRequest.cls +875 -0
- tdrpa/_tdxlwings/addin/WebResponse.cls +453 -0
- tdrpa/_tdxlwings/addin/xlwings.xlam +0 -0
- tdrpa/_tdxlwings/apps.py +35 -0
- tdrpa/_tdxlwings/base_classes.py +1092 -0
- tdrpa/_tdxlwings/cli.py +1306 -0
- tdrpa/_tdxlwings/com_server.py +385 -0
- tdrpa/_tdxlwings/constants.py +3080 -0
- tdrpa/_tdxlwings/conversion/__init__.py +103 -0
- tdrpa/_tdxlwings/conversion/framework.py +147 -0
- tdrpa/_tdxlwings/conversion/numpy_conv.py +34 -0
- tdrpa/_tdxlwings/conversion/pandas_conv.py +184 -0
- tdrpa/_tdxlwings/conversion/standard.py +321 -0
- tdrpa/_tdxlwings/expansion.py +83 -0
- tdrpa/_tdxlwings/ext/__init__.py +3 -0
- tdrpa/_tdxlwings/ext/sql.py +73 -0
- tdrpa/_tdxlwings/html/xlwings-alert.html +71 -0
- tdrpa/_tdxlwings/js/xlwings.js +577 -0
- tdrpa/_tdxlwings/js/xlwings.ts +729 -0
- tdrpa/_tdxlwings/mac_dict.py +6399 -0
- tdrpa/_tdxlwings/main.py +5205 -0
- tdrpa/_tdxlwings/mistune/__init__.py +63 -0
- tdrpa/_tdxlwings/mistune/block_parser.py +366 -0
- tdrpa/_tdxlwings/mistune/inline_parser.py +216 -0
- tdrpa/_tdxlwings/mistune/markdown.py +84 -0
- tdrpa/_tdxlwings/mistune/renderers.py +220 -0
- tdrpa/_tdxlwings/mistune/scanner.py +121 -0
- tdrpa/_tdxlwings/mistune/util.py +41 -0
- tdrpa/_tdxlwings/pro/__init__.py +40 -0
- tdrpa/_tdxlwings/pro/_xlcalamine.py +536 -0
- tdrpa/_tdxlwings/pro/_xlofficejs.py +146 -0
- tdrpa/_tdxlwings/pro/_xlremote.py +1293 -0
- tdrpa/_tdxlwings/pro/custom_functions_code.js +150 -0
- tdrpa/_tdxlwings/pro/embedded_code.py +60 -0
- tdrpa/_tdxlwings/pro/udfs_officejs.py +549 -0
- tdrpa/_tdxlwings/pro/utils.py +199 -0
- tdrpa/_tdxlwings/quickstart.xlsm +0 -0
- tdrpa/_tdxlwings/quickstart_addin.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_addin_ribbon.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_fastapi/main.py +47 -0
- tdrpa/_tdxlwings/quickstart_fastapi/requirements.txt +3 -0
- tdrpa/_tdxlwings/quickstart_standalone.xlsm +0 -0
- tdrpa/_tdxlwings/reports.py +12 -0
- tdrpa/_tdxlwings/rest/__init__.py +1 -0
- tdrpa/_tdxlwings/rest/api.py +368 -0
- tdrpa/_tdxlwings/rest/serializers.py +103 -0
- tdrpa/_tdxlwings/server.py +14 -0
- tdrpa/_tdxlwings/udfs.py +775 -0
- tdrpa/_tdxlwings/utils.py +777 -0
- tdrpa/_tdxlwings/xlwings-0.31.6.applescript +30 -0
- tdrpa/_tdxlwings/xlwings.bas +2061 -0
- tdrpa/_tdxlwings/xlwings_custom_addin.bas +2042 -0
- tdrpa/_tdxlwings/xlwingslib.cp38-win_amd64.pyd +0 -0
- tdrpa/tdworker/__init__.pyi +12 -0
- tdrpa/tdworker/_clip.pyi +50 -0
- tdrpa/tdworker/_excel.pyi +743 -0
- tdrpa/tdworker/_file.pyi +77 -0
- tdrpa/tdworker/_img.pyi +226 -0
- tdrpa/tdworker/_network.pyi +94 -0
- tdrpa/tdworker/_os.pyi +47 -0
- tdrpa/tdworker/_sp.pyi +21 -0
- tdrpa/tdworker/_w.pyi +129 -0
- tdrpa/tdworker/_web.pyi +995 -0
- tdrpa/tdworker/_winE.pyi +228 -0
- tdrpa/tdworker/_winK.pyi +74 -0
- tdrpa/tdworker/_winM.pyi +117 -0
- tdrpa/tdworker.cp312-win_amd64.pyd +0 -0
- tdrpa_tdworker-1.2.13.2.dist-info/METADATA +38 -0
- tdrpa_tdworker-1.2.13.2.dist-info/RECORD +101 -0
- tdrpa_tdworker-1.2.13.2.dist-info/WHEEL +5 -0
- 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
|
+
|