reykit 1.1.33__py3-none-any.whl → 1.1.34__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.
reykit/rtable.py CHANGED
@@ -9,503 +9,509 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import Any, TypedDict, overload
13
- from collections.abc import Iterable
12
+ from typing import Any, TypedDict, Literal, overload
13
+ from collections.abc import Collection, MutableMapping
14
14
  from os.path import abspath as os_abspath
15
- from pandas import DataFrame, ExcelWriter, isnull
16
- from sqlalchemy.engine.cursor import CursorResult
15
+ from sqlalchemy.engine.cursor import CursorResult, Row as CursorRow
16
+ from pandas import DataFrame, Series, ExcelWriter
17
17
 
18
+ from .rbase import Base, throw
19
+ from .rdata import to_json
18
20
  from .ros import File
19
- from .rtext import to_json, to_text
21
+ from .rtext import to_text
20
22
  from .rtime import time_to
21
23
 
22
24
 
23
25
  __all__ = (
24
- 'to_table',
25
- 'to_dict',
26
- 'to_list',
27
- 'to_df',
28
- 'to_json',
29
- 'to_text',
30
- 'to_sql',
31
- 'to_html',
32
- 'to_csv',
33
- 'to_excel'
26
+ 'is_row',
27
+ 'is_table',
28
+ 'Table'
34
29
  )
35
30
 
36
31
 
37
- type Table = list[dict] | dict | CursorResult | DataFrame
32
+ type RowData = MutableMapping | CursorRow | Series
33
+ type TableData = Collection[MutableMapping] | RowData | CursorResult | DataFrame
38
34
  SheetSet = TypedDict('SheetsSet', {'name': str, 'index': int, 'fields': str | list[str]})
39
35
 
40
36
 
41
- def to_table(
42
- data: Table | Iterable[Iterable],
43
- fields: Iterable | None = None
44
- ) -> list[dict]:
37
+ @overload
38
+ def is_row(obj: RowData) -> Literal[True]: ...
39
+
40
+ @overload
41
+ def is_row(obj: Any) -> Literal[False]: ...
42
+
43
+ def is_row(obj: Any) -> bool:
45
44
  """
46
- Convert data to table in `list[dict]` format, keys and keys sort of the dictionary are the same.
45
+ Judge whether it is row format.
47
46
 
48
47
  Parameters
49
48
  ----------
50
- data : Table format data.
51
- fields : Table fields.
52
- - `None`: Infer.
53
- - `Iterable`: Use values in Iterable.
49
+ obj : Ojbect.
54
50
 
55
51
  Returns
56
52
  -------
57
- Table in `list[dict]` format.
53
+ Judgment result.
58
54
  """
59
55
 
60
- # Convert.
61
- match data:
56
+ # Judge.
57
+ result = isinstance(obj, (MutableMapping, CursorRow, Series))
62
58
 
63
- ## From CursorResult object.
64
- case CursorResult():
65
- fields = fields or data.keys()
66
- data_table = [
67
- dict(zip(fields, row))
68
- for row in data
69
- ]
70
-
71
- ## From DataFrame object.
72
- case DataFrame():
73
- data_df = to_df(data, fields)
74
- fields = data_df.columns
75
- data_table = [
76
- dict(zip(
77
- fields,
78
- [
79
- None
80
- if (type(value) != list and isnull(value))
81
- else value
82
- for value in row
83
- ]
84
- ))
85
- for row in data_df.values
86
- ]
87
-
88
- ## From other object.
89
- case _:
90
- data_df = to_df(data, fields)
91
- data_table = to_table(data_df)
92
-
93
- return data_table
59
+ return result
94
60
 
95
61
 
96
62
  @overload
97
- def to_dict(
98
- data: Table | Iterable[Iterable],
99
- key_field: int | str = 0
100
- ) -> dict[Any, dict]: ...
63
+ def is_table(obj: TableData) -> bool: ...
101
64
 
102
65
  @overload
103
- def to_dict(
104
- data: Table | Iterable[Iterable],
105
- key_field: int | str = 0,
106
- *,
107
- val_field: int | str
108
- ) -> dict: ...
109
-
110
- def to_dict(
111
- data: Table | Iterable[Iterable],
112
- key_field: int | str = 0,
113
- val_field: int | str | None = None
114
- ) -> dict[Any, dict] | dict:
66
+ def is_table(obj: Any) -> Literal[False]: ...
67
+
68
+ def is_table(obj: Any) -> bool:
115
69
  """
116
- Convert data as dictionary.
70
+ Judge whether it is table format, and keys sort of the row are the same.
117
71
 
118
72
  Parameters
119
73
  ----------
120
- data : Table format data.
121
- key_field : Key field of dictionary.
122
- - `int`: Subscript index.
123
- - `str`: Name index.
124
- val_field : Value field of dictionary.
125
- - `None`: All fields except key.
126
- - `int`: Subscript index.
127
- - `str`: Name index.
74
+ obj : Ojbect.
128
75
 
129
76
  Returns
130
77
  -------
131
- Dictionary.
78
+ Judgment result.
132
79
  """
133
80
 
134
- # Handle parameter.
135
- data = to_table(data)
136
-
137
- ## Check parameter.
138
- if len(data) == 0:
139
- return {}
140
-
141
- # Get fields.
142
- fields = list(data[0].keys())
143
- if type(key_field) == int:
144
- key_field = fields[key_field]
145
- if type(val_field) == int:
146
- val_field = fields[val_field]
147
-
148
- # Convert.
149
-
150
- ## Value is all fields except key.
151
- if val_field is None:
152
- data_dict = {
153
- row[key_field]: {
154
- key: value
155
- for key, value in row.items()
156
- if key != key_field
157
- }
158
- for row in data
159
- }
160
-
161
- ## Value is one field.
162
- else:
163
- data_dict = {
164
- row[key_field]: row[val_field]
165
- for row in data
166
- }
167
-
168
- return data_dict
169
-
170
-
171
- def to_list(
172
- data: Table | Iterable[Iterable],
173
- field: int | str = 0,
174
- ) -> list:
81
+ # Judge.
82
+ if is_row(obj):
83
+ return True
84
+ if isinstance(obj, (CursorResult, DataFrame)):
85
+ return True
86
+ if isinstance(obj, Collection):
87
+ keys_strs = []
88
+ for row in obj:
89
+ if not isinstance(row, MutableMapping):
90
+ break
91
+ keys_str = ':'.join(row.keys())
92
+ keys_strs.append(keys_str)
93
+ keys_strs = set(keys_strs)
94
+ if len(keys_strs) == 1:
95
+ return True
96
+
97
+ return False
98
+
99
+
100
+ class Table(Base):
175
101
  """
176
- Convert data as list.
177
-
178
- Parameters
179
- ----------
180
- data : Table format data.
181
- field : Field of value.
182
- - `int`: Subscript index.
183
- - `str`: Name index.
184
-
185
- Returns
186
- -------
187
- List.
102
+ Table type.
188
103
  """
189
104
 
190
- # Handle parameter.
191
- data = to_table(data)
192
105
 
193
- ## Check parameter.
194
- if len(data) == 0:
195
- return []
106
+ def __init__(self, data: TableData) -> None:
107
+ """
108
+ Build instance attributes.
109
+
110
+ Parameters
111
+ ----------
112
+ data : Data.
113
+ """
114
+
115
+ # Set parameter.
116
+ self.data = data
117
+
118
+
119
+ def to_row(self) -> dict:
120
+ """
121
+ Convert data to `dict` format.
122
+
123
+ Returns
124
+ -------
125
+ Converted data.
126
+ """
127
+
128
+ # Convert.
129
+ match self.data:
130
+ case MutableMapping():
131
+ result = [dict(self.data)]
132
+ case CursorRow():
133
+ result = [dict(self.data._mapping)]
134
+ case Series():
135
+ result = [dict(self.data.items())]
136
+
137
+ return result
138
+
139
+
140
+ def to_table(self) -> list[dict]:
141
+ """
142
+ Convert data to `list[dict]` format.
143
+
144
+ Returns
145
+ -------
146
+ Converted data.
147
+ """
148
+
149
+ # Convert.
150
+ match self.data:
151
+ case MutableMapping() | CursorRow() | Series():
152
+ result = [self.to_row()]
153
+ case CursorResult():
154
+ result = [
155
+ dict(row)
156
+ for row in self.data.mappings()
157
+ ]
158
+ case DataFrame():
159
+ result = self.data.to_dict('records')
160
+ case Collection():
161
+ if not is_table(self.data):
162
+ text = 'is not table format, or keys sort of the row are the not same'
163
+ throw(TypeError, text=text)
164
+ result = [
165
+ dict(row)
166
+ for row in self.data
167
+ ]
168
+
169
+ return result
170
+
171
+
172
+ @overload
173
+ def to_dict(
174
+ self,
175
+ key_field: int | str = 0
176
+ ) -> dict[Any, dict]: ...
177
+
178
+ @overload
179
+ def to_dict(
180
+ self,
181
+ key_field: int | str = 0,
182
+ *,
183
+ val_field: int | str
184
+ ) -> dict: ...
185
+
186
+ def to_dict(
187
+ self,
188
+ key_field: int | str = 0,
189
+ val_field: int | str | None = None
190
+ ) -> dict[Any, dict] | dict:
191
+ """
192
+ Convert data as dictionary.
193
+
194
+ Parameters
195
+ ----------
196
+ key_field : Key field of dictionary.
197
+ - `int`: Subscript index.
198
+ - `str`: Name index.
199
+ val_field : Value field of dictionary.
200
+ - `None`: All fields except key.
201
+ - `int`: Subscript index.
202
+ - `str`: Name index.
203
+
204
+ Returns
205
+ -------
206
+ Dictionary.
207
+ """
208
+
209
+ # Get parameter.
210
+ data = self.to_table()
211
+
212
+ # Check.
213
+ if len(data) == 0:
214
+ return {}
215
+
216
+ # Get fields.
217
+ fields = list(data[0].keys())
218
+ if type(key_field) == int:
219
+ key_field = fields[key_field]
220
+ if type(val_field) == int:
221
+ val_field = fields[val_field]
222
+
223
+ # Convert.
224
+
225
+ ## Value is all fields except key.
226
+ if val_field is None:
227
+ data_dict = {
228
+ row[key_field]: {
229
+ key: value
230
+ for key, value in row.items()
231
+ if key != key_field
232
+ }
233
+ for row in data
234
+ }
196
235
 
197
- # Get fields.
198
- fields = list(data[0].keys())
199
- if type(field) == int:
200
- field = fields[field]
236
+ ## Value is one field.
237
+ else:
238
+ data_dict = {
239
+ row[key_field]: row[val_field]
240
+ for row in data
241
+ }
201
242
 
202
- # Convert.
203
- data_list = [
204
- row[field]
205
- for row in data
206
- ]
243
+ return data_dict
207
244
 
208
- return data_list
209
245
 
246
+ def to_list(self, field: int | str = 0) -> list:
247
+ """
248
+ Convert data as list.
210
249
 
211
- def to_df(
212
- data: Table | Iterable[Iterable],
213
- fields: Iterable | None = None
214
- ) -> DataFrame:
215
- """
216
- Convert data to table of `DataFrame` object.
250
+ Parameters
251
+ ----------
252
+ field : Field of value.
253
+ - `int`: Subscript index.
254
+ - `str`: Name index.
217
255
 
218
- Parameters
219
- ----------
220
- data : Table format data.
221
- fields : Table fields.
222
- - `None`: Infer.
223
- - `Iterable`: Use values in Iterable.
256
+ Returns
257
+ -------
258
+ List.
259
+ """
224
260
 
225
- Returns
226
- -------
227
- DataFrame object.
228
- """
261
+ # Get parameter.
262
+ data = self.to_table()
229
263
 
230
- # Convert.
231
- match data:
264
+ # Check.
265
+ if len(data) == 0:
266
+ return []
232
267
 
233
- ## From CursorResult object.
234
- case CursorResult():
235
- fields = fields or data.keys()
236
- data_df = DataFrame(data, columns=fields)
237
- data_df = data_df.convert_dtypes()
268
+ # Get fields.
269
+ fields = list(data[0].keys())
270
+ if type(field) == int:
271
+ field = fields[field]
238
272
 
239
- ## From DataFrame object.
240
- case DataFrame():
241
- data_df = data.convert_dtypes()
242
- if fields is not None:
243
- data_df.columns = fields
273
+ # Convert.
274
+ data_list = [
275
+ row[field]
276
+ for row in data
277
+ ]
244
278
 
245
- ## From other object.
246
- case _:
247
- if type(data) == dict:
248
- data = [data]
249
- data_df = DataFrame(data, columns=fields)
250
- data_df = data_df.convert_dtypes()
279
+ return data_list
251
280
 
252
- return data_df
253
281
 
282
+ def to_text(self, width: int | None = None) -> str:
283
+ """
284
+ Convert data to text.
254
285
 
255
- def to_json(
256
- data: Table | Iterable[Iterable],
257
- fields: Iterable | None = None,
258
- compact: bool = True
259
- ) -> str:
260
- """
261
- Convert data to JSON string.
286
+ Parameters
287
+ ----------
288
+ width : Format width.
289
+ - `None` : Use terminal display character size.
262
290
 
263
- Parameters
264
- ----------
265
- data : Table format data.
266
- fields : Table fields.
267
- - `None`: Infer.
268
- - `Iterable`: Use values in Iterable.
269
- compact : Whether compact content.
291
+ Returns
292
+ -------
293
+ Formatted text.
294
+ """
270
295
 
271
- Returns
272
- -------
273
- JSON string.
274
- """
296
+ # Get parameter.
297
+ data = self.to_table()
275
298
 
276
- # Handle parameter.
277
- data = to_table(data, fields)
299
+ # Convert.
300
+ text = to_text(data, width)
278
301
 
279
- # Convert.
280
- string = to_json(data, compact)
302
+ return text
281
303
 
282
- return string
283
304
 
305
+ def to_json(self, compact: bool = True) -> str:
306
+ """
307
+ Convert data to JSON string.
284
308
 
285
- def to_text(
286
- data: Table | Iterable[Iterable],
287
- fields: Iterable | None = None,
288
- width: int = 100
289
- ) -> str:
290
- """
291
- Convert data to text.
309
+ Parameters
310
+ ----------
311
+ compact : Whether compact content.
292
312
 
293
- Parameters
294
- ----------
295
- data : Table format data.
296
- fields : Table fields.
297
- - `None`: Infer.
298
- - `Iterable`: Use values in Iterable.
299
- width : Format width.
313
+ Returns
314
+ -------
315
+ JSON string.
316
+ """
300
317
 
301
- Returns
302
- -------
303
- Formatted text.
304
- """
318
+ # Get parameter.
319
+ data = self.to_table()
305
320
 
306
- # Handle parameter.
307
- data = to_table(data, fields)
321
+ # Convert.
322
+ string = to_json(data, compact)
308
323
 
309
- # Convert.
310
- text = to_text(data, width)
324
+ return string
311
325
 
312
- return text
313
326
 
327
+ def to_sql(self) -> str:
328
+ """
329
+ Convert data to SQL string.
314
330
 
315
- def to_sql(
316
- data: Table | Iterable[Iterable],
317
- fields: Iterable | None = None
318
- ) -> str:
319
- """
320
- Convert data to SQL string.
331
+ Returns
332
+ -------
333
+ SQL string.
334
+ """
321
335
 
322
- Parameters
323
- ----------
324
- data : Table format data.
325
- fields : Table fields.
326
- - `None`: Infer.
327
- - `Iterable`: Use values in Iterable.
336
+ # Get parameter.
337
+ data = self.to_table()
338
+ data = [
339
+ {
340
+ key : (
341
+ repr(time_to(value, raising=False))
342
+ if bool(value)
343
+ else 'NULL'
344
+ )
345
+ for key, value in row.items()
346
+ }
347
+ for row in data
348
+ ]
328
349
 
329
- Returns
330
- -------
331
- SQL string.
332
- """
350
+ # Check.
351
+ if len(data) == 0:
352
+ throw(ValueError, data)
333
353
 
334
- # Get fields of table.
335
- if isinstance(data, CursorResult):
336
- fields = fields or data.keys()
337
- else:
338
- data = to_table(data, fields)
339
- fields = data[0].keys()
340
-
341
- # Generate SQL.
342
- sql_rows_values = [
343
- [
344
- repr(time_to(value, raising=False))
345
- if value is not None
346
- else 'NULL'
347
- for value in row
354
+ # Generate SQL.
355
+ sql_rows = [
356
+ 'SELECT ' + ','.join(row.values())
357
+ for row in data[1:]
348
358
  ]
349
- for row in data
350
- ]
351
- sql_rows = [
352
- 'SELECT ' + ','.join(row_values)
353
- for row_values in sql_rows_values
354
- ]
355
- sql_row_first = 'SELECT ' + ','.join(
356
- [
357
- f'{value} AS `{key}`'
358
- for key, value in list(zip(fields, sql_rows_values[0]))
359
- ]
360
- )
361
- sql_rows[0] = sql_row_first
362
- data_sql = ' UNION ALL '.join(sql_rows)
359
+ sql_row_first = 'SELECT ' + ','.join(
360
+ [
361
+ f'{value} AS `{key}`'
362
+ for key, value in data[0].items()
363
+ ]
364
+ )
365
+ sql_rows.insert(0, sql_row_first)
366
+ data_sql = ' UNION ALL '.join(sql_rows)
363
367
 
364
- return data_sql
368
+ return data_sql
365
369
 
366
370
 
367
- def to_html(
368
- data: Table | Iterable[Iterable],
369
- fields: Iterable | None = None
370
- ) -> str:
371
- """
372
- Convert data to HTML string.
371
+ def to_df(self) -> DataFrame:
372
+ """
373
+ Convert data to table of `DataFrame` object.
373
374
 
374
- Parameters
375
- ----------
376
- data : Table format data.
377
- fields : Table fields.
378
- - `None`: Infer.
379
- - `Iterable`: Use values in Iterable.
375
+ Returns
376
+ -------
377
+ DataFrame object.
378
+ """
380
379
 
381
- Returns
382
- -------
383
- HTML string.
384
- """
380
+ # Check.
381
+ if type(self.data) == DataFrame:
382
+ return self.data
385
383
 
386
- # Handle parameter.
387
- data_df = to_df(data, fields)
384
+ # Get parameter.
385
+ data = self.to_table()
388
386
 
389
- # Convert.
390
- data_html = data_df.to_html(col_space=50, index=False, justify='center')
387
+ # Convert.
388
+ result = DataFrame(data)
391
389
 
392
- return data_html
390
+ return result
393
391
 
394
392
 
395
- def to_csv(
396
- data: Table | Iterable[Iterable],
397
- path: str = 'data.csv',
398
- fields: Iterable | None = None
399
- ) -> str:
400
- """
401
- Convert data to save CSV format file.
402
- When file exist, then append data.
393
+ def to_html(self) -> str:
394
+ """
395
+ Convert data to HTML string.
403
396
 
404
- Parameters
405
- ----------
406
- data : Table format data.
407
- path : File save path.
408
- fields : Table fields.
409
- - `None`: Infer.
410
- - `Iterable`: Use values in Iterable.
397
+ Returns
398
+ -------
399
+ HTML string.
400
+ """
411
401
 
412
- Returns
413
- -------
414
- File absolute path.
415
- """
402
+ # Get parameter.
403
+ data = self.to_df()
416
404
 
417
- # Handle parameter.
418
- data_df = to_df(data, fields)
419
- rfile = File(path)
420
- if rfile:
421
- header = False
422
- else:
423
- header = True
405
+ # Convert.
406
+ result = data.to_html(col_space=50, index=False, justify='center')
424
407
 
425
- # Save file.
426
- data_df.to_csv(rfile.path, header=header, index=False, mode='a')
408
+ return result
427
409
 
428
- return rfile.path
429
410
 
411
+ def to_csv(self, path: str = 'data.csv') -> str:
412
+ """
413
+ Convert data to save CSV format file.
414
+ When file exist, then append data.
430
415
 
431
- def to_excel(
432
- data: Table | Iterable[Iterable],
433
- path: str = 'data.xlsx',
434
- group_field: str | None = None,
435
- sheets_set: dict[str | int, SheetSet] = {}
436
- ) -> str:
437
- """
438
- Convert data to save Excel format file and return sheet name and sheet data.
439
- When file exist, then rebuild file.
440
-
441
- Parameters
442
- ----------
443
- data : Table format data.
444
- path : File save path.
445
- group_field : Group filed.
446
- sheets_set : Set sheet new name and sort sheet and filter sheet fields,
447
- key is old name or index, value is set parameters.
448
- - Parameter `name` : Set sheet new name.
449
- - Parameter `index` : Sort sheet.
450
- - Parameter `fields` : Filter sheet fields.
416
+ Parameters
417
+ ----------
418
+ path : File save path.
451
419
 
452
- Returns
453
- -------
454
- File absolute path.
455
-
456
- Examples
457
- --------
458
- >>> data = [
459
- ... {'id': 1, 'age': 21, 'group': 'one'},
460
- ... {'id': 2, 'age': 22, 'group': 'one'},
461
- ... {'id': 3, 'age': 23, 'group': 'two'}
462
- ... ]
463
- >>> sheets_set = {
464
- ... 'one': {'name': 'age', 'index': 2, 'fields': ['id', 'age']},
465
- ... 'two': {'name': 'id', 'index': 1, 'fields': 'id'}
466
- ... }
467
- >>> to_excel(data, 'file.xlsx', 'group', sheets_set)
468
- """
420
+ Returns
421
+ -------
422
+ File absolute path.
423
+ """
469
424
 
470
- # Handle parameter.
471
- if type(data) != DataFrame:
472
- data = to_df(data)
473
- path = os_abspath(path)
474
-
475
- # Generate sheets.
476
- if group_field is None:
477
- data_group = (('Sheet1', data),)
478
- else:
479
- data_group = data.groupby(group_field)
480
- sheets_table_before = []
481
- sheets_table_after = []
482
- for index, sheet_table in enumerate(data_group):
483
- sheet_name, sheet_df = sheet_table
484
- if group_field is not None:
485
- del sheet_df[group_field]
486
- if sheet_name in sheets_set:
487
- sheet_set = sheets_set[sheet_name]
488
- elif index in sheets_set:
489
- sheet_set = sheets_set[index]
425
+ # Get parameter.
426
+ data = self.to_df()
427
+ rfile = File(path)
428
+ if rfile:
429
+ header = False
490
430
  else:
491
- sheets_table_after.append((sheet_name, sheet_df))
492
- continue
493
- if 'name' in sheet_set:
494
- sheet_name = sheet_set['name']
495
- if 'fields' in sheet_set:
496
- sheet_df = sheet_df[sheet_set['fields']]
497
- if 'index' in sheet_set:
498
- sheets_table_before.append((sheet_set['index'], (sheet_name, sheet_df)))
431
+ header = True
432
+
433
+ # Save file.
434
+ data.to_csv(rfile.path, header=header, index=False, mode='a')
435
+
436
+ return rfile.path
437
+
438
+
439
+ def to_excel(
440
+ self,
441
+ path: str = 'data.xlsx',
442
+ group_field: str | None = None,
443
+ sheets_set: dict[str | int, SheetSet] = {}
444
+ ) -> str:
445
+ """
446
+ Convert data to save Excel format file and return sheet name and sheet data.
447
+ When file exist, then rebuild file.
448
+
449
+ Parameters
450
+ ----------
451
+ path : File save path.
452
+ group_field : Group filed.
453
+ sheets_set : Set sheet new name and sort sheet and filter sheet fields,
454
+ key is old name or index, value is set parameters.
455
+ - Parameter `name` : Set sheet new name.
456
+ - Parameter `index` : Sort sheet.
457
+ - Parameter `fields` : Filter sheet fields.
458
+
459
+ Returns
460
+ -------
461
+ File absolute path.
462
+
463
+ Examples
464
+ --------
465
+ >>> data = [
466
+ ... {'id': 1, 'age': 21, 'group': 'one'},
467
+ ... {'id': 2, 'age': 22, 'group': 'one'},
468
+ ... {'id': 3, 'age': 23, 'group': 'two'}
469
+ ... ]
470
+ >>> sheets_set = {
471
+ ... 'one': {'name': 'age', 'index': 2, 'fields': ['id', 'age']},
472
+ ... 'two': {'name': 'id', 'index': 1, 'fields': 'id'}
473
+ ... }
474
+ >>> to_excel(data, 'file.xlsx', 'group', sheets_set)
475
+ """
476
+
477
+ # Get parameter.
478
+ data = self.to_df()
479
+ path = os_abspath(path)
480
+
481
+ # Generate sheets.
482
+ if group_field is None:
483
+ data_group = (('Sheet1', data),)
499
484
  else:
500
- sheets_table_after.append((sheet_name, sheet_df))
501
- sort_func = lambda item: item[0]
502
- sheets_table_before.sort(key=sort_func)
503
- sheets_table = [sheet_table for sheet_index, sheet_table in sheets_table_before] + sheets_table_after
504
-
505
- # Save file.
506
- excel = ExcelWriter(path)
507
- for sheet_name, sheet_df in sheets_table:
508
- sheet_df.to_excel(excel, sheet_name, index=False)
509
- excel.close()
510
-
511
- return path
485
+ data_group = data.groupby(group_field)
486
+ sheets_table_before = []
487
+ sheets_table_after = []
488
+ for index, sheet_table in enumerate(data_group):
489
+ sheet_name, sheet_df = sheet_table
490
+ if group_field is not None:
491
+ del sheet_df[group_field]
492
+ if sheet_name in sheets_set:
493
+ sheet_set = sheets_set[sheet_name]
494
+ elif index in sheets_set:
495
+ sheet_set = sheets_set[index]
496
+ else:
497
+ sheets_table_after.append((sheet_name, sheet_df))
498
+ continue
499
+ if 'name' in sheet_set:
500
+ sheet_name = sheet_set['name']
501
+ if 'fields' in sheet_set:
502
+ sheet_df = sheet_df[sheet_set['fields']]
503
+ if 'index' in sheet_set:
504
+ sheets_table_before.append((sheet_set['index'], (sheet_name, sheet_df)))
505
+ else:
506
+ sheets_table_after.append((sheet_name, sheet_df))
507
+ sort_func = lambda item: item[0]
508
+ sheets_table_before.sort(key=sort_func)
509
+ sheets_table = [sheet_table for sheet_index, sheet_table in sheets_table_before] + sheets_table_after
510
+
511
+ # Save file.
512
+ excel = ExcelWriter(path)
513
+ for sheet_name, sheet_df in sheets_table:
514
+ sheet_df.to_excel(excel, sheet_name, index=False)
515
+ excel.close()
516
+
517
+ return path