xlwings-utils 0.0.4__py3-none-any.whl → 0.0.6__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 +128 -44
- {xlwings_utils-0.0.4.dist-info → xlwings_utils-0.0.6.dist-info}/METADATA +14 -5
- xlwings_utils-0.0.6.dist-info/RECORD +6 -0
- {xlwings_utils-0.0.4.dist-info → xlwings_utils-0.0.6.dist-info}/WHEEL +1 -1
- xlwings_utils-0.0.4.dist-info/RECORD +0 -6
- {xlwings_utils-0.0.4.dist-info → xlwings_utils-0.0.6.dist-info}/top_level.txt +0 -0
xlwings_utils/xlwings_utils.py
CHANGED
|
@@ -5,36 +5,27 @@
|
|
|
5
5
|
# /_/\_\|_| \_/\_/ |_||_| |_| \__, ||___/ _____ \__,_| \__||_||_||___/
|
|
6
6
|
# |___/ |_____|
|
|
7
7
|
|
|
8
|
-
__version__ = "0.0.
|
|
8
|
+
__version__ = "0.0.6"
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
import dropbox
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
import os
|
|
14
|
-
|
|
15
|
-
class BlockRange:
|
|
16
|
-
@property
|
|
17
|
-
def block(self):
|
|
18
|
-
return block(self.value)
|
|
19
|
-
|
|
20
|
-
@block.setter
|
|
21
|
-
def block(self, block):
|
|
22
|
-
self.value=block.as_list_of_lists
|
|
23
|
-
try:
|
|
24
|
-
import xlwings
|
|
25
|
-
xlwings.Range.block=BlockRange
|
|
26
|
-
except ImportError:
|
|
27
|
-
...
|
|
14
|
+
import sys
|
|
28
15
|
|
|
29
16
|
_captured_stdout = []
|
|
30
17
|
dbx = None
|
|
18
|
+
Pythonista = sys.platform == "ios"
|
|
31
19
|
|
|
32
20
|
|
|
33
21
|
def dropbox_init(refresh_token=None, app_key=None, app_secret=None):
|
|
34
22
|
"""
|
|
35
23
|
dropbox initialize
|
|
36
24
|
|
|
37
|
-
This function
|
|
25
|
+
This function may to be called prior to using any dropbox function
|
|
26
|
+
to specify the request token, app key and app secret.
|
|
27
|
+
If these are specified as REFRESH_TOKEN, APP_KEY and APP_SECRET
|
|
28
|
+
environment variables, it is no necessary to call dropbox_init().
|
|
38
29
|
|
|
39
30
|
Parameters
|
|
40
31
|
----------
|
|
@@ -58,54 +49,99 @@ def dropbox_init(refresh_token=None, app_key=None, app_secret=None):
|
|
|
58
49
|
-------
|
|
59
50
|
-
|
|
60
51
|
"""
|
|
52
|
+
global dbx
|
|
53
|
+
|
|
54
|
+
if Pythonista:
|
|
55
|
+
# under Pythonista, the environ is updated from the .environ.toml file, if present
|
|
56
|
+
environ_file = Path(os.environ["HOME"]) / "Documents" / ".environ.toml"
|
|
57
|
+
|
|
58
|
+
if environ_file.is_file():
|
|
59
|
+
with open(environ_file, "r") as f:
|
|
60
|
+
import toml
|
|
61
|
+
|
|
62
|
+
d = toml.load(f)
|
|
63
|
+
os.environ.update(d)
|
|
64
|
+
|
|
61
65
|
if refresh_token is None:
|
|
62
|
-
|
|
66
|
+
if "REFRESH_TOKEN" in os.environ:
|
|
67
|
+
refresh_token = os.environ["REFRESH_TOKEN"]
|
|
68
|
+
else:
|
|
69
|
+
raise ValueError("no REFRESH_TOKEN found in environment.")
|
|
63
70
|
if app_key is None:
|
|
64
|
-
|
|
71
|
+
if "APP_KEY" in os.environ:
|
|
72
|
+
app_key = os.environ["APP_KEY"]
|
|
73
|
+
else:
|
|
74
|
+
raise ValueError("no APP_KEY found in environment.")
|
|
65
75
|
if app_secret is None:
|
|
66
|
-
|
|
76
|
+
if "APP_SECRET" in os.environ:
|
|
77
|
+
app_secret = os.environ["APP_SECRET"]
|
|
78
|
+
else:
|
|
79
|
+
raise ValueError("no APP_SECRET found in environment.")
|
|
67
80
|
|
|
68
|
-
global dbx
|
|
69
81
|
dbx = dropbox.Dropbox(oauth2_refresh_token=refresh_token, app_key=app_key, app_secret=app_secret)
|
|
82
|
+
try:
|
|
83
|
+
dbx.files_list_folder(path="") # just to test proper credentials
|
|
84
|
+
except dropbox.exceptions.AuthError:
|
|
85
|
+
raise ValueError("invalid dropbox credentials")
|
|
70
86
|
|
|
71
87
|
|
|
72
|
-
def
|
|
88
|
+
def _login_dbx():
|
|
73
89
|
if dbx is None:
|
|
74
|
-
|
|
90
|
+
dropbox_init() # use environment
|
|
75
91
|
|
|
76
92
|
|
|
77
|
-
def list_dropbox(path="", recursive=False):
|
|
93
|
+
def list_dropbox(path="", recursive=False, show_files=True, show_folders=False):
|
|
78
94
|
"""
|
|
79
95
|
list_dropbox
|
|
80
96
|
|
|
81
|
-
returns all dropbox files in path
|
|
97
|
+
returns all dropbox files/folders in path
|
|
82
98
|
|
|
83
99
|
Parameters
|
|
84
100
|
----------
|
|
85
101
|
path : str or Pathlib.Path
|
|
86
102
|
path from which to list all files (default: '')
|
|
87
103
|
|
|
88
|
-
|
|
89
104
|
recursive : bool
|
|
90
105
|
if True, recursively list files. if False (default) no recursion
|
|
91
106
|
|
|
107
|
+
show_files : bool
|
|
108
|
+
if True (default), show file entries
|
|
109
|
+
if False, do not show file entries
|
|
110
|
+
|
|
111
|
+
show_folders : bool
|
|
112
|
+
if True, show folder entries
|
|
113
|
+
if False (default), do not show folder entries
|
|
114
|
+
|
|
92
115
|
Returns
|
|
93
116
|
-------
|
|
94
|
-
files
|
|
117
|
+
files : list
|
|
118
|
+
|
|
119
|
+
Note
|
|
120
|
+
----
|
|
121
|
+
Directory entries are never returned
|
|
122
|
+
|
|
123
|
+
Note
|
|
124
|
+
----
|
|
125
|
+
If REFRESH_TOKEN, APP_KEY and APP_SECRET environment variables are specified,
|
|
126
|
+
it is not necessary to call dropbox_init() prior to any dropbox function.
|
|
95
127
|
"""
|
|
96
|
-
|
|
128
|
+
_login_dbx()
|
|
97
129
|
out = []
|
|
98
130
|
result = dbx.files_list_folder(path, recursive=recursive)
|
|
99
131
|
|
|
100
132
|
for entry in result.entries:
|
|
101
|
-
if isinstance(entry, dropbox.files.FileMetadata):
|
|
133
|
+
if show_files and isinstance(entry, dropbox.files.FileMetadata):
|
|
102
134
|
out.append(entry.path_display)
|
|
135
|
+
if show_folders and isinstance(entry, dropbox.files.FolderMetadata):
|
|
136
|
+
out.append(entry.path_display + "/")
|
|
103
137
|
|
|
104
138
|
while result.has_more:
|
|
105
139
|
result = dbx.files_list_folder_continue(result.cursor)
|
|
106
140
|
for entry in result.entries:
|
|
107
|
-
if isinstance(entry, dropbox.files.FileMetadata):
|
|
141
|
+
if show_files and isinstance(entry, dropbox.files.FileMetadata):
|
|
108
142
|
out.append(entry.path_display)
|
|
143
|
+
if show_folders and isinstance(entry, dropbox.files.FolderMetadata):
|
|
144
|
+
out.append(entry.path_display + "/")
|
|
109
145
|
|
|
110
146
|
return out
|
|
111
147
|
|
|
@@ -124,16 +160,21 @@ def read_dropbox(dropbox_path):
|
|
|
124
160
|
Returns
|
|
125
161
|
-------
|
|
126
162
|
contents of the dropbox file : bytes
|
|
163
|
+
|
|
164
|
+
Note
|
|
165
|
+
----
|
|
166
|
+
If REFRESH_TOKEN, APP_KEY and APP_SECRET environment variables are specified,
|
|
167
|
+
it is not necessary to call dropbox_init() prior to any dropbox function.
|
|
127
168
|
"""
|
|
128
169
|
|
|
129
|
-
|
|
170
|
+
_login_dbx()
|
|
130
171
|
metadata, response = dbx.files_download(dropbox_path)
|
|
131
172
|
file_content = response.content
|
|
132
173
|
return file_content
|
|
133
174
|
|
|
134
175
|
|
|
135
176
|
def write_dropbox(dropbox_path, contents):
|
|
136
|
-
|
|
177
|
+
_login_dbx()
|
|
137
178
|
"""
|
|
138
179
|
write_dropbox
|
|
139
180
|
|
|
@@ -147,13 +188,53 @@ def write_dropbox(dropbox_path, contents):
|
|
|
147
188
|
contents : bytes
|
|
148
189
|
contents to be written
|
|
149
190
|
|
|
191
|
+
Note
|
|
192
|
+
----
|
|
193
|
+
If REFRESH_TOKEN, APP_KEY and APP_SECRET environment variables are specified,
|
|
194
|
+
it is not necessary to call dropbox_init() prior to any dropbox function.
|
|
150
195
|
"""
|
|
151
196
|
dbx.files_upload(contents, dropbox_path, mode=dropbox.files.WriteMode.overwrite)
|
|
152
197
|
|
|
153
198
|
|
|
154
|
-
def list_local(path):
|
|
199
|
+
def list_local(path, recursive=False, show_files=True, show_folders=False):
|
|
200
|
+
"""
|
|
201
|
+
list_local
|
|
202
|
+
|
|
203
|
+
returns all local files/folders in path
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
path : str or Pathlib.Path
|
|
208
|
+
path from which to list all files (default: '')
|
|
209
|
+
|
|
210
|
+
recursive : bool
|
|
211
|
+
if True, recursively list files. if False (default) no recursion
|
|
212
|
+
|
|
213
|
+
show_files : bool
|
|
214
|
+
if True (default), show file entries
|
|
215
|
+
if False, do not show file entries
|
|
216
|
+
|
|
217
|
+
show_folders : bool
|
|
218
|
+
if True, show folder entries
|
|
219
|
+
if False (default), do not show folder entries
|
|
220
|
+
|
|
221
|
+
Returns
|
|
222
|
+
-------
|
|
223
|
+
files, relative to path : list
|
|
224
|
+
"""
|
|
155
225
|
path = Path(path)
|
|
156
|
-
|
|
226
|
+
|
|
227
|
+
result = []
|
|
228
|
+
for entry in path.iterdir():
|
|
229
|
+
if entry.is_file():
|
|
230
|
+
if show_files:
|
|
231
|
+
result.append(str(entry))
|
|
232
|
+
elif entry.is_dir():
|
|
233
|
+
if show_folders:
|
|
234
|
+
result.append(str(entry) + "/")
|
|
235
|
+
if recursive:
|
|
236
|
+
result.extend(list_local(entry, recursive=recursive, show_files=show_files, show_folders=show_folders))
|
|
237
|
+
return result
|
|
157
238
|
|
|
158
239
|
|
|
159
240
|
def write_local(path, contents):
|
|
@@ -172,7 +253,7 @@ def read_local(path):
|
|
|
172
253
|
|
|
173
254
|
class block:
|
|
174
255
|
"""
|
|
175
|
-
block is 2 dimensional with 1 as lowest index (like xlwings range)
|
|
256
|
+
block is 2 dimensional data structure with 1 as lowest index (like xlwings range)
|
|
176
257
|
|
|
177
258
|
Parameters
|
|
178
259
|
----------
|
|
@@ -207,7 +288,7 @@ class block:
|
|
|
207
288
|
|
|
208
289
|
if True, one dimenional lists will be treated as a 1 wide range (column-like)
|
|
209
290
|
|
|
210
|
-
This parameter is not used for proper 2 dimensional list of lists
|
|
291
|
+
This parameter is not used for proper 2 dimensional list of lists or scalars
|
|
211
292
|
|
|
212
293
|
Returns
|
|
213
294
|
-------
|
|
@@ -240,17 +321,17 @@ class block:
|
|
|
240
321
|
def __setitem__(self, row_column, value):
|
|
241
322
|
row, column = row_column
|
|
242
323
|
if row < 1 or row > self.number_of_rows:
|
|
243
|
-
raise IndexError
|
|
324
|
+
raise IndexError(f"row must be between 1 and {self.number_of_rows} not {row}")
|
|
244
325
|
if column < 1 or column > self.number_of_columns:
|
|
245
|
-
raise IndexError
|
|
326
|
+
raise IndexError(f"column must be between 1 and {self.number_of_columns} not {column}")
|
|
246
327
|
self.dict[row, column] = value
|
|
247
328
|
|
|
248
329
|
def __getitem__(self, row_column):
|
|
249
330
|
row, column = row_column
|
|
250
331
|
if row < 1 or row > self.number_of_rows:
|
|
251
|
-
raise IndexError
|
|
332
|
+
raise IndexError(f"row must be between 1 and {self.number_of_rows} not {row}")
|
|
252
333
|
if column < 1 or column > self.number_of_columns:
|
|
253
|
-
raise IndexError
|
|
334
|
+
raise IndexError(f"column must be between 1 and {self.number_of_columns} not {column}")
|
|
254
335
|
return self.dict.get((row, column))
|
|
255
336
|
|
|
256
337
|
@property
|
|
@@ -267,7 +348,7 @@ class block:
|
|
|
267
348
|
|
|
268
349
|
@number_of_rows.setter
|
|
269
350
|
def number_of_rows(self, value):
|
|
270
|
-
if value<1:
|
|
351
|
+
if value < 1:
|
|
271
352
|
raise ValueError(f"number_of_rows should be >=1, not {value}")
|
|
272
353
|
self._number_of_rows = value
|
|
273
354
|
for row, column in list(self.dict):
|
|
@@ -280,7 +361,7 @@ class block:
|
|
|
280
361
|
|
|
281
362
|
@number_of_columns.setter
|
|
282
363
|
def number_of_columns(self, value):
|
|
283
|
-
if value<1:
|
|
364
|
+
if value < 1:
|
|
284
365
|
raise ValueError(f"number_of_columns should be >=1, not {value}")
|
|
285
366
|
self._number_of_columns = value
|
|
286
367
|
for row, column in list(self.dict):
|
|
@@ -314,7 +395,7 @@ def clear_captured_stdout():
|
|
|
314
395
|
|
|
315
396
|
def captured_stdout_as_str():
|
|
316
397
|
"""
|
|
317
|
-
returns the captured stdout as a
|
|
398
|
+
returns the captured stdout as a string
|
|
318
399
|
|
|
319
400
|
Returns
|
|
320
401
|
-------
|
|
@@ -333,14 +414,17 @@ def captured_stdout_as_list_of_lists():
|
|
|
333
414
|
-------
|
|
334
415
|
captured stdout : list
|
|
335
416
|
each line is an element of the list
|
|
336
|
-
"""
|
|
337
417
|
|
|
418
|
+
Note
|
|
419
|
+
----
|
|
420
|
+
This can be used directly to fill a xlwings range
|
|
421
|
+
"""
|
|
338
422
|
return [[line] for line in captured_stdout_as_str().splitlines()]
|
|
339
423
|
|
|
340
424
|
|
|
341
425
|
class capture_stdout:
|
|
342
426
|
"""
|
|
343
|
-
|
|
427
|
+
start capture stdout
|
|
344
428
|
|
|
345
429
|
Parameters
|
|
346
430
|
----------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xlwings_utils
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.6
|
|
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
|
|
@@ -10,28 +10,37 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
10
10
|
Requires-Python: >=3.9
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: dropbox
|
|
13
|
+
Requires-Dist: ssl
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
<img src="https://www.salabim.org/xlwings_utils_logo1.png">
|
|
15
16
|
|
|
16
17
|
## Introduction
|
|
17
18
|
|
|
18
19
|
This module provides some useful functions to be used in xlwings lite.
|
|
20
|
+
|
|
19
21
|
The xlwings lite system does not provide access to the local file system. With this
|
|
20
|
-
module, files can be copied between dropbox and the pyodide file systen. And
|
|
22
|
+
module, files can be copied between dropbox and the local pyodide file systen. And
|
|
21
23
|
therefore, it is possible to indirectly use the local file system.
|
|
22
24
|
|
|
25
|
+
The module contains support for a useful 2 dimensional data structure: block.
|
|
26
|
+
Thjs can be useful to manipulate a range without accessing the range directly,
|
|
27
|
+
which is expensive in terms of memory and execution time.
|
|
28
|
+
|
|
23
29
|
On top of that, this module makes it possible to capture stdout writes, which
|
|
24
30
|
can then be copied to a worksheet in a later stage.
|
|
25
31
|
|
|
26
32
|
## Installation
|
|
27
33
|
|
|
28
|
-
Just add xlwings-utils to the requirement tab.
|
|
34
|
+
Just add xlwings-utils to the requirement tab. It might be required to add ssl.
|
|
29
35
|
|
|
30
36
|
## Dropbox support
|
|
31
37
|
|
|
32
38
|
xlwings_lite only works with full access dropbox apps.
|
|
33
39
|
|
|
34
|
-
In order to use dropbox, is is necessary to initialize the module with credentials.
|
|
40
|
+
In order to use dropbox functionality, is is necessary to initialize the module with credentials.
|
|
41
|
+
|
|
42
|
+
```xwu.dropbox_init()```
|
|
43
|
+
If called without parameters, the refresh_token is
|
|
35
44
|
|
|
36
45
|
## Capture stdout support
|
|
37
46
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
xlwings_utils/__init__.py,sha256=FdaRztevSu5akGL7KBUBRzqwLMRTdvVUuS2Kfp2f1Uc,68
|
|
2
|
+
xlwings_utils/xlwings_utils.py,sha256=yvWW2yRjkHvF5814ptlbGxT5tpRRg-wH1yCDO-5qIe8,12866
|
|
3
|
+
xlwings_utils-0.0.6.dist-info/METADATA,sha256=0fJEsPdOJ1uoHQnAeGzB5dPm-qKD9F_1CGfP9h1Oc4s,2083
|
|
4
|
+
xlwings_utils-0.0.6.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
|
5
|
+
xlwings_utils-0.0.6.dist-info/top_level.txt,sha256=kf5SEv0gZiRObPhUoYcc1O_iX_wwTOPeUIYvzyYeAM4,14
|
|
6
|
+
xlwings_utils-0.0.6.dist-info/RECORD,,
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
xlwings_utils/__init__.py,sha256=FdaRztevSu5akGL7KBUBRzqwLMRTdvVUuS2Kfp2f1Uc,68
|
|
2
|
-
xlwings_utils/xlwings_utils.py,sha256=J2eMXggaLHXLyNnw5n3Am6bDrMxgdyZZxT24lhmhups,9494
|
|
3
|
-
xlwings_utils-0.0.4.dist-info/METADATA,sha256=H1En9zmkXwQaRbANKdz64auexCwoCN_BFeY0n-cm_yk,1662
|
|
4
|
-
xlwings_utils-0.0.4.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
|
5
|
-
xlwings_utils-0.0.4.dist-info/top_level.txt,sha256=kf5SEv0gZiRObPhUoYcc1O_iX_wwTOPeUIYvzyYeAM4,14
|
|
6
|
-
xlwings_utils-0.0.4.dist-info/RECORD,,
|
|
File without changes
|