pyfastexcel 0.1.8__py3-none-win_amd64.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.
@@ -0,0 +1,573 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal, Optional, overload, List
4
+
5
+ from pyfastexcel.driver import ExcelDriver, WorkSheet
6
+ from pyfastexcel.utils import deprecated_warning
7
+
8
+ from pydantic import validate_call as pydantic_validate_call
9
+
10
+ from .chart import (
11
+ Chart,
12
+ ChartSeries,
13
+ GraphicOptions,
14
+ RichTextRun,
15
+ ChartLegend,
16
+ ChartAxis,
17
+ ChartPlotArea,
18
+ Fill,
19
+ Line,
20
+ ChartDimension,
21
+ )
22
+ from .pivot import PivotTable, PivotTableField
23
+ from ._typing import CommentTextStructure, SetPanesSelection
24
+ from .utils import CommentText, Selection
25
+
26
+
27
+ class Workbook(ExcelDriver):
28
+ """
29
+ A base class for writing data to Excel files with custom styles.
30
+
31
+ This class provides methods to set file properties, cell dimensions,
32
+ merge cells, manipulate sheets, and more.
33
+
34
+ Methods:
35
+ remove_sheet(sheet: str) -> None:
36
+ Removes a sheet from the Excel data.
37
+ rename_sheet(self, old_sheet_name: str, new_sheet_name: str) -> None:
38
+ Rename a sheet.
39
+ create_sheet(sheet_name: str) -> None:
40
+ Creates a new sheet.
41
+ switch_sheet(sheet_name: str) -> None:
42
+ Set current self.sheet to a different sheet.
43
+ set_file_props(key: str, value: str) -> None:
44
+ Sets a file property.
45
+ set_cell_width(sheet: str, col: str | int, value: int) -> None:
46
+ Sets the width of a cell.
47
+ set_cell_height(sheet: str, row: int, value: int) -> None:
48
+ Sets the height of a cell.
49
+ set_merge_cell(sheet: str, top_left_cell: str, bottom_right_cell: str) -> None:
50
+ Sets a merge cell range in the specified sheet.
51
+ """
52
+
53
+ def remove_sheet(self, sheet: str) -> None:
54
+ """
55
+ Removes a sheet from the Excel data.
56
+
57
+ Args:
58
+ sheet (str): The name of the sheet to remove.
59
+ """
60
+ if len(self.workbook) == 1:
61
+ raise ValueError('Cannot remove the only sheet in the workbook.')
62
+ if self.workbook.get(sheet) is None:
63
+ raise IndexError(f'Sheet {sheet} does not exist.')
64
+ self.workbook.pop(sheet)
65
+ self._sheet_list = tuple(self.workbook.keys())
66
+ self.sheet = self._sheet_list[0]
67
+
68
+ def rename_sheet(self, old_sheet_name: str, new_sheet_name: str) -> None:
69
+ """
70
+ Renames a sheet in the Excel data.
71
+
72
+ Args:
73
+ old_sheet_name (str): The name of the sheet to rename.
74
+ new_sheet_name (str): The new name for the sheet.
75
+ """
76
+ if self.workbook.get(old_sheet_name) is None:
77
+ raise IndexError(f'Sheet {old_sheet_name} does not exist.')
78
+ if self.workbook.get(new_sheet_name) is not None:
79
+ raise ValueError(f'Sheet {new_sheet_name} already exists.')
80
+ self.workbook[new_sheet_name] = self.workbook.pop(old_sheet_name)
81
+ self._sheet_list = tuple(
82
+ [new_sheet_name if x == old_sheet_name else x for x in self._sheet_list]
83
+ )
84
+ self.sheet = new_sheet_name
85
+
86
+ def create_sheet(
87
+ self,
88
+ sheet_name: str,
89
+ pre_allocate: dict[str, int] = None,
90
+ plain_data: list[list] = None,
91
+ ) -> None:
92
+ """
93
+ Creates a new sheet, and set it as current self.sheet.
94
+
95
+ Args:
96
+ sheet_name (str): The name of the new sheet.
97
+ pre_allocate (dict[str, int], optional): A dictionary containing
98
+ 'n_rows' and 'n_cols' keys specifying the dimensions
99
+ for pre-allocating data in new sheet.
100
+ plain_data (list[list[str]], optional): A 2D list of strings
101
+ representing initial data to populate new sheet.
102
+ """
103
+ if self.workbook.get(sheet_name) is not None:
104
+ raise ValueError(f'Sheet {sheet_name} already exists.')
105
+ self.workbook[sheet_name] = WorkSheet(pre_allocate=pre_allocate, plain_data=plain_data)
106
+ self.sheet = sheet_name
107
+ self._sheet_list = tuple([x for x in self._sheet_list] + [sheet_name])
108
+
109
+ def switch_sheet(self, sheet_name: str) -> None:
110
+ """
111
+ Set current self.sheet to a different sheet. If sheet does not existed
112
+ then raise error.
113
+
114
+ Args:
115
+ sheet_name (str): The name of the sheet to switch to.
116
+
117
+ Raises:
118
+ IndexError: If sheet does not exist.
119
+ """
120
+ self._check_if_sheet_exists(sheet_name)
121
+ self.sheet = sheet_name
122
+
123
+ @pydantic_validate_call
124
+ def set_file_props(self, key: str, value: str) -> None:
125
+ """
126
+ Sets a file property.
127
+
128
+ Args:
129
+ key (str): The property key.
130
+ value (str): The property value.
131
+
132
+ Raises:
133
+ ValueError: If the key is invalid.
134
+ """
135
+ if key not in self._FILE_PROPS:
136
+ raise ValueError(f'Invalid file property: {key}')
137
+ self.file_props[key] = value
138
+
139
+ @pydantic_validate_call
140
+ def protect_workbook(
141
+ self,
142
+ algorithm: str,
143
+ password: str,
144
+ lock_structure: bool = False,
145
+ lock_windows: bool = False,
146
+ ):
147
+ if algorithm not in self._PROTECT_ALGORITHM:
148
+ raise ValueError(
149
+ f'Invalid algorithm, the options are {self._PROTECT_ALGORITHM}',
150
+ )
151
+ self.protection['algorithm'] = algorithm
152
+ self.protection['password'] = password
153
+ self.protection['lock_structure'] = lock_structure
154
+ self.protection['lock_windows'] = lock_windows
155
+
156
+ def set_cell_width(self, sheet: str, col: str | int, value: int) -> None:
157
+ self._check_if_sheet_exists(sheet)
158
+ self.workbook[sheet].set_cell_width(col, value)
159
+
160
+ def set_cell_height(self, sheet: str, row: int, value: int) -> None:
161
+ self._check_if_sheet_exists(sheet)
162
+ self.workbook[sheet].set_cell_height(row, value)
163
+
164
+ @overload
165
+ def set_merge_cell(
166
+ self,
167
+ sheet: str,
168
+ top_lef_cell: Optional[str],
169
+ bottom_right_cell: Optional[str],
170
+ ) -> None: ...
171
+
172
+ @overload
173
+ def set_merge_cell(
174
+ self,
175
+ sheet: str,
176
+ cell_range: Optional[str],
177
+ ) -> None: ...
178
+
179
+ def set_merge_cell(self, sheet, *args) -> None:
180
+ deprecated_warning(
181
+ "wb.set_merge_cell is going to deprecated in v1.0.0. Please use 'wb.merge_cell' instead",
182
+ )
183
+ self.merge_cell(sheet, *args)
184
+
185
+ @overload
186
+ def merge_cell(
187
+ self,
188
+ sheet: str,
189
+ top_lef_cell: Optional[str],
190
+ bottom_right_cell: Optional[str],
191
+ ) -> None: ...
192
+
193
+ @overload
194
+ def merge_cell(
195
+ self,
196
+ sheet: str,
197
+ cell_range: Optional[str],
198
+ ) -> None: ...
199
+
200
+ def merge_cell(self, sheet: str, *args) -> None:
201
+ self._check_if_sheet_exists(sheet)
202
+ self.workbook[sheet].set_merge_cell(*args)
203
+
204
+ def auto_filter(self, sheet: str, target_range: str) -> None:
205
+ self._check_if_sheet_exists(sheet)
206
+ self.workbook[sheet].auto_filter(target_range)
207
+
208
+ def set_panes(
209
+ self,
210
+ sheet: str,
211
+ freeze: bool = False,
212
+ split: bool = False,
213
+ x_split: int = 0,
214
+ y_split: int = 0,
215
+ top_left_cell: str = '',
216
+ active_pane: Literal['bottomLeft', 'bottomRight', 'topLeft', 'topRight', ''] = '',
217
+ selection: Optional[SetPanesSelection | list[Selection] | Selection] = None,
218
+ ) -> None:
219
+ """
220
+ Sets the panes for the worksheet with options for freezing, splitting, and selection.
221
+
222
+ Args:
223
+ sheet (str): The name of the sheet.
224
+ freeze (bool): Whether to freeze the panes.
225
+ split (bool): Whether to split the panes.
226
+ x_split (int): The column position to split or freeze.
227
+ y_split (int): The row position to split or freeze.
228
+ top_left_cell (str): The top-left cell in the split or frozen panes.
229
+ active_pane (Literal['bottomLeft', 'bottomRight', 'topLeft', 'topRight', '']):
230
+ The active pane.
231
+ selection (Optional[SetPanesSelection | list[Selection]]): The selection
232
+ details for the panes.
233
+
234
+ Raises:
235
+ ValueError: If x_split or y_split is negative, or if active_pane is
236
+ invalid.
237
+
238
+ Returns:
239
+ None
240
+ """
241
+ self._check_if_sheet_exists(sheet)
242
+ self.workbook[sheet].set_panes(
243
+ freeze=freeze,
244
+ split=split,
245
+ x_split=x_split,
246
+ y_split=y_split,
247
+ top_left_cell=top_left_cell,
248
+ active_pane=active_pane,
249
+ selection=selection,
250
+ )
251
+
252
+ def set_data_validation(
253
+ self,
254
+ sheet: str,
255
+ sq_ref: str = '',
256
+ set_range: Optional[list[int | float]] = None,
257
+ input_msg: Optional[list[str]] = None,
258
+ drop_list: Optional[list[str | int | float] | str] = None,
259
+ error_msg: Optional[list[str]] = None,
260
+ ):
261
+ """
262
+ Set data validation for the specified range.
263
+
264
+ Args:
265
+ sheet (str): The name of the sheet.
266
+ sq_ref (str): The range to set the data validation.
267
+ set_range (list[int | float]): The range of values to set the data validation.
268
+ input (list[str]): The input message for the data validation.
269
+ drop_list (list[str] | str): The drop list for the data validation.
270
+ error (list[str]): The error message for the data validation.
271
+
272
+ Raises:
273
+ ValueError: If the range is invalid.
274
+
275
+ Returns:
276
+ None
277
+ """
278
+ self._check_if_sheet_exists(sheet)
279
+ self.workbook[sheet].set_data_validation(
280
+ sq_ref=sq_ref,
281
+ set_range=set_range,
282
+ input_msg=input_msg,
283
+ drop_list=drop_list,
284
+ error_msg=error_msg,
285
+ )
286
+
287
+ def add_comment(
288
+ self,
289
+ sheet: str,
290
+ cell: str,
291
+ author: str,
292
+ text: CommentTextStructure | CommentText | List[CommentText],
293
+ ) -> None:
294
+ """
295
+ Adds a comment to the specified cell.
296
+ Args:
297
+ sheet (str): The name of the sheet.
298
+ cell (str): The cell location to add the comment.
299
+ author (str): The author of the comment.
300
+ text (str | dict[str, str] | list[str | dict[str, str]]): The text of the comment.
301
+ Raises:
302
+ ValueError: If the cell location is invalid.
303
+ Returns:
304
+ None
305
+ """
306
+ self._check_if_sheet_exists(sheet)
307
+ self.workbook[sheet].add_comment(cell, author, text)
308
+
309
+ def group_columns(
310
+ self,
311
+ sheet: str,
312
+ start_col: str,
313
+ end_col: Optional[str] = None,
314
+ outline_level: int = 1,
315
+ hidden: bool = False,
316
+ engine: Literal['pyfastexcel', 'openpyxl'] = 'pyfastexcel',
317
+ ):
318
+ """
319
+ Groups columns between start_col and end_col with specified outline
320
+ level and visibility.
321
+
322
+ Args:
323
+ sheet (str): The name of the sheet.
324
+ start_col (str): The starting column to group.
325
+ end_col (Optional[str]): The ending column to group. If None, only
326
+ start_col will be grouped.
327
+ outline_level (int): The outline level of the group.
328
+ hidden (bool): Whether the grouped columns should be hidden.
329
+ engine (Literal['pyfastexcel', 'openpyxl']): The engine to use for
330
+ grouping.
331
+
332
+ Returns:
333
+ None
334
+ """
335
+ self._check_if_sheet_exists(sheet)
336
+ self.workbook[sheet].group_columns(
337
+ start_col,
338
+ end_col,
339
+ outline_level,
340
+ hidden,
341
+ engine,
342
+ )
343
+
344
+ def group_rows(
345
+ self,
346
+ sheet: str,
347
+ start_row: int,
348
+ end_row: Optional[int] = None,
349
+ outline_level: int = 1,
350
+ hidden: bool = False,
351
+ engine: Literal['pyfastexcel', 'openpyxl'] = 'pyfastexcel',
352
+ ):
353
+ """
354
+ Groups rows between start_row and end_row with specified outline level
355
+ and visibility.
356
+
357
+ Args:
358
+ sheet (str): The name of the sheet.
359
+ start_row (int): The starting row to group.
360
+ end_row (Optional[int]): The ending row to group. If None,
361
+ only start_row will be grouped.
362
+ outline_level (int): The outline level of the group.
363
+ hidden (bool): Whether the grouped rows should be hidden.
364
+ engine (Literal['pyfastexcel', 'openpyxl']): The engine to use for
365
+ grouping.
366
+
367
+ Returns:
368
+ None
369
+ """
370
+ self._check_if_sheet_exists(sheet)
371
+ self.workbook[sheet].group_rows(
372
+ start_row,
373
+ end_row,
374
+ outline_level,
375
+ hidden,
376
+ engine,
377
+ )
378
+
379
+ def create_table(
380
+ self,
381
+ sheet: str,
382
+ cell_range: str,
383
+ name: str,
384
+ style_name: str = '',
385
+ show_first_column: bool = True,
386
+ show_last_column: bool = True,
387
+ show_row_stripes: bool = False,
388
+ show_column_stripes: bool = True,
389
+ validate_table: bool = True,
390
+ ):
391
+ """
392
+ Creates a table within the specified cell range with given style and display options.
393
+
394
+ Args:
395
+ sheet (str): The name of the sheet.
396
+ cell_range (str): The cell range where the table should be created (e.g., 'A1:D10').
397
+ name (str): The name of the table.
398
+ style_name (str): The style to apply to the table. Defaults to an empty string, which
399
+ applies the default style.
400
+ show_first_column (bool): Whether to emphasize the first column.
401
+ show_last_column (bool): Whether to emphasize the last column.
402
+ show_row_stripes (bool): Whether to show row stripes for alternate row shading.
403
+ show_column_stripes (bool): Whether to show column stripes for alternate column shading.
404
+ validate_table (bool): Whether to validate the table through TableFinalValidation.
405
+
406
+ Returns:
407
+ None
408
+ """
409
+ self._check_if_sheet_exists(sheet)
410
+ self.workbook[self.sheet].create_table(
411
+ cell_range,
412
+ name,
413
+ style_name,
414
+ show_first_column,
415
+ show_last_column,
416
+ show_row_stripes,
417
+ show_column_stripes,
418
+ validate_table,
419
+ )
420
+
421
+ @overload
422
+ def add_chart(self, sheet: str, cell: str, chart_model: Chart | List[Chart]): ...
423
+
424
+ @overload
425
+ def add_chart(
426
+ self,
427
+ sheet: str,
428
+ cell: str,
429
+ chart_type: str,
430
+ series: List[ChartSeries] | ChartSeries,
431
+ graph_format: Optional[GraphicOptions] = None,
432
+ title: Optional[List[RichTextRun]] = None,
433
+ legend: Optional[ChartLegend] = None,
434
+ dimension: Optional[ChartDimension] = None,
435
+ vary_colors: Optional[bool] = None,
436
+ x_axis: Optional[ChartAxis] = None,
437
+ y_axis: Optional[ChartAxis] = None,
438
+ plot_area: Optional[ChartPlotArea] = None,
439
+ fill: Optional[Fill] = None,
440
+ border: Optional[Line] = None,
441
+ show_blanks_as: Optional[str] = None,
442
+ bubble_size: Optional[int] = None,
443
+ hole_size: Optional[int] = None,
444
+ order: Optional[int] = None,
445
+ ): ...
446
+
447
+ def add_chart(
448
+ self,
449
+ sheet: str,
450
+ cell: str,
451
+ chart_model: Optional[List[Chart] | Chart] = None,
452
+ chart_type: Optional[str] = None,
453
+ series: Optional[List[ChartSeries] | ChartSeries] = None,
454
+ graph_format: Optional[GraphicOptions] = None,
455
+ title: Optional[List[RichTextRun]] = None,
456
+ legend: Optional[ChartLegend] = None,
457
+ dimension: Optional[ChartDimension] = None,
458
+ vary_colors: Optional[bool] = None,
459
+ x_axis: Optional[ChartAxis] = None,
460
+ y_axis: Optional[ChartAxis] = None,
461
+ plot_area: Optional[ChartPlotArea] = None,
462
+ fill: Optional[Fill] = None,
463
+ border: Optional[Line] = None,
464
+ show_blanks_as: Optional[str] = None,
465
+ bubble_size: Optional[int] = None,
466
+ hole_size: Optional[int] = None,
467
+ order: Optional[int] = None,
468
+ ):
469
+ self._check_if_sheet_exists(sheet)
470
+ if isinstance(chart_model, list):
471
+ self.workbook[sheet].add_chart(cell, chart_model)
472
+ else:
473
+ self.workbook[sheet].add_chart(
474
+ cell,
475
+ chart_model,
476
+ chart_type,
477
+ series,
478
+ graph_format,
479
+ title,
480
+ legend,
481
+ dimension,
482
+ vary_colors,
483
+ x_axis,
484
+ y_axis,
485
+ plot_area,
486
+ fill,
487
+ border,
488
+ show_blanks_as,
489
+ bubble_size,
490
+ hole_size,
491
+ order,
492
+ )
493
+
494
+ @overload
495
+ def add_pivot_table(self, sheet: str, pivot_table: PivotTable | list[PivotTable]) -> None: ...
496
+
497
+ @overload
498
+ def add_pivot_table(
499
+ self,
500
+ sheet: str,
501
+ data_range: str,
502
+ pivot_table_range: str,
503
+ rows: list[PivotTableField],
504
+ pivot_filter: list[PivotTableField],
505
+ columns: list[PivotTableField],
506
+ data: list[PivotTableField],
507
+ row_grand_totals: Optional[bool],
508
+ column_grand_totals: Optional[bool],
509
+ show_drill: Optional[bool],
510
+ show_row_headers: Optional[bool],
511
+ show_column_headers: Optional[bool],
512
+ show_row_stripes: Optional[bool],
513
+ show_col_stripes: Optional[bool],
514
+ show_last_column: Optional[bool],
515
+ use_auto_formatting: Optional[bool],
516
+ page_over_then_down: Optional[bool],
517
+ merge_item: Optional[bool],
518
+ compact_data: Optional[bool],
519
+ show_error: Optional[bool],
520
+ pivot_table_style_name: Optional[str],
521
+ ) -> None: ...
522
+
523
+ def add_pivot_table(
524
+ self,
525
+ sheet: str,
526
+ pivot_table: Optional[PivotTable | list[PivotTable]] = None,
527
+ data_range: Optional[str] = None,
528
+ pivot_table_range: Optional[str] = None,
529
+ rows: Optional[list[PivotTableField]] = None,
530
+ pivot_filter: Optional[list[PivotTableField]] = None,
531
+ columns: Optional[list[PivotTableField]] = None,
532
+ data: Optional[list[PivotTableField]] = None,
533
+ row_grand_totals: Optional[bool] = None,
534
+ column_grand_totals: Optional[bool] = None,
535
+ show_drill: Optional[bool] = None,
536
+ show_row_headers: Optional[bool] = None,
537
+ show_column_headers: Optional[bool] = None,
538
+ show_row_stripes: Optional[bool] = None,
539
+ show_col_stripes: Optional[bool] = None,
540
+ show_last_column: Optional[bool] = None,
541
+ use_auto_formatting: Optional[bool] = None,
542
+ page_over_then_down: Optional[bool] = None,
543
+ merge_item: Optional[bool] = None,
544
+ compact_data: Optional[bool] = None,
545
+ show_error: Optional[bool] = None,
546
+ pivot_table_style_name: Optional[str] = None,
547
+ ) -> None:
548
+ self._check_if_sheet_exists(sheet)
549
+ if isinstance(pivot_table, list) or isinstance(pivot_table, PivotTable):
550
+ self.workbook[sheet].add_pivot_table(pivot_table)
551
+ else:
552
+ self.workbook[sheet].add_pivot_table(
553
+ data_range=data_range,
554
+ pivot_table_range=pivot_table_range,
555
+ rows=rows,
556
+ pivot_filter=pivot_filter,
557
+ columns=columns,
558
+ data=data,
559
+ row_grand_totals=row_grand_totals,
560
+ column_grand_totals=column_grand_totals,
561
+ show_drill=show_drill,
562
+ show_row_headers=show_row_headers,
563
+ show_column_headers=show_column_headers,
564
+ show_row_stripes=show_row_stripes,
565
+ show_col_stripes=show_col_stripes,
566
+ show_last_column=show_last_column,
567
+ use_auto_formatting=use_auto_formatting,
568
+ page_over_then_down=page_over_then_down,
569
+ merge_item=merge_item,
570
+ compact_data=compact_data,
571
+ show_error=show_error,
572
+ pivot_table_style_name=pivot_table_style_name,
573
+ )