xlwings-utils 25.0.5.post0__py3-none-any.whl → 25.0.6.post0__py3-none-any.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.
Potentially problematic release.
This version of xlwings-utils might be problematic. Click here for more details.
- xlwings_utils/xlwings_utils.py +74 -58
- {xlwings_utils-25.0.5.post0.dist-info → xlwings_utils-25.0.6.post0.dist-info}/METADATA +41 -74
- xlwings_utils-25.0.6.post0.dist-info/RECORD +6 -0
- xlwings_utils-25.0.5.post0.dist-info/RECORD +0 -6
- {xlwings_utils-25.0.5.post0.dist-info → xlwings_utils-25.0.6.post0.dist-info}/WHEEL +0 -0
- {xlwings_utils-25.0.5.post0.dist-info → xlwings_utils-25.0.6.post0.dist-info}/top_level.txt +0 -0
xlwings_utils/xlwings_utils.py
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# /_/\_\|_| \_/\_/ |_||_| |_| \__, ||___/ _____ \__,_| \__||_||_||___/
|
|
6
6
|
# |___/ |_____|
|
|
7
7
|
|
|
8
|
-
__version__ = "25.0.
|
|
8
|
+
__version__ = "25.0.6"
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
import dropbox
|
|
@@ -155,7 +155,7 @@ def list_dropbox(path="", recursive=False, show_files=True, show_folders=False):
|
|
|
155
155
|
return out
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
def read_dropbox(dropbox_path):
|
|
158
|
+
def read_dropbox(dropbox_path, max_retries=100):
|
|
159
159
|
"""
|
|
160
160
|
read_dropbox
|
|
161
161
|
|
|
@@ -166,6 +166,9 @@ def read_dropbox(dropbox_path):
|
|
|
166
166
|
dropbox_path : str or Pathlib.Path
|
|
167
167
|
path to read from
|
|
168
168
|
|
|
169
|
+
max_retries : int
|
|
170
|
+
number of retries (default: 100)
|
|
171
|
+
|
|
169
172
|
Returns
|
|
170
173
|
-------
|
|
171
174
|
contents of the dropbox file : bytes
|
|
@@ -175,24 +178,25 @@ def read_dropbox(dropbox_path):
|
|
|
175
178
|
If REFRESH_TOKEN, APP_KEY and APP_SECRET environment variables are specified,
|
|
176
179
|
it is not necessary to call dropbox_init() prior to any dropbox function.
|
|
177
180
|
|
|
178
|
-
|
|
181
|
+
As reading from dropbox is very unreliable under pyodide, reading will have to be retried (by default maximum 100 times).
|
|
182
|
+
The number of retries can be found with read_dropbox.retries.
|
|
179
183
|
"""
|
|
180
184
|
|
|
181
185
|
_login_dbx()
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
186
|
+
for read_dropbox.retries in range(max_retries + 1):
|
|
187
|
+
metadata, response = dbx.files_download(dropbox_path)
|
|
188
|
+
file_content = response.content
|
|
189
|
+
if len(file_content) == metadata.size:
|
|
190
|
+
return file_content
|
|
191
|
+
raise OSError(f"after {max_retries} still no valid response")
|
|
187
192
|
|
|
188
193
|
|
|
189
194
|
def write_dropbox(dropbox_path, contents):
|
|
190
|
-
_login_dbx()
|
|
191
195
|
"""
|
|
192
196
|
write_dropbox
|
|
193
|
-
|
|
197
|
+
|
|
194
198
|
write from dopbox at given path
|
|
195
|
-
|
|
199
|
+
|
|
196
200
|
Parameters
|
|
197
201
|
----------
|
|
198
202
|
dropbox_path : str or Pathlib.Path
|
|
@@ -200,12 +204,13 @@ def write_dropbox(dropbox_path, contents):
|
|
|
200
204
|
|
|
201
205
|
contents : bytes
|
|
202
206
|
contents to be written
|
|
203
|
-
|
|
207
|
+
|
|
204
208
|
Note
|
|
205
209
|
----
|
|
206
210
|
If REFRESH_TOKEN, APP_KEY and APP_SECRET environment variables are specified,
|
|
207
211
|
it is not necessary to call dropbox_init() prior to any dropbox function.
|
|
208
212
|
"""
|
|
213
|
+
_login_dbx()
|
|
209
214
|
dbx.files_upload(contents, dropbox_path, mode=dropbox.files.WriteMode.overwrite)
|
|
210
215
|
|
|
211
216
|
|
|
@@ -429,6 +434,19 @@ class block:
|
|
|
429
434
|
if column > self.number_of_columns:
|
|
430
435
|
raise ValueError(f"{name}={column} > number_of_columns={self.number_of_columns}")
|
|
431
436
|
|
|
437
|
+
def transpose(self):
|
|
438
|
+
"""
|
|
439
|
+
transpose block
|
|
440
|
+
|
|
441
|
+
Returns
|
|
442
|
+
-------
|
|
443
|
+
transposed block : block
|
|
444
|
+
"""
|
|
445
|
+
bl = block(number_of_rows=self.number_of_columns, number_of_columns=self.number_of_rows)
|
|
446
|
+
for (row, column), value in self.dict.items():
|
|
447
|
+
bl[column, row] = value
|
|
448
|
+
return bl
|
|
449
|
+
|
|
432
450
|
def vlookup(self, s, *, row_from=1, row_to=missing, column1=1, column2=missing, default=missing):
|
|
433
451
|
"""
|
|
434
452
|
searches in column1 for row between row_from and row_to for s and returns the value found at (that row, column2)
|
|
@@ -680,63 +698,60 @@ class block:
|
|
|
680
698
|
return self.vlookup(s, row_from=row_from, row_to=row_to, column1=column1, column2=column2, default=default)
|
|
681
699
|
|
|
682
700
|
def decode_to_files(self):
|
|
683
|
-
"""
|
|
684
|
-
decode the block with encoded file(s) to individual local files
|
|
685
701
|
"""
|
|
702
|
+
decode the block with encoded file(s) to individual pyoidide files
|
|
703
|
+
"""
|
|
704
|
+
count = 0
|
|
705
|
+
for column in self.number_of_columns:
|
|
706
|
+
row = 1
|
|
707
|
+
bl = self.mimimized()
|
|
708
|
+
while row <= self.number_of_rows:
|
|
709
|
+
if self[row, column] and self[row, column].startswith("<file=") and self[row, column].endswith(">"):
|
|
710
|
+
filename = self[row, column][6:-1]
|
|
711
|
+
collect = []
|
|
712
|
+
row += 1
|
|
713
|
+
while bl[row, column] != "</file>":
|
|
714
|
+
if bl[row, column]:
|
|
715
|
+
collect.append(bl[row, column])
|
|
716
|
+
row += 1
|
|
717
|
+
decoded = base64.b64decode("".join(collect))
|
|
718
|
+
open(filename, "wb").write(decoded)
|
|
719
|
+
count += 1
|
|
720
|
+
row += 1
|
|
721
|
+
return count
|
|
686
722
|
|
|
687
|
-
row=1
|
|
688
|
-
while row<=self.number_of_rows:
|
|
689
|
-
if self[row,1] and self[row,1].startswith('<file=') and self[row,1].endswith('>'):
|
|
690
|
-
filename=self[row,1][6:-1]
|
|
691
|
-
collect=[]
|
|
692
|
-
row+=1
|
|
693
|
-
print(f"{filename=}")
|
|
694
|
-
|
|
695
|
-
while self[row,1]!='</file>':
|
|
696
|
-
print(f"{self[row,1]=}")
|
|
697
|
-
|
|
698
|
-
if self[row,1]:
|
|
699
|
-
collect.append(self[row,1])
|
|
700
|
-
row+=1
|
|
701
|
-
print(f"{collect=}")
|
|
702
|
-
decoded=base64.b64decode(''.join(collect))
|
|
703
|
-
open(filename,'wb').write(decoded)
|
|
704
|
-
row+=1
|
|
705
|
-
|
|
706
723
|
@classmethod
|
|
707
|
-
def
|
|
724
|
+
def encode_file(cls, file):
|
|
708
725
|
"""
|
|
709
|
-
make a block with the given
|
|
726
|
+
make a block with the given pyodide file encoded
|
|
710
727
|
|
|
711
728
|
Parameters
|
|
712
729
|
----------
|
|
713
|
-
|
|
714
|
-
|
|
730
|
+
file : file name (str)
|
|
731
|
+
file to be encoded
|
|
715
732
|
|
|
716
733
|
Returns
|
|
717
734
|
-------
|
|
718
|
-
block with encoded
|
|
719
|
-
not minimized!
|
|
735
|
+
block with encoded file : block (minimized)
|
|
720
736
|
"""
|
|
721
737
|
|
|
722
|
-
bl =cls(number_of_rows=
|
|
723
|
-
|
|
738
|
+
bl = cls(number_of_rows=100000, number_of_columns=1)
|
|
739
|
+
|
|
724
740
|
n = 5000 # block size
|
|
725
741
|
row = 1
|
|
726
|
-
|
|
727
|
-
|
|
742
|
+
bl[row, 1] = f"<file={file}>"
|
|
743
|
+
row += 1
|
|
744
|
+
b64 = base64.b64encode(open(file, "rb").read()).decode("utf-8")
|
|
745
|
+
while b64:
|
|
746
|
+
b64_n = b64[:n]
|
|
747
|
+
bl[row, 1] = b64_n
|
|
728
748
|
row += 1
|
|
729
|
-
b64 =
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
bl[row, 1] = f"</file>"
|
|
736
|
-
row+=1
|
|
737
|
-
return bl
|
|
738
|
-
|
|
739
|
-
|
|
749
|
+
b64 = b64[n:]
|
|
750
|
+
bl[row, 1] = f"</file>"
|
|
751
|
+
row += 1
|
|
752
|
+
return bl.minimized()
|
|
753
|
+
|
|
754
|
+
|
|
740
755
|
class Capture:
|
|
741
756
|
"""
|
|
742
757
|
specifies how to capture stdout
|
|
@@ -842,9 +857,9 @@ class Capture:
|
|
|
842
857
|
@include_print.setter
|
|
843
858
|
def include_print(self, value):
|
|
844
859
|
self._include_print = value
|
|
845
|
-
|
|
846
860
|
|
|
847
|
-
|
|
861
|
+
|
|
862
|
+
def trigger_macro(sheet):
|
|
848
863
|
"""
|
|
849
864
|
triggers the macro on sheet
|
|
850
865
|
|
|
@@ -852,11 +867,12 @@ def trigger(sheet):
|
|
|
852
867
|
----------
|
|
853
868
|
sheet : sheet
|
|
854
869
|
sheet to use
|
|
855
|
-
|
|
870
|
+
|
|
856
871
|
"""
|
|
857
872
|
|
|
858
873
|
sheet["A1"].value = "=NOW()"
|
|
859
874
|
|
|
860
|
-
|
|
875
|
+
|
|
861
876
|
if __name__ == "__main__":
|
|
862
877
|
...
|
|
878
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xlwings_utils
|
|
3
|
-
Version: 25.0.
|
|
3
|
+
Version: 25.0.6.post0
|
|
4
4
|
Summary: xlwings_utils
|
|
5
5
|
Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/salabim/xlwings_utils
|
|
@@ -62,8 +62,7 @@ python -c "exec(__import__('requests').get('https://salabim.org/dropbox setup.py
|
|
|
62
62
|
Then, it is possible to list all files in a specified folder using the list_dropbox function.
|
|
63
63
|
It is also possible to get the folders and to access all underlying folders.
|
|
64
64
|
|
|
65
|
-
The `read_dropbox` function can be used to read the contents (bytes) of a Dropbox file.
|
|
66
|
-
to happen rather frequently, an OSError exception is raised.
|
|
65
|
+
The `read_dropbox` function can be used to read the contents (bytes) of a Dropbox file. As reading from Dropbox under pyodide is rather unreliable, xlwings_utils automatically retries several times (by default 100 times). The actual number of retries can be found with `read_dropbox.retries`.
|
|
67
66
|
|
|
68
67
|
The function `write_dropbox` can be used to write contents (bytes) to a Dropbox file.
|
|
69
68
|
|
|
@@ -267,84 +266,52 @@ Clearing the captured stdout buffer can be done at any time with `capture.clear(
|
|
|
267
266
|
|
|
268
267
|
Currently, *xlwings Lite* does not provide access to the local file system. Therefore, xlwings_utils offers some functionality to trigger a VBA script as well as functionality to encode a file in the pyodide file system to a VBA sheet and to trigger writing the encoded file(s) to the local file system.
|
|
269
268
|
|
|
270
|
-
|
|
269
|
+
Files can be encoded into a block, like:
|
|
271
270
|
|
|
272
|
-
|
|
271
|
+
```
|
|
272
|
+
bl = xwu.block.encode_file("film1.mp4")
|
|
273
|
+
book.sheets["VBA"].range((10,1)).value=bl.value
|
|
274
|
+
```
|
|
273
275
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
```
|
|
285
|
-
* `init_transfer_files()`
|
|
286
|
-
This should be called prior to any `transfer_file` call. It just removes all encoded files from the VBA sheet (if any)
|
|
276
|
+
With this code, column A will be filled with an encoded copy of the files *film1.mp4* . This can then be used with a suitable VBA macro to decode to the real file system. A VBA macro can be triggered with `xwu.trigger_macro()`. This requires an Excel worksheet where cell A1 is reserved for communication with xlwings lite. This worksheet needs to contain a macro, like
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
Private Sub Worksheet_Calculate()
|
|
280
|
+
If Me.Range("A1").Formula = "=NOW()" Then
|
|
281
|
+
Me.Range("A1").Value = Null
|
|
282
|
+
Call MacroToExecute
|
|
283
|
+
End If
|
|
284
|
+
End Sub
|
|
285
|
+
```
|
|
287
286
|
|
|
288
|
-
|
|
289
|
-
Can be used to encode a file on the pyodide file system to the VBA sheet. Multiple files are allowed. The file name will be encoded on the sheet as well.
|
|
287
|
+
, where `MacroToExecute` should contain the user code, most likely code to decode file(s) encoded.
|
|
290
288
|
|
|
291
|
-
The VBA
|
|
289
|
+
The repo contains a VBA module called xlwings_utils.bas with code to decode encoded files.
|
|
290
|
+
Just add the .bas file to a worksheet and call like
|
|
292
291
|
|
|
293
292
|
```
|
|
294
|
-
Sub
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
Dim S As String
|
|
298
|
-
Dim Column As Integer
|
|
299
|
-
Dim Row As Integer
|
|
300
|
-
Dim ws As Worksheet
|
|
301
|
-
Dim Count As Integer
|
|
302
|
-
Dim FileNames As String
|
|
303
|
-
|
|
304
|
-
Column = 1
|
|
305
|
-
Row = 1
|
|
306
|
-
|
|
307
|
-
ThisDir = ThisWorkbook.Path
|
|
308
|
-
Set ws = Me
|
|
309
|
-
Count = 0
|
|
310
|
-
While Row < 30000
|
|
311
|
-
Line = ws.Cells(Row, Column)
|
|
312
|
-
If InStr(Line, "<file=") = 1 And Right(Line, 1) = ">" Then
|
|
313
|
-
If Count <> 0 Then
|
|
314
|
-
FileNames = FileNames & ", "
|
|
315
|
-
End If
|
|
316
|
-
Count = Count + 1
|
|
317
|
-
FileNameOnly = Mid(Line, 7, Len(Line) - 7)
|
|
318
|
-
Filename = ThisDir & "/" & FileNameOnly
|
|
319
|
-
FileNames = FileNames & FileNameOnly
|
|
320
|
-
|
|
321
|
-
Row = Row + 1
|
|
322
|
-
S = ""
|
|
323
|
-
While ws.Cells(Row, Column) <> "</file>"
|
|
324
|
-
S = S & ws.Cells(Row, Column)
|
|
325
|
-
Row = Row + 1
|
|
326
|
-
Wend
|
|
327
|
-
|
|
328
|
-
vArr = Base64ToArray(S)
|
|
329
|
-
|
|
330
|
-
Open Filename For Binary Access Write As #1
|
|
331
|
-
WritePos = 1
|
|
332
|
-
Put #1, WritePos, vArr
|
|
333
|
-
Close #1
|
|
334
|
-
End If
|
|
335
|
-
|
|
336
|
-
Row = Row + 1
|
|
337
|
-
|
|
338
|
-
Wend
|
|
339
|
-
If Cells(4, 2) = "y" Then
|
|
340
|
-
ws.Range("A10:A1000000").Clear
|
|
341
|
-
End If
|
|
293
|
+
Sub MacroToExecute()
|
|
294
|
+
DecodeFile(Me, 10, 1)
|
|
295
|
+
```
|
|
342
296
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
297
|
+
In this example, the file *film1.mp4* will be downloaded into the current directory.
|
|
298
|
+
|
|
299
|
+
The module xlwings_utils also contains code to encode a local file to a sheet:
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
Sub MacroToExecute()
|
|
303
|
+
EncodeFile(Me, "data.json", 10, 1)
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
This will place an encoded version of *data.json* on the sheet.
|
|
307
|
+
|
|
308
|
+
Then, the file can be copied to the pyodide file system with
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
bl = block(xw.range((10,1),(50000,1)).decode_to_files())
|
|
312
|
+
```
|
|
313
|
+
```
|
|
314
|
+
|
|
348
315
|
```
|
|
349
316
|
|
|
350
317
|
## Contact info
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
xlwings_utils/__init__.py,sha256=FdaRztevSu5akGL7KBUBRzqwLMRTdvVUuS2Kfp2f1Uc,68
|
|
2
|
+
xlwings_utils/xlwings_utils.py,sha256=arj8LGanSJk3pKER9_cIMNuCB77hBVtiPpiKUaXqqKY,25775
|
|
3
|
+
xlwings_utils-25.0.6.post0.dist-info/METADATA,sha256=uUqweJdGbgthjjuACxO2JwfgsBojtsyIrWeBRahVQIo,12255
|
|
4
|
+
xlwings_utils-25.0.6.post0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
xlwings_utils-25.0.6.post0.dist-info/top_level.txt,sha256=kf5SEv0gZiRObPhUoYcc1O_iX_wwTOPeUIYvzyYeAM4,14
|
|
6
|
+
xlwings_utils-25.0.6.post0.dist-info/RECORD,,
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
xlwings_utils/__init__.py,sha256=FdaRztevSu5akGL7KBUBRzqwLMRTdvVUuS2Kfp2f1Uc,68
|
|
2
|
-
xlwings_utils/xlwings_utils.py,sha256=KP4RPmEyajLF2pn9IS3QEQyYC_xBn1yNoWzdh3cqqSo,25238
|
|
3
|
-
xlwings_utils-25.0.5.post0.dist-info/METADATA,sha256=1amSYUkgWF76__slfIRyOpR-J-VbHjeoqmZxipWK21Q,13036
|
|
4
|
-
xlwings_utils-25.0.5.post0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
-
xlwings_utils-25.0.5.post0.dist-info/top_level.txt,sha256=kf5SEv0gZiRObPhUoYcc1O_iX_wwTOPeUIYvzyYeAM4,14
|
|
6
|
-
xlwings_utils-25.0.5.post0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|