xlwings-utils 0.0.2__tar.gz → 0.0.4__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xlwings_utils
3
- Version: 0.0.2
3
+ Version: 0.0.4
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,7 +10,7 @@ authors = [
10
10
  { name = "Ruud van der Ham", email = "rt.van.der.ham@gmail.com" },
11
11
  ]
12
12
  description = "xlwings_utils"
13
- version = "0.0.2"
13
+ version = "0.0.4"
14
14
  readme = "README.md"
15
15
  requires-python = ">=3.9"
16
16
  dependencies = [
@@ -0,0 +1,75 @@
1
+ import math
2
+ import itertools
3
+ import os
4
+ import sys
5
+ import re
6
+ from pathlib import Path
7
+
8
+ if __name__ == "__main__": # to make the tests run without the pytest cli
9
+ file_folder = os.path.dirname(__file__)
10
+ os.chdir(file_folder)
11
+ sys.path.insert(0, file_folder + "/../xlwings_utils")
12
+
13
+ import pytest
14
+
15
+ import xlwings_utils as xwu
16
+
17
+
18
+ def test_block():
19
+ this_block = xwu.block(number_of_rows=4, number_of_columns=6)
20
+ this_block[1, 2] = 2
21
+ this_block[2, 5] = 25
22
+ assert this_block.dict == {(1, 2): 2, (2, 5): 25}
23
+ assert this_block.as_list_of_lists == [
24
+ [None, 2, None, None, None, None],
25
+ [None, None, None, None, 25, None],
26
+ [None, None, None, None, None, None],
27
+ [None, None, None, None, None, None],
28
+ ]
29
+ assert this_block.as_minimal_list_of_lists == [[None, 2, None, None, None], [None, None, None, None, 25]]
30
+ assert this_block.number_of_rows == 4
31
+ assert this_block.number_of_columns == 6
32
+ assert this_block.maximum_row == 2
33
+ assert this_block.maximum_column == 5
34
+
35
+ this_block.number_of_rows = 99
36
+ this_block.number_of_columns = 99
37
+ assert this_block.maximum_row == 2
38
+ assert this_block.maximum_column == 5
39
+
40
+ this_block.number_of_rows = 1
41
+ this_block.number_of_columns = 3
42
+ assert this_block.as_list_of_lists == [[None, 2, None]]
43
+ assert this_block.as_minimal_list_of_lists == [[None, 2]]
44
+
45
+
46
+ def test_block_from_list_of_lists():
47
+ this_block = xwu.block.from_list_of_lists([[1, 2, 3], [4, 5, 6]])
48
+ assert this_block.dict == {(1, 1): 1, (1, 2): 2, (1, 3): 3, (2, 1): 4, (2, 2): 5, (2, 3): 6}
49
+ assert this_block.as_list_of_lists == [[1, 2, 3], [4, 5, 6]]
50
+ assert this_block.as_minimal_list_of_lists == [[1, 2, 3], [4, 5, 6]]
51
+ with pytest.raises(ValueError):
52
+ this_block.number_of_rows = 0
53
+ with pytest.raises(ValueError):
54
+ this_block.number_of_columns = 0
55
+ with pytest.raises(ValueError):
56
+ this_block = xwu.block(0, 1)
57
+ with pytest.raises(ValueError):
58
+ this_block = xwu.block(1, 0)
59
+
60
+
61
+ def test_block_one_dimension():
62
+ this_block = xwu.block.from_list_of_lists([1, 2, 3])
63
+ assert this_block.as_list_of_lists == [[1, 2, 3]]
64
+
65
+ this_block = xwu.block.from_list_of_lists([1, 2, 3], column_like=True)
66
+ assert this_block.as_list_of_lists == [[1], [2], [3]]
67
+
68
+
69
+ def test_block_scalar():
70
+ this_block = xwu.block.from_list_of_lists(1, column_like=True)
71
+ assert this_block.as_list_of_lists == [[1]]
72
+
73
+
74
+ if __name__ == "__main__":
75
+ pytest.main(["-vv", "-s", "-x", __file__])
@@ -0,0 +1,382 @@
1
+ # _ _ _ _ _
2
+ # __ __| |__ __(_) _ __ __ _ ___ _ _ | |_ (_)| | ___
3
+ # \ \/ /| |\ \ /\ / /| || '_ \ / _` |/ __| | | | || __|| || |/ __|
4
+ # > < | | \ V V / | || | | || (_| |\__ \ | |_| || |_ | || |\__ \
5
+ # /_/\_\|_| \_/\_/ |_||_| |_| \__, ||___/ _____ \__,_| \__||_||_||___/
6
+ # |___/ |_____|
7
+
8
+ __version__ = "0.0.4"
9
+
10
+
11
+ import dropbox
12
+ from pathlib import Path
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
+ ...
28
+
29
+ _captured_stdout = []
30
+ dbx = None
31
+
32
+
33
+ def dropbox_init(refresh_token=None, app_key=None, app_secret=None):
34
+ """
35
+ dropbox initialize
36
+
37
+ This function has to be called prior to using any dropbox function
38
+
39
+ Parameters
40
+ ----------
41
+ refresh_token : str
42
+ oauth2 refreshntoken
43
+
44
+ if omitted: use the environment variable REFRESH_TOKEN
45
+
46
+ app_key : str
47
+ app key
48
+
49
+ if omitted: use the environment variable APP_KEY
50
+
51
+
52
+ app_secret : str
53
+ app secret
54
+
55
+ if omitted: use the environment variable APP_SECRET
56
+
57
+ Returns
58
+ -------
59
+ -
60
+ """
61
+ if refresh_token is None:
62
+ refresh_token = os.environ["REFRESH_TOKEN"]
63
+ if app_key is None:
64
+ app_key = os.environ["APP_KEY"]
65
+ if app_secret is None:
66
+ app_secret = os.environ["APP_SECRET"]
67
+
68
+ global dbx
69
+ dbx = dropbox.Dropbox(oauth2_refresh_token=refresh_token, app_key=app_key, app_secret=app_secret)
70
+
71
+
72
+ def _check_dbx():
73
+ if dbx is None:
74
+ raise ValueError("not initialized. Please call dropbox_init()")
75
+
76
+
77
+ def list_dropbox(path="", recursive=False):
78
+ """
79
+ list_dropbox
80
+
81
+ returns all dropbox files in path
82
+
83
+ Parameters
84
+ ----------
85
+ path : str or Pathlib.Path
86
+ path from which to list all files (default: '')
87
+
88
+
89
+ recursive : bool
90
+ if True, recursively list files. if False (default) no recursion
91
+
92
+ Returns
93
+ -------
94
+ files, relative to path : list
95
+ """
96
+ _check_dbx()
97
+ out = []
98
+ result = dbx.files_list_folder(path, recursive=recursive)
99
+
100
+ for entry in result.entries:
101
+ if isinstance(entry, dropbox.files.FileMetadata):
102
+ out.append(entry.path_display)
103
+
104
+ while result.has_more:
105
+ result = dbx.files_list_folder_continue(result.cursor)
106
+ for entry in result.entries:
107
+ if isinstance(entry, dropbox.files.FileMetadata):
108
+ out.append(entry.path_display)
109
+
110
+ return out
111
+
112
+
113
+ def read_dropbox(dropbox_path):
114
+ """
115
+ read_dropbox
116
+
117
+ read from dopbox at given path
118
+
119
+ Parameters
120
+ ----------
121
+ dropbox_path : str or Pathlib.Path
122
+ path to read from
123
+
124
+ Returns
125
+ -------
126
+ contents of the dropbox file : bytes
127
+ """
128
+
129
+ _check_dbx()
130
+ metadata, response = dbx.files_download(dropbox_path)
131
+ file_content = response.content
132
+ return file_content
133
+
134
+
135
+ def write_dropbox(dropbox_path, contents):
136
+ _check_dbx()
137
+ """
138
+ write_dropbox
139
+
140
+ write from dopbox at given path
141
+
142
+ Parameters
143
+ ----------
144
+ dropbox_path : str or Pathlib.Path
145
+ path to write to
146
+
147
+ contents : bytes
148
+ contents to be written
149
+
150
+ """
151
+ dbx.files_upload(contents, dropbox_path, mode=dropbox.files.WriteMode.overwrite)
152
+
153
+
154
+ def list_local(path):
155
+ path = Path(path)
156
+ return list(path.iterdir())
157
+
158
+
159
+ def write_local(path, contents):
160
+ path = Path(path)
161
+ path.parent.mkdir(parents=True, exist_ok=True)
162
+ with open(path, "wb") as f:
163
+ f.write(contents)
164
+
165
+
166
+ def read_local(path):
167
+ path = Path(path)
168
+ with open(path, "rb") as f:
169
+ contents = f.read()
170
+ return contents
171
+
172
+
173
+ class block:
174
+ """
175
+ block is 2 dimensional with 1 as lowest index (like xlwings range) data structure
176
+
177
+ Parameters
178
+ ----------
179
+ number_of_rows : int
180
+ number of rows
181
+
182
+ number_of_columns : int
183
+ number of columns
184
+
185
+ Returns
186
+ -------
187
+ block
188
+ """
189
+
190
+ def __init__(self, number_of_rows, number_of_columns):
191
+ self.dict = {}
192
+ self.number_of_columns = number_of_columns
193
+ self.number_of_rows = number_of_rows
194
+
195
+ @classmethod
196
+ def from_list_of_lists(cls, list_of_lists, column_like=False):
197
+ """
198
+ from_list_of_lists
199
+
200
+ Parameters
201
+ ----------
202
+ list_of_lists : list of lists
203
+ to be used to fill the block
204
+
205
+ columns_like : bool
206
+ if False (default), one dimenional lists will be treated as a 1 high range (row-like)
207
+
208
+ if True, one dimenional lists will be treated as a 1 wide range (column-like)
209
+
210
+ This parameter is not used for proper 2 dimensional list of lists
211
+
212
+ Returns
213
+ -------
214
+ block
215
+
216
+ Note
217
+ ----
218
+ number_of_rows and number_of_columns will be retrieved from list_of_lists dimension
219
+ """
220
+ if not isinstance(list_of_lists, list):
221
+ list_of_lists = [[list_of_lists]]
222
+ if not isinstance(list_of_lists[0], list):
223
+ if column_like:
224
+ list_of_lists = [[value] for value in list_of_lists]
225
+ else:
226
+ list_of_lists = [list_of_lists]
227
+
228
+ self = cls(1, 1)
229
+
230
+ self.number_of_rows = len(list_of_lists)
231
+ self._number_of_columns = 0
232
+
233
+ for row, row_contents in enumerate(list_of_lists, 1):
234
+ for column, value in enumerate(row_contents, 1):
235
+ if value is not None:
236
+ self.dict[row, column] = value
237
+ self._number_of_columns = max(self.number_of_columns, column)
238
+ return self
239
+
240
+ def __setitem__(self, row_column, value):
241
+ row, column = row_column
242
+ if row < 1 or row > self.number_of_rows:
243
+ raise IndexError
244
+ if column < 1 or column > self.number_of_columns:
245
+ raise IndexError
246
+ self.dict[row, column] = value
247
+
248
+ def __getitem__(self, row_column):
249
+ row, column = row_column
250
+ if row < 1 or row > self.number_of_rows:
251
+ raise IndexError
252
+ if column < 1 or column > self.number_of_columns:
253
+ raise IndexError
254
+ return self.dict.get((row, column))
255
+
256
+ @property
257
+ def as_list_of_lists(self):
258
+ return [[self.dict.get((row, column)) for column in range(1, self.number_of_columns + 1)] for row in range(1, self.number_of_rows + 1)]
259
+
260
+ @property
261
+ def as_minimal_list_of_lists(self):
262
+ return [[self.dict.get((row, column)) for column in range(1, self.maximum_column + 1)] for row in range(1, self.maximum_row + 1)]
263
+
264
+ @property
265
+ def number_of_rows(self):
266
+ return self._number_of_rows
267
+
268
+ @number_of_rows.setter
269
+ def number_of_rows(self, value):
270
+ if value<1:
271
+ raise ValueError(f"number_of_rows should be >=1, not {value}")
272
+ self._number_of_rows = value
273
+ for row, column in list(self.dict):
274
+ if row > self._number_of_rows:
275
+ del self.dict[row, column]
276
+
277
+ @property
278
+ def number_of_columns(self):
279
+ return self._number_of_columns
280
+
281
+ @number_of_columns.setter
282
+ def number_of_columns(self, value):
283
+ if value<1:
284
+ raise ValueError(f"number_of_columns should be >=1, not {value}")
285
+ self._number_of_columns = value
286
+ for row, column in list(self.dict):
287
+ if column > self._number_of_columns:
288
+ del self.dict[row, column]
289
+
290
+ @property
291
+ def maximum_row(self):
292
+ if self.dict:
293
+ return max(row for (row, column) in self.dict)
294
+ else:
295
+ return 1
296
+
297
+ @property
298
+ def maximum_column(self):
299
+ if self.dict:
300
+ return max(column for (row, column) in self.dict)
301
+ else:
302
+ return 1
303
+
304
+ def __repr__(self):
305
+ return f"block.from_list_of_lists({self.as_list_of_lists})"
306
+
307
+
308
+ def clear_captured_stdout():
309
+ """
310
+ empties the captured stdout
311
+ """
312
+ _captured_stdout.clear()
313
+
314
+
315
+ def captured_stdout_as_str():
316
+ """
317
+ returns the captured stdout as a list of strings
318
+
319
+ Returns
320
+ -------
321
+ captured stdout : list
322
+ each line is an element of the list
323
+ """
324
+
325
+ return "".join(_captured_stdout)
326
+
327
+
328
+ def captured_stdout_as_list_of_lists():
329
+ """
330
+ returns the captured stdout as a list of lists
331
+
332
+ Returns
333
+ -------
334
+ captured stdout : list
335
+ each line is an element of the list
336
+ """
337
+
338
+ return [[line] for line in captured_stdout_as_str().splitlines()]
339
+
340
+
341
+ class capture_stdout:
342
+ """
343
+ specifies how to capture stdout
344
+
345
+ Parameters
346
+ ----------
347
+ include_print : bool
348
+ if True (default), the output is also printed out as normal
349
+
350
+ if False, no output is printed
351
+
352
+ Note
353
+ ----
354
+ This function is normally used as a context manager, like ::
355
+
356
+ with capture_stdout():
357
+ ...
358
+ """
359
+
360
+ def __init__(self, include_print: bool = True):
361
+ self.stdout = sys.stdout
362
+ self.include_print = include_print
363
+
364
+ def __enter__(self):
365
+ sys.stdout = self
366
+
367
+ def __exit__(self, exc_type, exc_value, tb):
368
+ sys.stdout = self.stdout
369
+
370
+ def write(self, data):
371
+ _captured_stdout.append(data)
372
+ if self.include_print:
373
+ self.stdout.write(data)
374
+
375
+ def flush(self):
376
+ if self.include_print:
377
+ self.stdout.flush()
378
+ _captured_stdout.append("\n")
379
+
380
+
381
+ if __name__ == "__main__":
382
+ ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xlwings_utils
3
- Version: 0.0.2
3
+ Version: 0.0.4
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
@@ -1,5 +1,6 @@
1
1
  README.md
2
2
  pyproject.toml
3
+ tests/test_xlwings_utils.py
3
4
  xlwings_utils/__init__.py
4
5
  xlwings_utils/xlwings_utils.py
5
6
  xlwings_utils.egg-info/PKG-INFO
@@ -1,286 +0,0 @@
1
- # _ _ _ _ _
2
- # __ __| |__ __(_) _ __ __ _ ___ _ _ | |_ (_)| | ___
3
- # \ \/ /| |\ \ /\ / /| || '_ \ / _` |/ __| | | | || __|| || |/ __|
4
- # > < | | \ V V / | || | | || (_| |\__ \ | |_| || |_ | || |\__ \
5
- # /_/\_\|_| \_/\_/ |_||_| |_| \__, ||___/ _____ \__,_| \__||_||_||___/
6
- # |___/ |_____|
7
-
8
- __version__ = "0.0.2"
9
-
10
-
11
- import dropbox
12
- from pathlib import Path
13
- import sys
14
-
15
- _captured_stdout = []
16
- dbx = None
17
-
18
-
19
- def dropbox_init(refresh_token, app_key, app_secret):
20
- '''
21
- dropbox initialize
22
-
23
- This function has to be called prior to using any dropbox function
24
-
25
- Parameters
26
- ----------
27
- refresh_token : str
28
- oauth2 refreshntoken
29
-
30
- app_key : str
31
- app key
32
-
33
- app_secret : str
34
- app secret
35
-
36
-
37
- Returns
38
- -------
39
- -
40
- '''
41
- global dbx
42
- dbx = dropbox.Dropbox(oauth2_refresh_token=refresh_token, app_key=app_key, app_secret=app_secret)
43
-
44
- def _check_dbx():
45
- if dbx is None:
46
- raise ValueError('not initialized. Please call dropbox_init()')
47
-
48
-
49
- def list_dropbox(path="", recursive=False):
50
- '''
51
- list_dropbox
52
-
53
- returns all dropbox files in path
54
-
55
- Parameters
56
- ----------
57
- path : str or Pathlib.Path
58
- path from which to list all files (default: '')
59
-
60
-
61
- recursive : bool
62
- if True, recursively list files. if False (default) no recursion
63
-
64
- Returns
65
- -------
66
- files, relative to path : list
67
- '''
68
- _check_dbx()
69
- out = []
70
- result = dbx.files_list_folder(path, recursive=recursive)
71
-
72
- for entry in result.entries:
73
- if isinstance(entry, dropbox.files.FileMetadata):
74
- out.append(entry.path_display)
75
-
76
- while result.has_more:
77
- result = dbx.files_list_folder_continue(result.cursor)
78
- for entry in result.entries:
79
- if isinstance(entry, dropbox.files.FileMetadata):
80
- out.append(entry.path_display)
81
-
82
- return out
83
-
84
-
85
- def read_dropbox(dropbox_path):
86
- '''
87
- read_dropbox
88
-
89
- read from dopbox at given path
90
-
91
- Parameters
92
- ----------
93
- path : str or Pathlib.Path
94
- path to read from
95
-
96
- Returns
97
- -------
98
- contents of the dropbox file : bytes
99
- '''
100
-
101
- _check_dbx()
102
- metadata, response = dbx.files_download(dropbox_path)
103
- file_content = response.content
104
- return file_content
105
-
106
-
107
- def write_dropbox(dropbox_path, contents):
108
- _check_dbx()
109
- dbx.files_upload(contents, dropbox_path, mode=dropbox.files.WriteMode.overwrite)
110
-
111
-
112
- def list_pyodide(path):
113
- path = Path(path)
114
- return list(path.iterdir())
115
-
116
-
117
- def write_pyodide(path, contents):
118
- path = Path(path)
119
- path.parent.mkdir(parents=True, exist_ok=True)
120
- with open(path, "wb") as f:
121
- f.write(contents)
122
-
123
-
124
- def read_pyodide(path):
125
- path = Path(path)
126
- with open(path, "rb") as f:
127
- contents = f.read()
128
- return contents
129
-
130
- class block:
131
- def __init__(self, number_of_rows,number_of_columns):
132
- self.dict={}
133
- self.number_of_columns=number_of_columns
134
- self.number_of_rows=number_of_rows
135
-
136
- @classmethod
137
- def from_list_of_lists(cls, list_of_lists, column_like=False):
138
- if not isinstance(list_of_lists[0],list):
139
- if column_like:
140
- list_of_lists=[[value] for value in list_of_lists]
141
- else:
142
- list_of_lists=[list_of_lists]
143
-
144
- self=cls(0,0)
145
-
146
- self.number_of_rows=len(list_of_lists)
147
- self.number_of_columns=0
148
-
149
-
150
- for row,row_contents in enumerate(list_of_lists,1):
151
- for column,value in enumerate(row_contents,1):
152
- if value is not None:
153
- self.dict[row,column]=value
154
- self.number_of_columns=max(self.number_of_columns, column)
155
- return self
156
-
157
- def __setitem__(self, row_column, value):
158
- row,column=row_column
159
- if row<1 or row>self.number_of_rows:
160
- raise IndexError
161
- if column<1 or column>self.number_of_columns:
162
- raise IndexError
163
- if value is None:
164
- del self.dict[row,column]
165
- else:
166
- self.dict[row,column]=value
167
-
168
- def __getitem__(self, row_column):
169
- row,column=row_column
170
- if row<1 or row>self.number_of_rows:
171
- raise IndexError
172
- if column<1 or column>self.number_of_columns:
173
- raise IndexError
174
- return self.dict.get((row,column))
175
-
176
- @property
177
- def as_list_of_lists(self):
178
- return [[self.dict.get((row,column)) for column in range(1,self.number_of_columns+1)] for row in range(1,self.number_of_rows+1)]
179
-
180
-
181
- def __repr__(self):
182
- return f"block.from_list_of_lists({self.as_list_of_lists})"
183
-
184
- def clear_captured_stdout():
185
- """
186
- empties the captured stdout
187
- """
188
- _captured_stdout.clear()
189
-
190
-
191
- def captured_stdout_as_str():
192
- """
193
- returns the captured stdout as a list of strings
194
-
195
- Returns
196
- -------
197
- captured stdout : list
198
- each line is an element of the list
199
- """
200
-
201
- return "".join(_captured_stdout)
202
-
203
-
204
- def captured_stdout_as_range():
205
- """
206
- returns the captured stdout as a list of strings
207
-
208
- Returns
209
- -------
210
- captured stdout : list
211
- each line is an element of the list
212
- """
213
-
214
- return [[line] for line in captured_stdout_as_str().splitlines()]
215
-
216
-
217
- class capture_stdout:
218
- """
219
- specifies how to capture stdout
220
-
221
- Parameters
222
- ----------
223
- include_print : bool
224
- if True (default), the output is also printed out as normal
225
-
226
- if False, no output is printed
227
-
228
- Note
229
- ----
230
- This function is normally used as a context manager, like ::
231
-
232
- with capture_stdout():
233
- ...
234
- """
235
-
236
- def __init__(self, include_print: bool = True):
237
- self.stdout = sys.stdout
238
- self.include_print = include_print
239
-
240
- def __enter__(self):
241
- sys.stdout = self
242
-
243
- def __exit__(self, exc_type, exc_value, tb):
244
- sys.stdout = self.stdout
245
-
246
- def write(self, data):
247
- _captured_stdout.append(data)
248
- if self.include_print:
249
- self.stdout.write(data)
250
-
251
- def flush(self):
252
- if self.include_print:
253
- self.stdout.flush()
254
- _captured_stdout.append("\n")
255
-
256
-
257
- if __name__ == "__main__":
258
- ...
259
-
260
-
261
- # @xw.script
262
- # def test_stdout(book: xw.Book):
263
- # with capture_stdout():
264
- # for i in range(10):
265
- # print(10 * f'{i}')
266
- # book.sheets.active.range("A1").value=captured_stdout_as_range()
267
-
268
-
269
- # @xw.script
270
- # def test(book: xw.Book):
271
- # dropbox_init(
272
- # refresh_token=REFRESH_TOKEN,
273
- # app_key=APP_KEY,
274
- # app_secret=APP_SECRET,
275
- # )
276
-
277
- # files =list_dropbox("/Downloads",recursive=True)
278
- # peek(files)
279
- # write_pyodide("Test/x.x", b"abc")
280
- # files = list_pyodide("Test")
281
-
282
- # # files=list_dropbox_files("/Downloads")
283
- # # peek(files)
284
- # contents = read_dropbox("/Downloads/dropbox setup.py")
285
- # write_dropbox("/Downloads/dropbox setup1.py", contents)
286
- # peek("done")
File without changes
File without changes