tpltable 0.3.3__tar.gz → 0.3.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.
- {tpltable-0.3.3 → tpltable-0.3.4}/PKG-INFO +1 -1
- {tpltable-0.3.3 → tpltable-0.3.4}/setup.py +1 -1
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/basic.py +7 -2
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/table.py +245 -108
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable.egg-info/PKG-INFO +1 -1
- {tpltable-0.3.3 → tpltable-0.3.4}/setup.cfg +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/__init__.py +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/core.py +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/excel.py +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/main.py +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/style.py +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable/style_demo.py +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable.egg-info/SOURCES.txt +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable.egg-info/dependency_links.txt +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable.egg-info/requires.txt +0 -0
- {tpltable-0.3.3 → tpltable-0.3.4}/tpltable.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tpltable
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: define "Excel" "Table|StyleTable" "Row|Col|StyleRow|StyleCol". Can dynamic modify excel data & styles. Support multiple kinds of indexes. (70%)
|
|
5
5
|
Author-email: 2229066748@qq.com
|
|
6
6
|
Maintainer: Eagle'sBaby
|
|
@@ -5,7 +5,7 @@ from setuptools import find_packages, setup
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name='tpltable',
|
|
8
|
-
version='0.3.
|
|
8
|
+
version='0.3.4',
|
|
9
9
|
description='define "Excel" "Table|StyleTable" "Row|Col|StyleRow|StyleCol". Can dynamic modify excel data & styles. Support multiple kinds of indexes. (70%)',
|
|
10
10
|
author_email='2229066748@qq.com',
|
|
11
11
|
maintainer="Eagle'sBaby",
|
|
@@ -73,6 +73,11 @@ COLORAMA_STYLES = {
|
|
|
73
73
|
|
|
74
74
|
__PAT_COORD = re.compile("([A-Z]+)(\d+)")
|
|
75
75
|
|
|
76
|
+
|
|
77
|
+
# 模糊的行列索引混用警告
|
|
78
|
+
class AmbiguousIndexWarning(UserWarning):
|
|
79
|
+
...
|
|
80
|
+
|
|
76
81
|
class Coord:
|
|
77
82
|
def __init__(self, iloc_c, iloc_r):
|
|
78
83
|
self._r:int = iloc_r
|
|
@@ -143,7 +148,7 @@ def index_from_string(letters:str, *, only_int:bool=False, should:str=None) -> U
|
|
|
143
148
|
if letters.isdigit():
|
|
144
149
|
if should == 's':
|
|
145
150
|
warnings.warn(
|
|
146
|
-
f"Here should be a letter, but got '{letters}'. Regarded as '{get_column_letter(int(letters))}'."
|
|
151
|
+
AmbiguousIndexWarning(f"Here should be a letter (Col-Index), but got '{letters}' (Row-Index). Regarded as '{get_column_letter(int(letters))}'."),
|
|
147
152
|
)
|
|
148
153
|
return int(letters)
|
|
149
154
|
_s = __PAT_COORD.match(letters)
|
|
@@ -154,7 +159,7 @@ def index_from_string(letters:str, *, only_int:bool=False, should:str=None) -> U
|
|
|
154
159
|
return Coord(index_from_string(_c) - 1, int(_r) - 1)
|
|
155
160
|
if should == 'i':
|
|
156
161
|
warnings.warn(
|
|
157
|
-
f"Here should be an digit, but got '{letters}'. Regarded as '{_column_index_from_string(letters)}'."
|
|
162
|
+
AmbiguousIndexWarning(f"Here should be an digit (Row-Index), but got '{letters}' (Col-Index). Regarded as '{_column_index_from_string(letters)}'.")
|
|
158
163
|
)
|
|
159
164
|
return _column_index_from_string(letters)
|
|
160
165
|
|
|
@@ -7,10 +7,96 @@ from tpltable.core import *
|
|
|
7
7
|
from tpltable.style import Style, TYPE_BORDER
|
|
8
8
|
|
|
9
9
|
_PAT_COORD = re.compile(r"([A-Z]+)(\d+)")
|
|
10
|
+
|
|
11
|
+
|
|
10
12
|
class EMPTY_INDEX:
|
|
11
13
|
pass
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
|
|
16
|
+
class _ExcelIndexsLike_1DArray_Def:
|
|
17
|
+
|
|
18
|
+
def _reindexself(self) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Reindex the Series
|
|
21
|
+
* Return None. Modify self._sr inplace.
|
|
22
|
+
:return:
|
|
23
|
+
"""
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
|
|
26
|
+
def _reconstruct(self, other) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Reconstruct self
|
|
29
|
+
* Return None. Modify self._sr inplace.
|
|
30
|
+
:param other: inst of __class__. The other instance.
|
|
31
|
+
:return:
|
|
32
|
+
"""
|
|
33
|
+
raise NotImplementedError
|
|
34
|
+
|
|
35
|
+
def _construct_new_from_index(self, new_index: Union[int, slice], *, inplace=False) -> '__class__() | None':
|
|
36
|
+
"""
|
|
37
|
+
Construct a new __class__ from the new index
|
|
38
|
+
* Use this instead of directly create a new __class__ object. So you can override this method to add some other logic.
|
|
39
|
+
:param new_index: int|slice. The new index you want to index self
|
|
40
|
+
*
|
|
41
|
+
:param inplace: bool. If True, modify self inplace. If True, Return None.
|
|
42
|
+
:return: inst of __class__ | None
|
|
43
|
+
"""
|
|
44
|
+
raise NotImplementedError
|
|
45
|
+
|
|
46
|
+
def _construct_new_from_insert(self, insert_index: int, *values, inplace=False) -> '__class__() | None':
|
|
47
|
+
"""
|
|
48
|
+
Construct a new __class__ from the new index
|
|
49
|
+
* Use this instead of directly create a new __class__ object. So you can override this method to add some other logic.
|
|
50
|
+
:param insert_index: int. The index to insert before.
|
|
51
|
+
:param *values: Any. The values to insert.
|
|
52
|
+
:param inplace:
|
|
53
|
+
:return: inst of __class__ | None
|
|
54
|
+
"""
|
|
55
|
+
raise NotImplementedError
|
|
56
|
+
|
|
57
|
+
def _construct_new_from_delete(self, delete_index: Union[int, slice], *, inplace=False) -> '__class__() | None':
|
|
58
|
+
"""
|
|
59
|
+
Construct a new __class__ from the new index
|
|
60
|
+
* Use this instead of directly create a new __class__ object. So you can override this method to add some other logic.
|
|
61
|
+
:param delete_index: int|slice. The index to delete.
|
|
62
|
+
*
|
|
63
|
+
:param inplace: bool. If True, modify self inplace. If True, Return None.
|
|
64
|
+
:return: inst of __class__ | None
|
|
65
|
+
"""
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
|
|
68
|
+
def on_subinstance(self, construction: object) -> '__class__()':
|
|
69
|
+
"""
|
|
70
|
+
Hook function called when a subinstance is created.
|
|
71
|
+
* Return the new instance. So you can modify the new instance.
|
|
72
|
+
* When this method is called, self is not modified.
|
|
73
|
+
:param construction: inst of __class__. The subinstance created.
|
|
74
|
+
:return: inst of __class__ | None
|
|
75
|
+
"""
|
|
76
|
+
return construction
|
|
77
|
+
|
|
78
|
+
def on_insert(self, construction: object) -> '__class__()':
|
|
79
|
+
"""
|
|
80
|
+
Hook function called when a subinstance is created.
|
|
81
|
+
* Return the new instance. So you can modify the new instance.
|
|
82
|
+
* When this method is called, self is not modified.
|
|
83
|
+
:param construction: inst of __class__. The subinstance created.
|
|
84
|
+
:return: inst of __class__
|
|
85
|
+
"""
|
|
86
|
+
return construction
|
|
87
|
+
|
|
88
|
+
def on_delete(self, construction: object) -> '__class__()':
|
|
89
|
+
"""
|
|
90
|
+
Hook function called when a subinstance is created.
|
|
91
|
+
* Return the new instance. So you can modify the new instance.
|
|
92
|
+
* When this method is called, self is not modified.
|
|
93
|
+
:param construction: inst of __class__. The subinstance created.
|
|
94
|
+
:return: inst of __class__
|
|
95
|
+
"""
|
|
96
|
+
return construction
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class _ExcelIndexsLike_1DArray_Base(_ExcelIndexsLike_1DArray_Def):
|
|
14
100
|
_CLS_DEFAULT_INDEX_TYPE = None # "i" or "s" or None
|
|
15
101
|
|
|
16
102
|
# None: integer index, start with 0 and label'0'
|
|
@@ -18,65 +104,119 @@ class _ExcelIndexsLike_1DArray:
|
|
|
18
104
|
# "s": letter index, start with 0 and label:'A'
|
|
19
105
|
def __init__(self, _from=None, *, copy: bool = True):
|
|
20
106
|
self._sr: pd.Series = None
|
|
21
|
-
if isinstance(_from, pd.Series):
|
|
22
|
-
self._sr = _from
|
|
23
|
-
if copy:
|
|
24
|
-
self._sr = self._sr.copy()
|
|
25
|
-
elif isinstance(_from, np.ndarray):
|
|
26
|
-
# check shape
|
|
27
|
-
s = _from.shape
|
|
28
|
-
if np.ndim(_from) != 1:
|
|
29
|
-
raise ValueError(f"Only 1D array is supported. But got {np.ndim(_from)}D array.(shape={s})")
|
|
30
|
-
self._sr = pd.Series(_from)
|
|
31
107
|
|
|
32
|
-
|
|
108
|
+
if isinstance(_from, list):
|
|
33
109
|
try:
|
|
34
|
-
|
|
35
|
-
s = arr.shape
|
|
36
|
-
if np.ndim(arr) != 1:
|
|
37
|
-
raise ValueError(f"Only 1D array is supported. But got {np.ndim(arr)}D array from list.(shape={s})")
|
|
38
|
-
self._sr = pd.Series(arr)
|
|
110
|
+
_from = np.array(_from)
|
|
39
111
|
except Exception as e:
|
|
40
112
|
raise ValueError(f"Failed to convert list to 1D array. {e}")
|
|
41
|
-
else:
|
|
42
|
-
raise ValueError(f"Unsupported type: {type(_from)}")
|
|
43
|
-
|
|
44
|
-
self._reindex()
|
|
45
113
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if isinstance(_from, pd.Series):
|
|
49
|
-
if len(_from) and not isinstance(_from.iloc[0]):
|
|
50
|
-
...
|
|
51
|
-
self._sr = _from
|
|
52
|
-
if copy:
|
|
53
|
-
self._sr = self._sr.copy()
|
|
114
|
+
if _from is None:
|
|
115
|
+
self._sr = pd.Series()
|
|
54
116
|
elif isinstance(_from, np.ndarray):
|
|
55
117
|
# check shape
|
|
56
118
|
s = _from.shape
|
|
57
119
|
if np.ndim(_from) != 1:
|
|
58
120
|
raise ValueError(f"Only 1D array is supported. But got {np.ndim(_from)}D array.(shape={s})")
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if np.ndim(arr) != 1:
|
|
67
|
-
raise ValueError(f"Only 1D array is supported. But got {np.ndim(arr)}D array from list.(shape={s})")
|
|
68
|
-
self._sr = pd.Series(arr)
|
|
69
|
-
except Exception as e:
|
|
70
|
-
raise ValueError(f"Failed to convert list to 1D array. {e}")
|
|
121
|
+
self._sr = pd.Series(_from)
|
|
122
|
+
elif isinstance(_from, pd.Series):
|
|
123
|
+
self._sr = _from
|
|
124
|
+
if copy:
|
|
125
|
+
self._sr = self._sr.copy()
|
|
126
|
+
elif isinstance(_from, _ExcelIndexsLike_1DArray_Base):
|
|
127
|
+
self._sr = _from._sr.copy()
|
|
71
128
|
else:
|
|
72
129
|
raise ValueError(f"Unsupported type: {type(_from)}")
|
|
73
130
|
|
|
74
|
-
|
|
131
|
+
self._reindexself()
|
|
132
|
+
|
|
133
|
+
def _reindexself(self):
|
|
134
|
+
"""
|
|
135
|
+
Reindex the Series
|
|
136
|
+
* Return None. Modify self._sr inplace.
|
|
137
|
+
:return:
|
|
138
|
+
"""
|
|
75
139
|
if self._CLS_DEFAULT_INDEX_TYPE == "s":
|
|
76
140
|
self._sr.index = [get_column_letter(i + 1) for i in range(self.size)]
|
|
77
141
|
elif self._CLS_DEFAULT_INDEX_TYPE == "i":
|
|
78
142
|
self._sr.index = [i + 1 for i in range(self.size)]
|
|
79
143
|
|
|
144
|
+
def _reconstruct(self, other):
|
|
145
|
+
"""
|
|
146
|
+
Reconstruct self
|
|
147
|
+
* Return None. Modify self._sr inplace.
|
|
148
|
+
:param other: inst of __class__. The other instance.
|
|
149
|
+
:return:
|
|
150
|
+
"""
|
|
151
|
+
self._sr = other._sr.copy()
|
|
152
|
+
self._reindexself()
|
|
153
|
+
|
|
154
|
+
def _construct_new_from_index(self, new_index: Union[int, slice], *, inplace=False) -> '__class__() | None':
|
|
155
|
+
"""
|
|
156
|
+
Construct a new __class__ from the new index
|
|
157
|
+
* Use this instead of directly create a new __class__ object. So you can override this method to add some other logic.
|
|
158
|
+
:param new_index: int|slice. The new index you want to index self
|
|
159
|
+
*
|
|
160
|
+
:param inplace: bool. If True, modify self inplace. If True, Return None.
|
|
161
|
+
:return: inst of __class__ | None
|
|
162
|
+
"""
|
|
163
|
+
_new = self.__class__(self._sr.iloc[new_index], copy=False)
|
|
164
|
+
_new = self.on_subinstance(_new)
|
|
165
|
+
if inplace:
|
|
166
|
+
self._reconstruct(_new)
|
|
167
|
+
else:
|
|
168
|
+
return _new
|
|
169
|
+
|
|
170
|
+
def _construct_new_from_insert(self, insert_index: int, *values, inplace=False) -> '__class__() | None':
|
|
171
|
+
"""
|
|
172
|
+
Construct a new __class__ from the new index
|
|
173
|
+
* Use this instead of directly create a new __class__ object. So you can override this method to add some other logic.
|
|
174
|
+
:param insert_index: int. The index to insert before.
|
|
175
|
+
:param *values: Any. The values to insert.
|
|
176
|
+
:param inplace:
|
|
177
|
+
:return: inst of __class__ | None
|
|
178
|
+
"""
|
|
179
|
+
_construct = self._sr.to_list()
|
|
180
|
+
values = list(values)
|
|
181
|
+
_construct = _construct[:insert_index] + values + _construct[insert_index:]
|
|
182
|
+
_new = self.__class__(_construct, copy=False)
|
|
183
|
+
_new = self.on_insert(_new)
|
|
184
|
+
if inplace:
|
|
185
|
+
self._reconstruct(_new)
|
|
186
|
+
else:
|
|
187
|
+
return _new
|
|
188
|
+
|
|
189
|
+
def _construct_new_from_delete(self, delete_index: Union[int, slice], *, inplace=False) -> '__class__() | None':
|
|
190
|
+
"""
|
|
191
|
+
Construct a new __class__ from the new index
|
|
192
|
+
* Use this instead of directly create a new __class__ object. So you can override this method to add some other logic.
|
|
193
|
+
:param delete_index: int|slice. The index to delete. Special case: slice(None) means clear all.
|
|
194
|
+
*
|
|
195
|
+
:param inplace: bool. If True, modify self inplace. If True, Return None.
|
|
196
|
+
:return: inst of __class__ | None
|
|
197
|
+
"""
|
|
198
|
+
if delete_index == slice(None):
|
|
199
|
+
_new = self.__class__()
|
|
200
|
+
else:
|
|
201
|
+
_new = self.__class__(self._sr.drop(self._sr.index[delete_index]), copy=False)
|
|
202
|
+
_new = self.on_delete(_new)
|
|
203
|
+
|
|
204
|
+
if inplace:
|
|
205
|
+
self._reconstruct(_new)
|
|
206
|
+
else:
|
|
207
|
+
return _new
|
|
208
|
+
|
|
209
|
+
def _parse_slice(self, key: slice) -> Tuple[int, int, int]:
|
|
210
|
+
"""
|
|
211
|
+
Parse the slice to get the start, stop and step
|
|
212
|
+
:param key: slice. The slice to parse.
|
|
213
|
+
:return: start, stop, step
|
|
214
|
+
"""
|
|
215
|
+
_start = key.start if key.start is not None else 0
|
|
216
|
+
_stop = key.stop if key.stop is not None else self.size
|
|
217
|
+
_step = key.step if key.step is not None else 1
|
|
218
|
+
return _start, _stop, _step
|
|
219
|
+
|
|
80
220
|
def __str__(self):
|
|
81
221
|
txt = str(self._sr)
|
|
82
222
|
|
|
@@ -111,10 +251,12 @@ class _ExcelIndexsLike_1DArray:
|
|
|
111
251
|
:return: type, real_index
|
|
112
252
|
* type:
|
|
113
253
|
' ': 简单索引类型
|
|
254
|
+
'n': 全选类型
|
|
114
255
|
"s": 文本ABC索引类型
|
|
115
256
|
"i": 文本123索引类型
|
|
116
257
|
"t??": slice类型, ? 可以是 ' nis'中的一个
|
|
117
258
|
"""
|
|
259
|
+
skey = skey.upper()
|
|
118
260
|
# NOTE: index_from_string will thorw warning if the type is not matched
|
|
119
261
|
# 先考虑是否是slice
|
|
120
262
|
if ':' in skey:
|
|
@@ -125,20 +267,22 @@ class _ExcelIndexsLike_1DArray:
|
|
|
125
267
|
_t1 = 'i' if l1.isdigit() else 's'
|
|
126
268
|
|
|
127
269
|
start, end = index_from_string(l0, should=self._CLS_DEFAULT_INDEX_TYPE, only_int=True), index_from_string(l1, should=self._CLS_DEFAULT_INDEX_TYPE, only_int=True)
|
|
128
|
-
return f"t{_t0}{_t1}", slice(start, end + 1)
|
|
270
|
+
return f"t{_t0}{_t1}", slice(start, end + 1) if start <= end else slice(end, start + 1) # NOTE: 'A:C' with 'C:A' is the same
|
|
129
271
|
|
|
130
272
|
if _PAT_COORD.match(skey):
|
|
131
273
|
raise ValueError(f"Unexpected index: {skey}.")
|
|
132
274
|
_type = 'i' if skey.isdigit() else 's'
|
|
133
275
|
return _type, index_from_string(skey, should=self._CLS_DEFAULT_INDEX_TYPE, only_int=True) - 1
|
|
134
276
|
|
|
135
|
-
def
|
|
277
|
+
def _dim1_parse_index_key(self, key, *, err_when_slice=False) -> Tuple[U[str, None], U[int, slice]]:
|
|
136
278
|
"""
|
|
137
279
|
Parse the key to get the type and index
|
|
138
280
|
:param key:
|
|
281
|
+
:param err_when_slice: bool. If True, raise error when slice is found.
|
|
139
282
|
:return: type, index
|
|
140
283
|
* type:
|
|
141
284
|
' ': 简单索引类型
|
|
285
|
+
'n': 全选类型
|
|
142
286
|
"s": 文本ABC索引类型
|
|
143
287
|
"i": 文本123索引类型
|
|
144
288
|
"t??": slice类型, ? 可以是 ' nis'中的一个
|
|
@@ -152,53 +296,47 @@ class _ExcelIndexsLike_1DArray:
|
|
|
152
296
|
# NOTE:交给专用于处理字符串索引的函数处理
|
|
153
297
|
return self.__dim1_parse_str_index(key)
|
|
154
298
|
elif isinstance(key, slice):
|
|
299
|
+
if err_when_slice:
|
|
300
|
+
raise ValueError(f"Unexpected slice index: {key}. (Because param err_when_slice=True).")
|
|
155
301
|
_a, _b, _step = key.start, key.stop, key.step
|
|
302
|
+
_atype, _aindex, _btype, _bindex = 'n', None, 'n', None
|
|
156
303
|
if _a is None and _b is None:
|
|
157
304
|
return "tnn", key
|
|
158
|
-
_atype, _aindex, _btype, _bindex, _any_flag = 'n', None, 'n', None, False
|
|
159
305
|
if _a is not None:
|
|
160
|
-
_atype, _aindex = self.
|
|
161
|
-
_any_flag = True
|
|
306
|
+
_atype, _aindex = self._dim1_parse_index_key(_a)
|
|
162
307
|
if _b is not None:
|
|
163
|
-
_btype, _bindex = self.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
308
|
+
_btype, _bindex = self._dim1_parse_index_key(_b)
|
|
309
|
+
if _atype != _btype:
|
|
310
|
+
raise ValueError(f"Unexpected index: '{key}'. Which is not in the same type.")
|
|
311
|
+
|
|
167
312
|
return f"t{_atype}{_btype}", slice(_aindex, _bindex, _step)
|
|
168
313
|
else:
|
|
169
314
|
raise ValueError(f"Unsupported type: {type(key)}")
|
|
170
315
|
|
|
171
316
|
def __getitem__(self, key):
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
:param key:
|
|
175
|
-
only unit types:
|
|
176
|
-
int -> value
|
|
177
|
-
alpha -> value
|
|
178
|
-
slice -> sub Series (new CLS)
|
|
179
|
-
:return:
|
|
180
|
-
"""
|
|
181
|
-
_stype, _index = self.__dim1_parse_index_key(key)
|
|
317
|
+
_stype, _index = self._dim1_parse_index_key(key)
|
|
182
318
|
if _stype == 'n':
|
|
183
|
-
return self
|
|
184
|
-
elif _stype[0] != 't':
|
|
319
|
+
return self.copy() # None or ... Type
|
|
320
|
+
elif _stype[0] != 't': # return single value directly
|
|
185
321
|
return self._sr.iloc[_index]
|
|
186
322
|
else:
|
|
187
|
-
return self.
|
|
323
|
+
return self._construct_new_from_index(_index) # slice Type
|
|
188
324
|
|
|
189
325
|
def __setitem__(self, key, value):
|
|
190
|
-
_stype, _index = self.
|
|
326
|
+
_stype, _index = self._dim1_parse_index_key(key)
|
|
191
327
|
if _stype == 'n':
|
|
192
|
-
_index = slice()
|
|
193
|
-
self._sr.iloc[_index] = value
|
|
328
|
+
_index = slice(None)
|
|
329
|
+
self._sr.iloc[_index] = value # NOTE: Set value won't change the shape. So no need to construct new one.
|
|
194
330
|
|
|
195
331
|
def __delitem__(self, key):
|
|
196
|
-
_stype, _index = self.
|
|
332
|
+
_stype, _index = self._dim1_parse_index_key(key)
|
|
197
333
|
if _stype == 'n':
|
|
198
334
|
self.clear()
|
|
199
335
|
else:
|
|
200
|
-
self.
|
|
201
|
-
|
|
336
|
+
self._construct_new_from_delete(_index, inplace=True)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class ExcelIndexsLike_1DArray(_ExcelIndexsLike_1DArray_Base):
|
|
202
340
|
|
|
203
341
|
def append(self, *values):
|
|
204
342
|
"""
|
|
@@ -206,33 +344,30 @@ class _ExcelIndexsLike_1DArray:
|
|
|
206
344
|
:param values: Any. The values to append.
|
|
207
345
|
:return: None
|
|
208
346
|
"""
|
|
209
|
-
self.
|
|
210
|
-
self._reindex()
|
|
347
|
+
self._construct_new_from_insert(self.size, *values, inplace=True)
|
|
211
348
|
|
|
212
|
-
def insert(self, index, *values):
|
|
349
|
+
def insert(self, index: Union[str, int], *values):
|
|
213
350
|
"""
|
|
214
351
|
Insert values before the index
|
|
215
|
-
:param index: int|str. The index to insert before. (Can be a column-letter string)
|
|
352
|
+
:param index: int|str. The index to insert before. (Can be a column-letter string) But not support slice.
|
|
216
353
|
:param values: Any. The values to insert.
|
|
217
354
|
:return: None
|
|
218
355
|
"""
|
|
219
|
-
_stype, _index = self.
|
|
356
|
+
_stype, _index = self._dim1_parse_index_key(index)
|
|
220
357
|
if _stype[0] == "t" or _stype == "n":
|
|
221
358
|
raise ValueError(f"Here only accept non-slice index In {self.__class__.__name__}. But got {index}")
|
|
222
359
|
|
|
223
|
-
|
|
224
|
-
self._sr = pd.Series(_construct_list)
|
|
225
|
-
self._reindex()
|
|
360
|
+
self._construct_new_from_insert(_index, *values, inplace=True)
|
|
226
361
|
|
|
227
|
-
def pop(self, index, n: int = 1):
|
|
362
|
+
def pop(self, index: Union[str, int], n: int = 1):
|
|
228
363
|
"""
|
|
229
364
|
Remove and return the value at the index
|
|
230
|
-
:param index: int|str. The index to remove. (Can be a column-letter string)
|
|
365
|
+
:param index: int|str. The index to remove. (Can be a column-letter string) But not support slice.
|
|
231
366
|
:param n: int. The number of values to remove.
|
|
232
367
|
- if index + n > size, remove until the end.
|
|
233
368
|
:return: Any. The removed value. (If n > 1, return a list of values)
|
|
234
369
|
"""
|
|
235
|
-
_stype, _index = self.
|
|
370
|
+
_stype, _index = self._dim1_parse_index_key(index)
|
|
236
371
|
if _stype[0] == "t" or _stype == "n":
|
|
237
372
|
raise ValueError(f"Here only accept non-slice index In {self.__class__.__name__}. But got {index}")
|
|
238
373
|
|
|
@@ -241,9 +376,7 @@ class _ExcelIndexsLike_1DArray:
|
|
|
241
376
|
end = self.size
|
|
242
377
|
|
|
243
378
|
_poped = self._sr.iloc[_index:end].to_list()
|
|
244
|
-
|
|
245
|
-
self._sr = pd.Series(_construct_list)
|
|
246
|
-
self._reindex()
|
|
379
|
+
self._construct_new_from_delete(slice(_index, end), inplace=True)
|
|
247
380
|
if n == 1:
|
|
248
381
|
return _poped[0]
|
|
249
382
|
return _poped
|
|
@@ -254,10 +387,7 @@ class _ExcelIndexsLike_1DArray:
|
|
|
254
387
|
:param other: Series/List/NumpyArray/ExcelIndexed-1D
|
|
255
388
|
:return: None
|
|
256
389
|
"""
|
|
257
|
-
|
|
258
|
-
other = self.__class__(other)
|
|
259
|
-
self._sr = self._sr._append(other._sr, ignore_index=True)
|
|
260
|
-
self._reindex()
|
|
390
|
+
self._construct_new_from_insert(self.size, *other, inplace=True)
|
|
261
391
|
|
|
262
392
|
def index(self, value):
|
|
263
393
|
"""
|
|
@@ -292,22 +422,21 @@ class _ExcelIndexsLike_1DArray:
|
|
|
292
422
|
Reverse the Series in place.
|
|
293
423
|
:return: None
|
|
294
424
|
"""
|
|
295
|
-
self.
|
|
296
|
-
self._reindex()
|
|
425
|
+
self._construct_new_from_index(slice(None, None, -1), inplace=True)
|
|
297
426
|
|
|
298
427
|
def clear(self):
|
|
299
428
|
"""
|
|
300
429
|
Clear the Series.
|
|
301
430
|
:return: None
|
|
302
431
|
"""
|
|
303
|
-
self.
|
|
432
|
+
self._construct_new_from_delete(slice(None), inplace=True)
|
|
304
433
|
|
|
305
434
|
def copy(self):
|
|
306
435
|
"""
|
|
307
436
|
Return a shallow copy of the Series.
|
|
308
437
|
:return: Series. A shallow copy of the Series.
|
|
309
438
|
"""
|
|
310
|
-
return self.__class__(self._sr.copy(), copy=False)
|
|
439
|
+
return self.__class__(self._sr.copy(), copy=False) # NOTE: copy won't change the shape. So no need to construct new one.
|
|
311
440
|
|
|
312
441
|
def sort(self, key=None, reverse=False):
|
|
313
442
|
"""
|
|
@@ -318,8 +447,8 @@ class _ExcelIndexsLike_1DArray:
|
|
|
318
447
|
"""
|
|
319
448
|
_construct_list = self._sr.to_list()
|
|
320
449
|
_construct_list.sort(key=key, reverse=reverse)
|
|
321
|
-
self._sr = pd.Series(_construct_list)
|
|
322
|
-
self.
|
|
450
|
+
self._sr = pd.Series(_construct_list) # NOTE: sort won't change the shape. So no need to construct new one.
|
|
451
|
+
self._reindexself()
|
|
323
452
|
|
|
324
453
|
def __iter__(self):
|
|
325
454
|
return iter(self._sr)
|
|
@@ -328,7 +457,7 @@ class _ExcelIndexsLike_1DArray:
|
|
|
328
457
|
return value in self._sr
|
|
329
458
|
|
|
330
459
|
def __eq__(self, other):
|
|
331
|
-
if not isinstance(other,
|
|
460
|
+
if not isinstance(other, ExcelIndexsLike_1DArray):
|
|
332
461
|
other = self.__class__(other)
|
|
333
462
|
return self._sr.equals(other._sr)
|
|
334
463
|
|
|
@@ -347,14 +476,14 @@ class _ExcelIndexsLike_1DArray:
|
|
|
347
476
|
return self.__class__(_construct_list)
|
|
348
477
|
|
|
349
478
|
|
|
350
|
-
class Row(
|
|
479
|
+
class Row(ExcelIndexsLike_1DArray): # Like 1: (A B C D)
|
|
351
480
|
_CLS_DEFAULT_INDEX_TYPE = "s"
|
|
352
481
|
|
|
353
482
|
def __str__(self):
|
|
354
483
|
return "Row Series:\n" + super().__str__() + "\n"
|
|
355
484
|
|
|
356
485
|
|
|
357
|
-
class Col(
|
|
486
|
+
class Col(ExcelIndexsLike_1DArray): # Like A: (1 2 3 4)
|
|
358
487
|
_CLS_DEFAULT_INDEX_TYPE = "i"
|
|
359
488
|
|
|
360
489
|
def __str__(self):
|
|
@@ -393,7 +522,7 @@ class _ExcelIndexsLike_2DArray:
|
|
|
393
522
|
warnings.warn(
|
|
394
523
|
f"Table's input should be rows, but got a column. Regarded as a row.(at index:{i})"
|
|
395
524
|
)
|
|
396
|
-
elif isinstance(_l,
|
|
525
|
+
elif isinstance(_l, ExcelIndexsLike_1DArray):
|
|
397
526
|
_construct_list.append(_l._sr.to_list())
|
|
398
527
|
elif isinstance(_l, list):
|
|
399
528
|
_construct_list.append(_l.copy())
|
|
@@ -462,10 +591,8 @@ class _ExcelIndexsLike_2DArray:
|
|
|
462
591
|
_cnd[lt.ir, lt.ic] = ':' + _cnd[lt.ir, lt.ic][1:]
|
|
463
592
|
_unhandled_mask[lt.ir:rb.ir + 1, lt.ic:rb.ic + 1] = False
|
|
464
593
|
|
|
465
|
-
|
|
466
594
|
return str(pd.DataFrame(_cnd, index=self._df.index, columns=self._df.columns, copy=False))
|
|
467
595
|
|
|
468
|
-
|
|
469
596
|
def __repr__(self):
|
|
470
597
|
c = Coord(self._df.shape[1] - 1, self._df.shape[0] - 1)
|
|
471
598
|
return f"Table[:'{c.letter}']"
|
|
@@ -813,7 +940,6 @@ class _ExcelIndexsLike_2DArray:
|
|
|
813
940
|
if isinstance(ic, slice):
|
|
814
941
|
ic = ic.stop if ic.stop is not None else sc
|
|
815
942
|
|
|
816
|
-
|
|
817
943
|
if ir is None:
|
|
818
944
|
ir = sr
|
|
819
945
|
if ic is None:
|
|
@@ -978,7 +1104,6 @@ class _ExcelIndexsLike_2DArray:
|
|
|
978
1104
|
else:
|
|
979
1105
|
self._df.iloc[_i0, _i1] = np.nan
|
|
980
1106
|
|
|
981
|
-
|
|
982
1107
|
def append(self, *values, axis=0):
|
|
983
1108
|
"""
|
|
984
1109
|
Append Rows to the end of the table
|
|
@@ -995,7 +1120,6 @@ class _ExcelIndexsLike_2DArray:
|
|
|
995
1120
|
row.extend(values)
|
|
996
1121
|
self._reconstruct(_construct, *self._other_raws, copy=False)
|
|
997
1122
|
|
|
998
|
-
|
|
999
1123
|
def clear(self):
|
|
1000
1124
|
"""
|
|
1001
1125
|
Clear the table
|
|
@@ -1051,7 +1175,6 @@ class _ExcelIndexsLike_2DArray:
|
|
|
1051
1175
|
if _c > _new_c:
|
|
1052
1176
|
self._reconstruct(self._df.iloc[:, :_new_c], *self._other_raws, copy=False)
|
|
1053
1177
|
|
|
1054
|
-
|
|
1055
1178
|
def __iter__(self):
|
|
1056
1179
|
for _r in self._df.values.tolist():
|
|
1057
1180
|
yield _r
|
|
@@ -1076,7 +1199,6 @@ class _ExcelIndexsLike_2DArray:
|
|
|
1076
1199
|
return self.shape[0]
|
|
1077
1200
|
|
|
1078
1201
|
|
|
1079
|
-
|
|
1080
1202
|
class StyleRow(Row):
|
|
1081
1203
|
def set(self, key, value):
|
|
1082
1204
|
"""
|
|
@@ -1088,6 +1210,7 @@ class StyleRow(Row):
|
|
|
1088
1210
|
for ic in range(self.shape[0]):
|
|
1089
1211
|
self._sr.iloc[ic][key] = value
|
|
1090
1212
|
|
|
1213
|
+
|
|
1091
1214
|
class StyleCol(Col):
|
|
1092
1215
|
def set(self, key, value):
|
|
1093
1216
|
"""
|
|
@@ -1099,9 +1222,11 @@ class StyleCol(Col):
|
|
|
1099
1222
|
for ir in range(self.shape[0]):
|
|
1100
1223
|
self._sr.iloc[ir][key] = value
|
|
1101
1224
|
|
|
1225
|
+
|
|
1102
1226
|
class StyleTable(_ExcelIndexsLike_2DArray):
|
|
1103
1227
|
_ROW_CLS = StyleRow
|
|
1104
1228
|
_COL_CLS = StyleCol
|
|
1229
|
+
|
|
1105
1230
|
def set(self, key, value):
|
|
1106
1231
|
"""
|
|
1107
1232
|
Set the style of each cell
|
|
@@ -1113,9 +1238,10 @@ class StyleTable(_ExcelIndexsLike_2DArray):
|
|
|
1113
1238
|
for ic in range(self.shape[1]):
|
|
1114
1239
|
self._df.iloc[ir, ic][key] = value
|
|
1115
1240
|
|
|
1241
|
+
|
|
1116
1242
|
class Table(_ExcelIndexsLike_2DArray):
|
|
1117
1243
|
# def __init__(self, _from=None, *, copy: bool = True):
|
|
1118
|
-
def __init__(self, data=None, styles=None, merges:list=None, *, copy: bool = True):
|
|
1244
|
+
def __init__(self, data=None, styles=None, merges: list = None, *, copy: bool = True):
|
|
1119
1245
|
super().__init__(data, copy=copy)
|
|
1120
1246
|
self._styles = StyleTable() if styles is None else (styles.copy() if isinstance(styles, StyleTable) else StyleTable(styles))
|
|
1121
1247
|
self._merges = []
|
|
@@ -1143,7 +1269,7 @@ class Table(_ExcelIndexsLike_2DArray):
|
|
|
1143
1269
|
def merges(self):
|
|
1144
1270
|
return self._merges
|
|
1145
1271
|
|
|
1146
|
-
def merge(self, key:U[int, str, slice, None], key1:U[int, str, slice, None]=EMPTY_INDEX, *, border:Border=None):
|
|
1272
|
+
def merge(self, key: U[int, str, slice, None], key1: U[int, str, slice, None] = EMPTY_INDEX, *, border: Border = None):
|
|
1147
1273
|
if key1 is not EMPTY_INDEX:
|
|
1148
1274
|
key = key, key1
|
|
1149
1275
|
|
|
@@ -1296,6 +1422,7 @@ class Table(_ExcelIndexsLike_2DArray):
|
|
|
1296
1422
|
|
|
1297
1423
|
|
|
1298
1424
|
def __1d_test(_print=True):
|
|
1425
|
+
|
|
1299
1426
|
d = [1, 2, 3, 4, 5]
|
|
1300
1427
|
|
|
1301
1428
|
r = Row(d)
|
|
@@ -1326,6 +1453,16 @@ def __1d_test(_print=True):
|
|
|
1326
1453
|
if _print: print(f"删除测试:\n{r}")
|
|
1327
1454
|
|
|
1328
1455
|
|
|
1456
|
+
def _1d_unit_test(_print=True):
|
|
1457
|
+
tc = TimeRecorder()
|
|
1458
|
+
__1d_test(_print)
|
|
1459
|
+
warnings.filterwarnings('ignore')
|
|
1460
|
+
for i in range(999):
|
|
1461
|
+
__1d_test(_print)
|
|
1462
|
+
warnings.filterwarnings('default')
|
|
1463
|
+
print(f"测试结束,耗时: {tc.dms(1000)} ms / 测试")
|
|
1464
|
+
|
|
1465
|
+
|
|
1329
1466
|
def __2d_test(_print=True):
|
|
1330
1467
|
import colorama
|
|
1331
1468
|
r0 = Col([1, 2, 3, 4, 5])
|
|
@@ -1397,4 +1534,4 @@ if __name__ == '__main__':
|
|
|
1397
1534
|
# print(f"Finish Test. Cost:{round((time.time() - _a) * 1000, 2)} ms")
|
|
1398
1535
|
# exit(0)
|
|
1399
1536
|
|
|
1400
|
-
|
|
1537
|
+
_1d_unit_test(False)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tpltable
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: define "Excel" "Table|StyleTable" "Row|Col|StyleRow|StyleCol". Can dynamic modify excel data & styles. Support multiple kinds of indexes. (70%)
|
|
5
5
|
Author-email: 2229066748@qq.com
|
|
6
6
|
Maintainer: Eagle'sBaby
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|