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.

@@ -5,36 +5,27 @@
5
5
  # /_/\_\|_| \_/\_/ |_||_| |_| \__, ||___/ _____ \__,_| \__||_||_||___/
6
6
  # |___/ |_____|
7
7
 
8
- __version__ = "0.0.4"
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 has to be called prior to using any dropbox 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
- refresh_token = os.environ["REFRESH_TOKEN"]
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
- app_key = os.environ["APP_KEY"]
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
- app_secret = os.environ["APP_SECRET"]
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 _check_dbx():
88
+ def _login_dbx():
73
89
  if dbx is None:
74
- raise ValueError("not initialized. Please call dropbox_init()")
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, relative to path : list
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
- _check_dbx()
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
- _check_dbx()
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
- _check_dbx()
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
- return list(path.iterdir())
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) data structure
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 list of strings
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
- specifies how to capture stdout
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.4
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
- # xlwings_utils
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,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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,,