xlwings-utils 0.0.7__tar.gz → 0.0.7.post1__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.
Potentially problematic release.
This version of xlwings-utils might be problematic. Click here for more details.
- {xlwings_utils-0.0.7/xlwings_utils.egg-info → xlwings_utils-0.0.7.post1}/PKG-INFO +29 -5
- xlwings_utils-0.0.7/PKG-INFO → xlwings_utils-0.0.7.post1/README.md +142 -132
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/pyproject.toml +1 -1
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/tests/test_xlwings_utils.py +24 -14
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils/xlwings_utils.py +83 -58
- xlwings_utils-0.0.7/README.md → xlwings_utils-0.0.7.post1/xlwings_utils.egg-info/PKG-INFO +156 -118
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/setup.cfg +0 -0
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils/__init__.py +0 -0
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils.egg-info/SOURCES.txt +0 -0
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils.egg-info/dependency_links.txt +0 -0
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils.egg-info/requires.txt +0 -0
- {xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xlwings_utils
|
|
3
|
-
Version: 0.0.7
|
|
3
|
+
Version: 0.0.7.post1
|
|
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
|
|
@@ -16,16 +16,20 @@ Requires-Dist: ssl
|
|
|
16
16
|
|
|
17
17
|
## Introduction
|
|
18
18
|
|
|
19
|
-
This module provides some useful functions to be used in xlwings lite.
|
|
19
|
+
This module provides some useful functions to be used in xlwings (lite).
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
|
-
Just add xlwings-utils to the *
|
|
23
|
+
Just add xlwings-utils to the *requirements.txt* tab.
|
|
24
24
|
|
|
25
25
|
In the script, add
|
|
26
26
|
|
|
27
27
|
```ìmport xlwings_utils as xwu```
|
|
28
28
|
|
|
29
|
+
> [!NOTE]
|
|
30
|
+
>
|
|
31
|
+
> The GitHub repository can be found on https://github.com/salabim/xlwings_utils .
|
|
32
|
+
|
|
29
33
|
## Dropbox support
|
|
30
34
|
|
|
31
35
|
The xlwings lite system does not provide access to the local file system. With this module, files can be copied between Dropbox and the local pyodide file system, making it possible to indirectly use the local file system.
|
|
@@ -95,10 +99,26 @@ To assign a block to range, use
|
|
|
95
99
|
range.value = block.value
|
|
96
100
|
```
|
|
97
101
|
|
|
98
|
-
The property `block.
|
|
102
|
+
The property `block.highest_used_row_number` returns the row number of the highest non-None cell.
|
|
103
|
+
|
|
104
|
+
The property `block.highest_used_column_number` returns the column_number of the highest non-None cell.
|
|
99
105
|
|
|
100
106
|
The method `block.minimized()` returns a block that has the dimensions of (highest_used_row_number, highest_used_column_number).
|
|
101
107
|
|
|
108
|
+
Particularly if we process an unknown number of lines, we can do something like:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
this_block = xwu.block(number_of_rows=10000, number_of_columns=2)
|
|
112
|
+
for row in range(1, 10001):
|
|
113
|
+
this_block[row,1]= ...
|
|
114
|
+
this_block[row,2]= ...
|
|
115
|
+
if ...: # end condition
|
|
116
|
+
break
|
|
117
|
+
sheet.range(10,1).value = this_block.minimized().value
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
In this case, only the really processed rows are copied to the sheet.
|
|
121
|
+
|
|
102
122
|
## Capture stdout support
|
|
103
123
|
|
|
104
124
|
The module has support for capturing stdout and -later- using showing the captured output on a sheet.
|
|
@@ -117,13 +137,17 @@ sheet.range(4,5).value = xwu.captured_stdout_as_value()
|
|
|
117
137
|
|
|
118
138
|
Clearing the captured stdout buffer can be done with `xwu.clear_captured_std_out`.
|
|
119
139
|
|
|
120
|
-
Normally, stdout will be
|
|
140
|
+
Normally, stdout will also be sent to the xlwings lite UI panel. This can be suppressed with
|
|
121
141
|
|
|
122
142
|
```
|
|
123
143
|
with xwu.capture_stdout(include_print=False):
|
|
124
144
|
...
|
|
125
145
|
```
|
|
126
146
|
|
|
147
|
+
## Contact info
|
|
148
|
+
|
|
149
|
+
You can contact Ruud van der Ham, the core developer, via ruud@salabim.org .
|
|
150
|
+
|
|
127
151
|
## Badges
|
|
128
152
|
|
|
129
153
|
  
|
|
@@ -1,132 +1,142 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
The
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
block
|
|
89
|
-
|
|
90
|
-
The
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
1
|
+
<img src="https://www.salabim.org/xlwings_utils_logo2.png">
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
This module provides some useful functions to be used in xlwings (lite).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Just add xlwings-utils to the *requirements.txt* tab.
|
|
10
|
+
|
|
11
|
+
In the script, add
|
|
12
|
+
|
|
13
|
+
```ìmport xlwings_utils as xwu```
|
|
14
|
+
|
|
15
|
+
> [!NOTE]
|
|
16
|
+
>
|
|
17
|
+
> The GitHub repository can be found on https://github.com/salabim/xlwings_utils .
|
|
18
|
+
|
|
19
|
+
## Dropbox support
|
|
20
|
+
|
|
21
|
+
The xlwings lite system does not provide access to the local file system. With this module, files can be copied between Dropbox and the local pyodide file system, making it possible to indirectly use the local file system.
|
|
22
|
+
|
|
23
|
+
It is only possible, as of now, to use full-access Dropbox apps.
|
|
24
|
+
|
|
25
|
+
The easiest way to use the Dropbox functionality is to add the credentials to the environment variables. Add REFRESH_TOKEN, APP_KEY and APP_SECRET with their corresponding values to the environment variables.
|
|
26
|
+
|
|
27
|
+
Then, it is possible to list all files in a specified folder with the function `list_dropbox`.
|
|
28
|
+
It is also possible to get the folders and to access all underlying folders.
|
|
29
|
+
|
|
30
|
+
The function `read_dropbox` can be used to read a Dropbox file's contents (bytes).
|
|
31
|
+
|
|
32
|
+
The function `write_dropbox` can be used to write contents (bytes) to a Dropbox file.
|
|
33
|
+
|
|
34
|
+
The functions `list_local`, `read_local` and `write_local` offer similar functionality for the local file system (on pyodide).
|
|
35
|
+
|
|
36
|
+
So, a way to access a file on the system's drive (mapped to Dropbox) as a local file is:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
contents = xlwings_utils.read_dropbox('/downloads/file1.xls')
|
|
40
|
+
xlwings_utils.write_local('file1.xlsx')
|
|
41
|
+
df = pandas.read_excel"file1.xlsx")
|
|
42
|
+
...
|
|
43
|
+
```
|
|
44
|
+
And the other direction:
|
|
45
|
+
```
|
|
46
|
+
contents = xlwings_utils.read_local('file1.gif')
|
|
47
|
+
xlwings_utils.write_dropbox('/downloads/file1.gif')
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Block support
|
|
51
|
+
|
|
52
|
+
The module contains a useful 2-dimensional data structure: *block*.
|
|
53
|
+
This can be useful to manipulate a range without accessing the range directly, which is expensive in terms of memory and execution time.
|
|
54
|
+
The advantage over an ordinary list of lists is that a block is index one-based, in line with range and addressing is done with a row, column tuple.
|
|
55
|
+
So, `my_block(lol)[row, col]` is roughly equivalent to `lol[row-1][col-1]`
|
|
56
|
+
|
|
57
|
+
A block stores the values internally as a dictionary and will only convert these to a list of lists when using `block.value`.
|
|
58
|
+
|
|
59
|
+
Converting the value of a range (usually a list of lists, but can also be a list or scalar) to a block can be done with
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
my_block = xwu.block.from_value(range.value)
|
|
63
|
+
```
|
|
64
|
+
The dimensions (number of rows and number of columns) are automatically set.
|
|
65
|
+
|
|
66
|
+
Setting of an individual item (one-based, like range) can be done like
|
|
67
|
+
```
|
|
68
|
+
my_block[row, column] = x
|
|
69
|
+
```
|
|
70
|
+
And, likewise, reading an individual item can be done like
|
|
71
|
+
```
|
|
72
|
+
x = my_block[row, column]
|
|
73
|
+
```
|
|
74
|
+
It is not allowed t,o read or write outside the block dimensions.
|
|
75
|
+
|
|
76
|
+
It is also possible to define an empty block, like
|
|
77
|
+
```
|
|
78
|
+
block = xlwings_utils.block(number_of_rows, number_columns)
|
|
79
|
+
```
|
|
80
|
+
The dimensions can be queried or redefined with `block.number_of_rows` and
|
|
81
|
+
`block.number_of_columns`.
|
|
82
|
+
|
|
83
|
+
To assign a block to range, use
|
|
84
|
+
```
|
|
85
|
+
range.value = block.value
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The property `block.highest_used_row_number` returns the row number of the highest non-None cell.
|
|
89
|
+
|
|
90
|
+
The property `block.highest_used_column_number` returns the column_number of the highest non-None cell.
|
|
91
|
+
|
|
92
|
+
The method `block.minimized()` returns a block that has the dimensions of (highest_used_row_number, highest_used_column_number).
|
|
93
|
+
|
|
94
|
+
Particularly if we process an unknown number of lines, we can do something like:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
this_block = xwu.block(number_of_rows=10000, number_of_columns=2)
|
|
98
|
+
for row in range(1, 10001):
|
|
99
|
+
this_block[row,1]= ...
|
|
100
|
+
this_block[row,2]= ...
|
|
101
|
+
if ...: # end condition
|
|
102
|
+
break
|
|
103
|
+
sheet.range(10,1).value = this_block.minimized().value
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
In this case, only the really processed rows are copied to the sheet.
|
|
107
|
+
|
|
108
|
+
## Capture stdout support
|
|
109
|
+
|
|
110
|
+
The module has support for capturing stdout and -later- using showing the captured output on a sheet.
|
|
111
|
+
|
|
112
|
+
To do that:
|
|
113
|
+
|
|
114
|
+
```makes it possible to capture stdout writes, which
|
|
115
|
+
with xwu.capture_stdout():
|
|
116
|
+
...
|
|
117
|
+
```
|
|
118
|
+
and then the captured output can be copied to the screen, like
|
|
119
|
+
|
|
120
|
+
```can then be copied to a worksheet in a later stage.
|
|
121
|
+
sheet.range(4,5).value = xwu.captured_stdout_as_value()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Clearing the captured stdout buffer can be done with `xwu.clear_captured_std_out`.
|
|
125
|
+
|
|
126
|
+
Normally, stdout will also be sent to the xlwings lite UI panel. This can be suppressed with
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
with xwu.capture_stdout(include_print=False):
|
|
130
|
+
...
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Contact info
|
|
134
|
+
|
|
135
|
+
You can contact Ruud van der Ham, the core developer, via ruud@salabim.org .
|
|
136
|
+
|
|
137
|
+
## Badges
|
|
138
|
+
|
|
139
|
+
  
|
|
140
|
+
 
|
|
141
|
+

|
|
142
|
+
|
|
@@ -103,24 +103,34 @@ def test_raise():
|
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
def test_capture_stdout(capsys):
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
print("def")
|
|
109
|
-
assert xwu.captured_stdout_as_str() == "abc\ndef\n"
|
|
110
|
-
assert xwu.captured_stdout_as_value() == [["abc"], ["def"]]
|
|
111
|
-
|
|
106
|
+
print("abc")
|
|
107
|
+
print("def")
|
|
112
108
|
out, err = capsys.readouterr()
|
|
113
109
|
assert out == "abc\ndef\n"
|
|
114
|
-
|
|
115
|
-
xwu.clear_captured_stdout()
|
|
116
110
|
assert xwu.captured_stdout_as_str() == ""
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
111
|
+
assert xwu.captured_stdout_as_value() == []
|
|
112
|
+
|
|
113
|
+
xwu.capture_stdout(do_capture=True)
|
|
114
|
+
print("abc")
|
|
115
|
+
print("def")
|
|
122
116
|
out, err = capsys.readouterr()
|
|
123
|
-
assert out == ""
|
|
117
|
+
assert out == "abc\ndef\n"
|
|
118
|
+
|
|
119
|
+
assert xwu.captured_stdout_as_str(clear=False) == "abc\ndef\n"
|
|
120
|
+
assert xwu.captured_stdout_as_value(clear=False) == [["abc"], ["def"]]
|
|
121
|
+
|
|
122
|
+
# out, err = capsys.readouterr()
|
|
123
|
+
# assert out == "abc\ndef\n"
|
|
124
|
+
|
|
125
|
+
# xwu.clear_captured_stdout()
|
|
126
|
+
# assert xwu.captured_stdout_as_str() == ""
|
|
127
|
+
# with xwu.capture_stdout(include_print=False):
|
|
128
|
+
# print("ghi")
|
|
129
|
+
# print("jkl")
|
|
130
|
+
# assert xwu.captured_stdout_as_str() == "ghi\njkl\n"
|
|
131
|
+
# assert xwu.captured_stdout_as_value() == [["ghi"], ["jkl"]]
|
|
132
|
+
# out, err = capsys.readouterr()
|
|
133
|
+
# assert out == ""
|
|
124
134
|
|
|
125
135
|
|
|
126
136
|
if __name__ == "__main__":
|
|
@@ -13,7 +13,8 @@ from pathlib import Path
|
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
_org_stdout = sys.stdout
|
|
17
|
+
|
|
17
18
|
dbx = None
|
|
18
19
|
Pythonista = sys.platform == "ios"
|
|
19
20
|
|
|
@@ -217,7 +218,7 @@ def list_local(path, recursive=False, show_files=True, show_folders=False):
|
|
|
217
218
|
show_folders : bool
|
|
218
219
|
if True, show folder entries
|
|
219
220
|
if False (default), do not show folder entries
|
|
220
|
-
|
|
221
|
+
|
|
221
222
|
Returns
|
|
222
223
|
-------
|
|
223
224
|
files, relative to path : list
|
|
@@ -268,33 +269,32 @@ class block:
|
|
|
268
269
|
block
|
|
269
270
|
"""
|
|
270
271
|
|
|
271
|
-
def __init__(self, value=None, *, number_of_rows=None, number_of_columns=None,column_like=False):
|
|
272
|
+
def __init__(self, value=None, *, number_of_rows=None, number_of_columns=None, column_like=False):
|
|
272
273
|
self.dict = {}
|
|
273
|
-
self.column_like=column_like
|
|
274
|
+
self.column_like = column_like
|
|
274
275
|
if value is None:
|
|
275
276
|
if number_of_rows is None:
|
|
276
|
-
|
|
277
|
+
number_of_rows = 1
|
|
277
278
|
if number_of_columns is None:
|
|
278
|
-
|
|
279
|
-
self.number_of_rows=number_of_rows
|
|
280
|
-
self.number_of_columns=number_of_columns
|
|
281
|
-
|
|
279
|
+
number_of_columns = 1
|
|
280
|
+
self.number_of_rows = number_of_rows
|
|
281
|
+
self.number_of_columns = number_of_columns
|
|
282
|
+
|
|
282
283
|
else:
|
|
283
|
-
if isinstance(value,block):
|
|
284
|
-
value=value.value
|
|
285
|
-
self.value=value
|
|
284
|
+
if isinstance(value, block):
|
|
285
|
+
value = value.value
|
|
286
|
+
self.value = value
|
|
286
287
|
if number_of_rows is not None:
|
|
287
|
-
self.number_of_rows=number_of_rows
|
|
288
|
+
self.number_of_rows = number_of_rows
|
|
288
289
|
if number_of_columns is not None:
|
|
289
|
-
self.number_of_columns=number_of_columns
|
|
290
|
+
self.number_of_columns = number_of_columns
|
|
290
291
|
|
|
291
|
-
|
|
292
292
|
@property
|
|
293
293
|
def value(self):
|
|
294
294
|
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)]
|
|
295
|
-
|
|
295
|
+
|
|
296
296
|
@value.setter
|
|
297
|
-
def value(self,value):
|
|
297
|
+
def value(self, value):
|
|
298
298
|
if not isinstance(value, list):
|
|
299
299
|
value = [[value]]
|
|
300
300
|
if not isinstance(value[0], list):
|
|
@@ -303,7 +303,6 @@ class block:
|
|
|
303
303
|
else:
|
|
304
304
|
value = [value]
|
|
305
305
|
|
|
306
|
-
|
|
307
306
|
self.number_of_rows = len(value)
|
|
308
307
|
self._number_of_columns = 0
|
|
309
308
|
|
|
@@ -311,8 +310,7 @@ class block:
|
|
|
311
310
|
for column, item in enumerate(row_contents, 1):
|
|
312
311
|
if item is not None:
|
|
313
312
|
self.dict[row, column] = item
|
|
314
|
-
self._number_of_columns = max(self.number_of_columns, column)
|
|
315
|
-
|
|
313
|
+
self._number_of_columns = max(self.number_of_columns, column)
|
|
316
314
|
|
|
317
315
|
def __setitem__(self, row_column, value):
|
|
318
316
|
row, column = row_column
|
|
@@ -329,7 +327,7 @@ class block:
|
|
|
329
327
|
if column < 1 or column > self.number_of_columns:
|
|
330
328
|
raise IndexError(f"column must be between 1 and {self.number_of_columns} not {column}")
|
|
331
329
|
return self.dict.get((row, column))
|
|
332
|
-
|
|
330
|
+
|
|
333
331
|
def minimized(self):
|
|
334
332
|
return block(self, number_of_rows=self.highest_used_row_number, number_of_columns=self.highest_used_column_number)
|
|
335
333
|
|
|
@@ -358,7 +356,6 @@ class block:
|
|
|
358
356
|
for row, column in list(self.dict):
|
|
359
357
|
if column > self._number_of_columns:
|
|
360
358
|
del self.dict[row, column]
|
|
361
|
-
|
|
362
359
|
|
|
363
360
|
@property
|
|
364
361
|
def highest_used_row_number(self):
|
|
@@ -378,14 +375,22 @@ class block:
|
|
|
378
375
|
return f"block({self.value})"
|
|
379
376
|
|
|
380
377
|
|
|
381
|
-
def clear_captured_stdout():
|
|
378
|
+
def clear_captured_stdout(clear=True):
|
|
382
379
|
"""
|
|
383
380
|
empties the captured stdout
|
|
381
|
+
|
|
382
|
+
Parameters
|
|
383
|
+
----------
|
|
384
|
+
clear : bool
|
|
385
|
+
if True (default), the capture buffer is emptied
|
|
386
|
+
|
|
387
|
+
if False: no action
|
|
384
388
|
"""
|
|
385
|
-
|
|
389
|
+
if clear:
|
|
390
|
+
_buffer.clear()
|
|
386
391
|
|
|
387
392
|
|
|
388
|
-
def captured_stdout_as_str():
|
|
393
|
+
def captured_stdout_as_str(clear=True):
|
|
389
394
|
"""
|
|
390
395
|
returns the captured stdout as a string
|
|
391
396
|
|
|
@@ -394,64 +399,84 @@ def captured_stdout_as_str():
|
|
|
394
399
|
captured stdout : list
|
|
395
400
|
each line is an element of the list
|
|
396
401
|
"""
|
|
397
|
-
|
|
398
|
-
|
|
402
|
+
result = "".join(_buffer)
|
|
403
|
+
clear_captured_stdout(clear)
|
|
404
|
+
return result
|
|
399
405
|
|
|
400
406
|
|
|
401
|
-
def captured_stdout_as_value():
|
|
407
|
+
def captured_stdout_as_value(clear=True):
|
|
402
408
|
"""
|
|
403
409
|
returns the captured stdout as a list of lists
|
|
404
410
|
|
|
405
411
|
Returns
|
|
406
412
|
-------
|
|
407
|
-
captured stdout : list
|
|
413
|
+
captured stdout : list of lists
|
|
408
414
|
each line is an element of the list
|
|
409
415
|
|
|
410
416
|
Note
|
|
411
417
|
----
|
|
412
418
|
This can be used directly to fill a xlwings range
|
|
413
419
|
"""
|
|
414
|
-
return [[line] for line in captured_stdout_as_str().splitlines()]
|
|
420
|
+
return [[line] for line in captured_stdout_as_str(clear).splitlines()]
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class handle_capture_stdout:
|
|
424
|
+
def __init__(self):
|
|
425
|
+
pass
|
|
426
|
+
|
|
427
|
+
def isatty(self):
|
|
428
|
+
return False
|
|
415
429
|
|
|
430
|
+
def write(self, data):
|
|
431
|
+
if _do_capture:
|
|
432
|
+
_buffer.append(data)
|
|
433
|
+
if _do_print:
|
|
434
|
+
_org_stdout.write(data)
|
|
416
435
|
|
|
417
|
-
|
|
436
|
+
def flush(self):
|
|
437
|
+
if _do_print:
|
|
438
|
+
_org_stdout.flush()
|
|
439
|
+
if _do_capture:
|
|
440
|
+
_buffer.append("\n")
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def reset():
|
|
444
|
+
global _buffer
|
|
445
|
+
global _do_print
|
|
446
|
+
global _do_capture
|
|
447
|
+
_buffer = []
|
|
448
|
+
_do_print = True
|
|
449
|
+
_do_capture = False
|
|
450
|
+
|
|
451
|
+
sys.stdout = handle_capture_stdout()
|
|
452
|
+
reset()
|
|
453
|
+
|
|
454
|
+
def capture_stdout(do_print=True, do_capture=True, clear=True):
|
|
455
|
+
global _do_print
|
|
456
|
+
global _do_capture
|
|
418
457
|
"""
|
|
419
458
|
start capture stdout
|
|
420
459
|
|
|
421
460
|
Parameters
|
|
422
461
|
----------
|
|
423
|
-
|
|
424
|
-
if True (default), the output is also printed out as normal
|
|
462
|
+
do_print : bool
|
|
463
|
+
if True (default), the output is (also) printed out as normal
|
|
425
464
|
|
|
426
465
|
if False, no output is printed
|
|
427
466
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
This function is normally used as a context manager, like ::
|
|
431
|
-
|
|
432
|
-
with capture_stdout():
|
|
433
|
-
...
|
|
434
|
-
"""
|
|
435
|
-
|
|
436
|
-
def __init__(self, include_print: bool = True):
|
|
437
|
-
self.stdout = sys.stdout
|
|
438
|
-
self.include_print = include_print
|
|
439
|
-
|
|
440
|
-
def __enter__(self):
|
|
441
|
-
sys.stdout = self
|
|
467
|
+
do_capture : bool
|
|
468
|
+
if True (default), the output is (also) captured to a buffer
|
|
442
469
|
|
|
443
|
-
|
|
444
|
-
sys.stdout = self.stdout
|
|
470
|
+
if False, no output is captured
|
|
445
471
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
_captured_stdout.append("\n")
|
|
472
|
+
clear : bool
|
|
473
|
+
if True (default), the capture buffer is emptied
|
|
474
|
+
"""
|
|
475
|
+
if not (do_print or do_capture):
|
|
476
|
+
raise ValueError("at least one of do_print and do_capture should be True")
|
|
477
|
+
clear_captured_stdout(clear)
|
|
478
|
+
_do_print = do_print
|
|
479
|
+
_do_capture = do_capture
|
|
455
480
|
|
|
456
481
|
|
|
457
482
|
if __name__ == "__main__":
|
|
@@ -1,118 +1,156 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
The
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xlwings_utils
|
|
3
|
+
Version: 0.0.7.post1
|
|
4
|
+
Summary: xlwings_utils
|
|
5
|
+
Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
|
|
6
|
+
Project-URL: Homepage, https://github.com/salabim/xlwings_utils
|
|
7
|
+
Project-URL: Repository, https://github.com/salabim/xlwings_utils
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: dropbox
|
|
13
|
+
Requires-Dist: ssl
|
|
14
|
+
|
|
15
|
+
<img src="https://www.salabim.org/xlwings_utils_logo2.png">
|
|
16
|
+
|
|
17
|
+
## Introduction
|
|
18
|
+
|
|
19
|
+
This module provides some useful functions to be used in xlwings (lite).
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Just add xlwings-utils to the *requirements.txt* tab.
|
|
24
|
+
|
|
25
|
+
In the script, add
|
|
26
|
+
|
|
27
|
+
```ìmport xlwings_utils as xwu```
|
|
28
|
+
|
|
29
|
+
> [!NOTE]
|
|
30
|
+
>
|
|
31
|
+
> The GitHub repository can be found on https://github.com/salabim/xlwings_utils .
|
|
32
|
+
|
|
33
|
+
## Dropbox support
|
|
34
|
+
|
|
35
|
+
The xlwings lite system does not provide access to the local file system. With this module, files can be copied between Dropbox and the local pyodide file system, making it possible to indirectly use the local file system.
|
|
36
|
+
|
|
37
|
+
It is only possible, as of now, to use full-access Dropbox apps.
|
|
38
|
+
|
|
39
|
+
The easiest way to use the Dropbox functionality is to add the credentials to the environment variables. Add REFRESH_TOKEN, APP_KEY and APP_SECRET with their corresponding values to the environment variables.
|
|
40
|
+
|
|
41
|
+
Then, it is possible to list all files in a specified folder with the function `list_dropbox`.
|
|
42
|
+
It is also possible to get the folders and to access all underlying folders.
|
|
43
|
+
|
|
44
|
+
The function `read_dropbox` can be used to read a Dropbox file's contents (bytes).
|
|
45
|
+
|
|
46
|
+
The function `write_dropbox` can be used to write contents (bytes) to a Dropbox file.
|
|
47
|
+
|
|
48
|
+
The functions `list_local`, `read_local` and `write_local` offer similar functionality for the local file system (on pyodide).
|
|
49
|
+
|
|
50
|
+
So, a way to access a file on the system's drive (mapped to Dropbox) as a local file is:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
contents = xlwings_utils.read_dropbox('/downloads/file1.xls')
|
|
54
|
+
xlwings_utils.write_local('file1.xlsx')
|
|
55
|
+
df = pandas.read_excel"file1.xlsx")
|
|
56
|
+
...
|
|
57
|
+
```
|
|
58
|
+
And the other direction:
|
|
59
|
+
```
|
|
60
|
+
contents = xlwings_utils.read_local('file1.gif')
|
|
61
|
+
xlwings_utils.write_dropbox('/downloads/file1.gif')
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Block support
|
|
65
|
+
|
|
66
|
+
The module contains a useful 2-dimensional data structure: *block*.
|
|
67
|
+
This can be useful to manipulate a range without accessing the range directly, which is expensive in terms of memory and execution time.
|
|
68
|
+
The advantage over an ordinary list of lists is that a block is index one-based, in line with range and addressing is done with a row, column tuple.
|
|
69
|
+
So, `my_block(lol)[row, col]` is roughly equivalent to `lol[row-1][col-1]`
|
|
70
|
+
|
|
71
|
+
A block stores the values internally as a dictionary and will only convert these to a list of lists when using `block.value`.
|
|
72
|
+
|
|
73
|
+
Converting the value of a range (usually a list of lists, but can also be a list or scalar) to a block can be done with
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
my_block = xwu.block.from_value(range.value)
|
|
77
|
+
```
|
|
78
|
+
The dimensions (number of rows and number of columns) are automatically set.
|
|
79
|
+
|
|
80
|
+
Setting of an individual item (one-based, like range) can be done like
|
|
81
|
+
```
|
|
82
|
+
my_block[row, column] = x
|
|
83
|
+
```
|
|
84
|
+
And, likewise, reading an individual item can be done like
|
|
85
|
+
```
|
|
86
|
+
x = my_block[row, column]
|
|
87
|
+
```
|
|
88
|
+
It is not allowed t,o read or write outside the block dimensions.
|
|
89
|
+
|
|
90
|
+
It is also possible to define an empty block, like
|
|
91
|
+
```
|
|
92
|
+
block = xlwings_utils.block(number_of_rows, number_columns)
|
|
93
|
+
```
|
|
94
|
+
The dimensions can be queried or redefined with `block.number_of_rows` and
|
|
95
|
+
`block.number_of_columns`.
|
|
96
|
+
|
|
97
|
+
To assign a block to range, use
|
|
98
|
+
```
|
|
99
|
+
range.value = block.value
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The property `block.highest_used_row_number` returns the row number of the highest non-None cell.
|
|
103
|
+
|
|
104
|
+
The property `block.highest_used_column_number` returns the column_number of the highest non-None cell.
|
|
105
|
+
|
|
106
|
+
The method `block.minimized()` returns a block that has the dimensions of (highest_used_row_number, highest_used_column_number).
|
|
107
|
+
|
|
108
|
+
Particularly if we process an unknown number of lines, we can do something like:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
this_block = xwu.block(number_of_rows=10000, number_of_columns=2)
|
|
112
|
+
for row in range(1, 10001):
|
|
113
|
+
this_block[row,1]= ...
|
|
114
|
+
this_block[row,2]= ...
|
|
115
|
+
if ...: # end condition
|
|
116
|
+
break
|
|
117
|
+
sheet.range(10,1).value = this_block.minimized().value
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
In this case, only the really processed rows are copied to the sheet.
|
|
121
|
+
|
|
122
|
+
## Capture stdout support
|
|
123
|
+
|
|
124
|
+
The module has support for capturing stdout and -later- using showing the captured output on a sheet.
|
|
125
|
+
|
|
126
|
+
To do that:
|
|
127
|
+
|
|
128
|
+
```makes it possible to capture stdout writes, which
|
|
129
|
+
with xwu.capture_stdout():
|
|
130
|
+
...
|
|
131
|
+
```
|
|
132
|
+
and then the captured output can be copied to the screen, like
|
|
133
|
+
|
|
134
|
+
```can then be copied to a worksheet in a later stage.
|
|
135
|
+
sheet.range(4,5).value = xwu.captured_stdout_as_value()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Clearing the captured stdout buffer can be done with `xwu.clear_captured_std_out`.
|
|
139
|
+
|
|
140
|
+
Normally, stdout will also be sent to the xlwings lite UI panel. This can be suppressed with
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
with xwu.capture_stdout(include_print=False):
|
|
144
|
+
...
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Contact info
|
|
148
|
+
|
|
149
|
+
You can contact Ruud van der Ham, the core developer, via ruud@salabim.org .
|
|
150
|
+
|
|
151
|
+
## Badges
|
|
152
|
+
|
|
153
|
+
  
|
|
154
|
+
 
|
|
155
|
+

|
|
156
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xlwings_utils-0.0.7 → xlwings_utils-0.0.7.post1}/xlwings_utils.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|