pyfastexcel 0.0.7__tar.gz → 0.0.9__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.
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/PKG-INFO +15 -4
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/README.md +14 -3
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel/__init__.py +3 -3
- pyfastexcel-0.0.9/pyfastexcel/_typing.py +25 -0
- pyfastexcel-0.0.9/pyfastexcel/driver.py +192 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel/pyfastexcel.dll +0 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel/pyfastexcel.so +0 -0
- pyfastexcel-0.0.9/pyfastexcel/style.py +198 -0
- pyfastexcel-0.0.9/pyfastexcel/utils.py +177 -0
- pyfastexcel-0.0.9/pyfastexcel/workbook.py +198 -0
- pyfastexcel-0.0.9/pyfastexcel/worksheet.py +627 -0
- pyfastexcel-0.0.9/pyfastexcel/writer.py +60 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel.egg-info/PKG-INFO +15 -4
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel.egg-info/SOURCES.txt +4 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/setup.cfg +1 -1
- pyfastexcel-0.0.7/pyfastexcel/driver.py +0 -717
- pyfastexcel-0.0.7/pyfastexcel/utils.py +0 -92
- pyfastexcel-0.0.7/pyfastexcel/writer.py +0 -263
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/LICENSE +0 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel.egg-info/dependency_links.txt +0 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel.egg-info/not-zip-safe +0 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel.egg-info/requires.txt +0 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/pyfastexcel.egg-info/top_level.txt +0 -0
- {pyfastexcel-0.0.7 → pyfastexcel-0.0.9}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: pyfastexcel
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary: High performace excel file generation library.
|
|
5
5
|
Home-page: https://github.com/Zncl2222/pyfastexcel
|
|
6
6
|
Author: Zncl2222
|
|
@@ -100,7 +100,7 @@ If you prefer to build the package manually, follow these steps:
|
|
|
100
100
|
|
|
101
101
|
## Usage
|
|
102
102
|
|
|
103
|
-
The index assignment is now avaliable in `Workbook` and the `
|
|
103
|
+
The index assignment is now avaliable in `Workbook` and the `StreamWriter`.
|
|
104
104
|
Here is the example usage:
|
|
105
105
|
|
|
106
106
|
```python
|
|
@@ -146,8 +146,8 @@ if __name__ == '__main__':
|
|
|
146
146
|
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
You can also using the `
|
|
150
|
-
subclass of `Workbook` to write excel row by row, see
|
|
149
|
+
You can also using the `StreamWriter` which was the
|
|
150
|
+
subclass of `Workbook` to write excel row by row, see more in [StreamWriter](https://pyfastexcel.readthedocs.io/en/stable/writer/).
|
|
151
151
|
|
|
152
152
|
## Documentation
|
|
153
153
|
|
|
@@ -157,6 +157,17 @@ The documentation is hosted on Read the Docs.
|
|
|
157
157
|
|
|
158
158
|
- [Latest Stable Version](https://pyfastexcel.readthedocs.io/en/stable/)
|
|
159
159
|
|
|
160
|
+
## Benchmark
|
|
161
|
+
|
|
162
|
+
The following result displays the performance comparison between
|
|
163
|
+
`pyfastexcel` and `openpyxl` for writing 50000 rows with 30
|
|
164
|
+
columns (Total 1500000 cells). To see more benchmark results, please
|
|
165
|
+
see the [benchmark](https://pyfastexcel.readthedocs.io/en/stable/benchmark/).
|
|
166
|
+
|
|
167
|
+
<dev align='center'>
|
|
168
|
+
<img src='./docs/images/50000_30_horizontal_Windows11.png' width="80%" height="45%" >
|
|
169
|
+
</dev>
|
|
170
|
+
|
|
160
171
|
## How it Works
|
|
161
172
|
|
|
162
173
|
The core functionality revolves around encoding Excel cell data and styles,
|
|
@@ -76,7 +76,7 @@ If you prefer to build the package manually, follow these steps:
|
|
|
76
76
|
|
|
77
77
|
## Usage
|
|
78
78
|
|
|
79
|
-
The index assignment is now avaliable in `Workbook` and the `
|
|
79
|
+
The index assignment is now avaliable in `Workbook` and the `StreamWriter`.
|
|
80
80
|
Here is the example usage:
|
|
81
81
|
|
|
82
82
|
```python
|
|
@@ -122,8 +122,8 @@ if __name__ == '__main__':
|
|
|
122
122
|
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
You can also using the `
|
|
126
|
-
subclass of `Workbook` to write excel row by row, see
|
|
125
|
+
You can also using the `StreamWriter` which was the
|
|
126
|
+
subclass of `Workbook` to write excel row by row, see more in [StreamWriter](https://pyfastexcel.readthedocs.io/en/stable/writer/).
|
|
127
127
|
|
|
128
128
|
## Documentation
|
|
129
129
|
|
|
@@ -133,6 +133,17 @@ The documentation is hosted on Read the Docs.
|
|
|
133
133
|
|
|
134
134
|
- [Latest Stable Version](https://pyfastexcel.readthedocs.io/en/stable/)
|
|
135
135
|
|
|
136
|
+
## Benchmark
|
|
137
|
+
|
|
138
|
+
The following result displays the performance comparison between
|
|
139
|
+
`pyfastexcel` and `openpyxl` for writing 50000 rows with 30
|
|
140
|
+
columns (Total 1500000 cells). To see more benchmark results, please
|
|
141
|
+
see the [benchmark](https://pyfastexcel.readthedocs.io/en/stable/benchmark/).
|
|
142
|
+
|
|
143
|
+
<dev align='center'>
|
|
144
|
+
<img src='./docs/images/50000_30_horizontal_Windows11.png' width="80%" height="45%" >
|
|
145
|
+
</dev>
|
|
146
|
+
|
|
136
147
|
## How it Works
|
|
137
148
|
|
|
138
149
|
The core functionality revolves around encoding Excel cell data and styles,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
from openpyxl_style_writer import CustomStyle, DefaultStyle
|
|
2
2
|
|
|
3
|
-
from pyfastexcel.
|
|
3
|
+
from pyfastexcel.workbook import Workbook
|
|
4
|
+
from pyfastexcel.writer import StreamWriter
|
|
4
5
|
|
|
5
6
|
__all__ = [
|
|
6
7
|
'Workbook',
|
|
7
|
-
'
|
|
8
|
-
'NormalWriter',
|
|
8
|
+
'StreamWriter',
|
|
9
9
|
# Temporary link the CustomStyle from openpyxl_style_writer for
|
|
10
10
|
# convinent usage.
|
|
11
11
|
'CustomStyle',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal, TypedDict, Optional, List, Union
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CommentTextDict(TypedDict, total=False):
|
|
7
|
+
text: str
|
|
8
|
+
size: Optional[int]
|
|
9
|
+
name: Optional[str]
|
|
10
|
+
bold: Optional[bool]
|
|
11
|
+
italic: Optional[bool]
|
|
12
|
+
underline: Optional[Literal['single', 'double']]
|
|
13
|
+
strike: Optional[bool]
|
|
14
|
+
vert_align: Optional[str]
|
|
15
|
+
color: Optional[str]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SelectionDict(TypedDict, total=False):
|
|
19
|
+
sq_ref: str
|
|
20
|
+
active_cell: str
|
|
21
|
+
pane: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
CommentTextStructure = Union[str, List[str], CommentTextDict, List[CommentTextDict]]
|
|
25
|
+
SetPanesSelection = List[SelectionDict]
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import ctypes
|
|
5
|
+
import sys
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import msgspec
|
|
10
|
+
from openpyxl_style_writer import CustomStyle
|
|
11
|
+
|
|
12
|
+
from .style import StyleManager
|
|
13
|
+
from .worksheet import WorkSheet
|
|
14
|
+
|
|
15
|
+
BASE_DIR = Path(__file__).resolve().parent
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ExcelDriver:
|
|
19
|
+
"""
|
|
20
|
+
A driver class to write data to Excel files using custom styles.
|
|
21
|
+
|
|
22
|
+
### Attributes:
|
|
23
|
+
_FILE_PROPS (dict[str, str]): Default file properties for the Excel
|
|
24
|
+
file.
|
|
25
|
+
_PROTECT_ALGORITHM (tuple[str]): Algorithm for the workbook protection
|
|
26
|
+
|
|
27
|
+
### Methods:
|
|
28
|
+
__init__(): Initializes the ExcelDriver.
|
|
29
|
+
_read_lib(lib_path: str): Reads a library for Excel manipulation.
|
|
30
|
+
read_lib_and_create_excel(lib_path: str = None): Reads the library and
|
|
31
|
+
creates the Excel file.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
_FILE_PROPS = {
|
|
35
|
+
'Category': '',
|
|
36
|
+
'ContentStatus': '',
|
|
37
|
+
'Created': '',
|
|
38
|
+
'Creator': 'pyfastexcel',
|
|
39
|
+
'Description': '',
|
|
40
|
+
'Identifier': 'xlsx',
|
|
41
|
+
'Keywords': 'spreadsheet',
|
|
42
|
+
'LastModifiedBy': 'pyfastexcel',
|
|
43
|
+
'Modified': '',
|
|
44
|
+
'Revision': '0',
|
|
45
|
+
'Subject': '',
|
|
46
|
+
'Title': '',
|
|
47
|
+
'Language': 'en-Us',
|
|
48
|
+
'Version': '',
|
|
49
|
+
}
|
|
50
|
+
_PROTECT_ALGORITHM = (
|
|
51
|
+
'XOR',
|
|
52
|
+
'MD4',
|
|
53
|
+
'MD5',
|
|
54
|
+
'SHA-1',
|
|
55
|
+
'SHA-256',
|
|
56
|
+
'SHA-384',
|
|
57
|
+
'SHA-512',
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def __init__(self, pre_allocate: dict[str, int] = None, plain_data: list[list[str]] = None):
|
|
61
|
+
"""
|
|
62
|
+
Initializes the Workbook with default settings and initializes Sheet1.
|
|
63
|
+
|
|
64
|
+
It initializes the workbook structure with Sheet1 as the default sheet,
|
|
65
|
+
sets default file properties, initializes current sheet and sheet list,
|
|
66
|
+
and initializes dictionaries for workbook and protection settings.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
pre_allocate (dict[str, int], optional): A dictionary containing 'n_rows' and 'n_cols'
|
|
70
|
+
keys specifying the dimensions for pre-allocating data in Sheet1.
|
|
71
|
+
plain_data (list[list[str]], optional): A 2D list of strings representing initial data
|
|
72
|
+
to populate Sheet1.
|
|
73
|
+
"""
|
|
74
|
+
self.workbook = {
|
|
75
|
+
'Sheet1': WorkSheet(pre_allocate=pre_allocate, plain_data=plain_data),
|
|
76
|
+
}
|
|
77
|
+
self.file_props = self._get_default_file_props()
|
|
78
|
+
self.sheet = 'Sheet1'
|
|
79
|
+
self._sheet_list = tuple(['Sheet1'])
|
|
80
|
+
self._dict_wb = {}
|
|
81
|
+
self.protection = {}
|
|
82
|
+
self.style = StyleManager()
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def sheet_list(self):
|
|
86
|
+
return self._sheet_list
|
|
87
|
+
|
|
88
|
+
def save(self, path: str = './pyfastexcel.xlsx') -> None:
|
|
89
|
+
if not hasattr(self, 'decoded_bytes'):
|
|
90
|
+
self.read_lib_and_create_excel()
|
|
91
|
+
|
|
92
|
+
with open(path, 'wb') as file:
|
|
93
|
+
file.write(self.decoded_bytes)
|
|
94
|
+
|
|
95
|
+
def __getitem__(self, key: str) -> WorkSheet:
|
|
96
|
+
return self.workbook[key]
|
|
97
|
+
|
|
98
|
+
def _check_if_sheet_exists(self, sheet_name: str) -> None:
|
|
99
|
+
if sheet_name not in self.sheet_list:
|
|
100
|
+
raise KeyError(f'{sheet_name} Sheet Does Not Exist.')
|
|
101
|
+
|
|
102
|
+
def read_lib_and_create_excel(self, lib_path: str = None) -> bytes:
|
|
103
|
+
"""
|
|
104
|
+
Reads the library and creates the Excel file.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
lib_path (str, optional): The path to the library. Defaults to None.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
bytes: The byte data of the created Excel file.
|
|
111
|
+
"""
|
|
112
|
+
pyfastexcel = self._read_lib(lib_path)
|
|
113
|
+
self._create_style()
|
|
114
|
+
|
|
115
|
+
# Transfer all WorkSheet Object to the sheet dictionary in the workbook.
|
|
116
|
+
for sheet in self._sheet_list:
|
|
117
|
+
self._dict_wb[sheet] = self.workbook[sheet]._transfer_to_dict()
|
|
118
|
+
|
|
119
|
+
results = {
|
|
120
|
+
'content': self._dict_wb,
|
|
121
|
+
'file_props': self.file_props,
|
|
122
|
+
'style': self.style._style_map,
|
|
123
|
+
'protection': self.protection,
|
|
124
|
+
}
|
|
125
|
+
json_data = msgspec.json.encode(results)
|
|
126
|
+
create_excel = pyfastexcel.Export
|
|
127
|
+
free_pointer = pyfastexcel.FreeCPointer
|
|
128
|
+
free_pointer.argtypes = [ctypes.c_void_p]
|
|
129
|
+
create_excel.argtypes = [ctypes.c_char_p]
|
|
130
|
+
create_excel.restype = ctypes.c_void_p
|
|
131
|
+
byte_data = create_excel(json_data)
|
|
132
|
+
self.decoded_bytes = base64.b64decode(ctypes.cast(byte_data, ctypes.c_char_p).value)
|
|
133
|
+
free_pointer(byte_data)
|
|
134
|
+
StyleManager.reset_style_configs()
|
|
135
|
+
return self.decoded_bytes
|
|
136
|
+
|
|
137
|
+
def _read_lib(self, lib_path: str) -> ctypes.CDLL:
|
|
138
|
+
"""
|
|
139
|
+
Reads a shared-library for writing Excel.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
lib_path (str): The path to the library.
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
ctypes.CDLL: The library object.
|
|
146
|
+
"""
|
|
147
|
+
if lib_path is None:
|
|
148
|
+
if sys.platform.startswith('linux'):
|
|
149
|
+
lib_path = str(list(BASE_DIR.glob('**/*.so'))[0])
|
|
150
|
+
elif sys.platform.startswith('win32'):
|
|
151
|
+
lib_path = str(list(BASE_DIR.glob('**/*.dll'))[0])
|
|
152
|
+
lib = ctypes.CDLL(lib_path, winmode=0)
|
|
153
|
+
return lib
|
|
154
|
+
|
|
155
|
+
def _get_default_file_props(self) -> dict[str, str]:
|
|
156
|
+
now = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
157
|
+
file_props = self._FILE_PROPS.copy()
|
|
158
|
+
file_props['Created'] = now
|
|
159
|
+
file_props['Modified'] = now
|
|
160
|
+
return file_props
|
|
161
|
+
|
|
162
|
+
def _get_style_collections(self) -> dict[str, CustomStyle]:
|
|
163
|
+
"""
|
|
164
|
+
Gets collections of custom styles.
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
dict[str, CustomStyle]: A dictionary containing custom style
|
|
168
|
+
collections.
|
|
169
|
+
"""
|
|
170
|
+
return {
|
|
171
|
+
attr: getattr(self, attr)
|
|
172
|
+
for attr in dir(self)
|
|
173
|
+
if not callable(getattr(self, attr)) and isinstance(getattr(self, attr), CustomStyle)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
def _create_style(self) -> None:
|
|
177
|
+
"""
|
|
178
|
+
Creates custom styles for the Excel file.
|
|
179
|
+
|
|
180
|
+
This method initializes custom styles for the Excel file based on
|
|
181
|
+
predefined attributes.
|
|
182
|
+
"""
|
|
183
|
+
style_collections = self._get_style_collections()
|
|
184
|
+
self.style._STYLE_NAME_MAP.update({val: key for key, val in style_collections.items()})
|
|
185
|
+
|
|
186
|
+
# Set the CustomStyle from the pre-defined class attributes.
|
|
187
|
+
for key, val in style_collections.items():
|
|
188
|
+
self.style._update_style_map(key, val)
|
|
189
|
+
|
|
190
|
+
# Set the CustomStyle from the REGISTERED method.
|
|
191
|
+
for key, val in self.style.REGISTERED_STYLES.items():
|
|
192
|
+
self.style._update_style_map(key, val)
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from openpyxl_style_writer import CustomStyle
|
|
8
|
+
|
|
9
|
+
BASE_DIR = Path(__file__).resolve().parent
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
logger.setLevel(logging.DEBUG)
|
|
13
|
+
|
|
14
|
+
ch = logging.StreamHandler()
|
|
15
|
+
ch.setLevel(logging.DEBUG)
|
|
16
|
+
|
|
17
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
18
|
+
ch.setFormatter(formatter)
|
|
19
|
+
|
|
20
|
+
if not logger.hasHandlers():
|
|
21
|
+
logger.addHandler(ch)
|
|
22
|
+
|
|
23
|
+
# TODO: Implement a CustomStyle without the dependency of openpyxl_style_writer
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class StyleManager:
|
|
27
|
+
"""
|
|
28
|
+
A class to set custom styles for Excel files.
|
|
29
|
+
|
|
30
|
+
### Attributes:
|
|
31
|
+
BORDER_TO_INDEX (dict[str, int]): Mapping of border styles to excelize's
|
|
32
|
+
corresponding index.
|
|
33
|
+
|
|
34
|
+
### Methods:
|
|
35
|
+
set_custom_style(cls, name: str, custom_style: CustomStyle): Set custom style
|
|
36
|
+
by register method.
|
|
37
|
+
_create_style(): Creates custom styles for the Excel file.
|
|
38
|
+
_get_style_collections(): Gets collections of custom styles.
|
|
39
|
+
_get_default_style(): Gets the default style.
|
|
40
|
+
_update_style_map(style_name: str, custom_style: CustomStyle): Updates
|
|
41
|
+
the style map.
|
|
42
|
+
_get_font_style(style: CustomStyle): Gets the font style.
|
|
43
|
+
_get_fill_style(style: CustomStyle): Gets the fill style.
|
|
44
|
+
_get_border_style(style: CustomStyle): Gets the border style.
|
|
45
|
+
_get_alignment_style(style: CustomStyle): Gets the alignment style.
|
|
46
|
+
_get_protection_style(style: CustomStyle): Gets the protection style.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
BORDER_TO_INDEX = {
|
|
50
|
+
None: 0,
|
|
51
|
+
'thick': 5,
|
|
52
|
+
'slantDashDot': 13,
|
|
53
|
+
'dotted': 4,
|
|
54
|
+
'hair': 7,
|
|
55
|
+
'dashed': 3,
|
|
56
|
+
'double': 6,
|
|
57
|
+
'mediumDashDotDot': 12,
|
|
58
|
+
'medium': 2,
|
|
59
|
+
'dashDotDot': 11,
|
|
60
|
+
'thin': 1,
|
|
61
|
+
'dashDot': 9,
|
|
62
|
+
'mediumDashed': 8,
|
|
63
|
+
'mediumDashDot': 10,
|
|
64
|
+
}
|
|
65
|
+
# The style retrieved from set_custom_style will be stored in
|
|
66
|
+
# REGISTERED_STYLES temporarily. It will be created after any
|
|
67
|
+
# Writer is initialized and calls the self._create_style() method.
|
|
68
|
+
DEFAULT_STYLE = CustomStyle()
|
|
69
|
+
REGISTERED_STYLES = {'DEFAULT_STYLE': DEFAULT_STYLE}
|
|
70
|
+
_STYLE_NAME_MAP = {}
|
|
71
|
+
_STYLE_ID = 0
|
|
72
|
+
# The shared memory in the parent class that stores every CustomStyle
|
|
73
|
+
# from different Writer classes.
|
|
74
|
+
_style_map = {}
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def set_custom_style(cls, name: str, custom_style: CustomStyle):
|
|
78
|
+
cls.REGISTERED_STYLES[name] = custom_style
|
|
79
|
+
cls._STYLE_NAME_MAP[custom_style] = name
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def reset_style_configs(cls):
|
|
83
|
+
cls.REGISTERED_STYLES = {'DEFAULT_STYLE': cls.DEFAULT_STYLE}
|
|
84
|
+
cls._STYLE_NAME_MAP = {}
|
|
85
|
+
cls._STYLE_ID = 0
|
|
86
|
+
cls._style_map = {}
|
|
87
|
+
|
|
88
|
+
def _get_default_style(self) -> dict[str, dict[str, Any] | str]:
|
|
89
|
+
"""
|
|
90
|
+
Gets the default style.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
dict[str, dict[str, Any] | str]: A dictionary containing the
|
|
94
|
+
default style settings.
|
|
95
|
+
"""
|
|
96
|
+
return {
|
|
97
|
+
'Font': {},
|
|
98
|
+
'Fill': {},
|
|
99
|
+
'Border': {},
|
|
100
|
+
'Alignment': {},
|
|
101
|
+
'Protection': {},
|
|
102
|
+
'CustomNumFmt': 'general',
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def _update_style_map(self, style_name: str, custom_style: CustomStyle) -> None:
|
|
106
|
+
if self._style_map.get(style_name):
|
|
107
|
+
logger.warning(f'{style_name} has already existed. Overiding the style settings.')
|
|
108
|
+
self._style_map[style_name] = self._get_default_style()
|
|
109
|
+
self._style_map[style_name]['Font'] = self._get_font_style(custom_style)
|
|
110
|
+
self._style_map[style_name]['Fill'] = self._get_fill_style(custom_style)
|
|
111
|
+
self._style_map[style_name]['Border'] = self._get_border_style(custom_style)
|
|
112
|
+
self._style_map[style_name]['Alignment'] = self._get_alignment_style(custom_style)
|
|
113
|
+
self._style_map[style_name]['Protection'] = self._get_protection_style(custom_style)
|
|
114
|
+
self._style_map[style_name]['CustomNumFmt'] = custom_style.number_format
|
|
115
|
+
|
|
116
|
+
def _get_font_style(self, style: CustomStyle) -> dict[str, str | int | bool | None]:
|
|
117
|
+
font_style_map = {}
|
|
118
|
+
if style.font.name:
|
|
119
|
+
font_style_map['Family'] = style.font.name
|
|
120
|
+
if style.font.sz:
|
|
121
|
+
font_style_map['Size'] = style.font.sz
|
|
122
|
+
if style.font.b:
|
|
123
|
+
font_style_map['Bold'] = style.font.b
|
|
124
|
+
if style.font.i:
|
|
125
|
+
font_style_map['Italic'] = style.font.i
|
|
126
|
+
if style.font.strike:
|
|
127
|
+
font_style_map['Strike'] = style.font.strike
|
|
128
|
+
if style.font.u:
|
|
129
|
+
font_style_map['UnderLine'] = style.font.u
|
|
130
|
+
if style.font.color.rgb:
|
|
131
|
+
font_style_map['Color'] = f'#{style.font.color.rgb[2:]}'
|
|
132
|
+
return font_style_map
|
|
133
|
+
|
|
134
|
+
def _get_fill_style(self, style: CustomStyle) -> dict[str, str]:
|
|
135
|
+
fill_style_map = {}
|
|
136
|
+
if style.fill.fgColor.rgb:
|
|
137
|
+
fill_style_map['Color'] = f'#{style.fill.fgColor.rgb[2:]}'
|
|
138
|
+
fill_style_map['Type'] = 'pattern'
|
|
139
|
+
fill_style_map['Pattern'] = 1
|
|
140
|
+
return fill_style_map
|
|
141
|
+
|
|
142
|
+
def _get_border_style(self, style: CustomStyle) -> dict[str, str]:
|
|
143
|
+
border_style_map = {}
|
|
144
|
+
direction = ['left', 'right', 'top', 'bottom']
|
|
145
|
+
|
|
146
|
+
for d in direction:
|
|
147
|
+
border_style_map[d] = {}
|
|
148
|
+
|
|
149
|
+
if style.border.left.style:
|
|
150
|
+
border_style_map['left']['Style'] = self.BORDER_TO_INDEX[style.border.left.style]
|
|
151
|
+
if style.border.right.style:
|
|
152
|
+
border_style_map['right']['Style'] = self.BORDER_TO_INDEX[style.border.right.style]
|
|
153
|
+
if style.border.top.style:
|
|
154
|
+
border_style_map['top']['Style'] = self.BORDER_TO_INDEX[style.border.top.style]
|
|
155
|
+
if style.border.bottom.style:
|
|
156
|
+
border_style_map['bottom']['Style'] = self.BORDER_TO_INDEX[style.border.bottom.style]
|
|
157
|
+
|
|
158
|
+
if style.border.left.color.rgb:
|
|
159
|
+
border_style_map['left']['Color'] = f'#{style.border.left.color.rgb[2:]}'
|
|
160
|
+
if style.border.right.color.rgb:
|
|
161
|
+
border_style_map['right']['Color'] = f'#{style.border.right.color.rgb[2:]}'
|
|
162
|
+
if style.border.top.color.rgb:
|
|
163
|
+
border_style_map['top']['Color'] = f'#{style.border.top.color.rgb[2:]}'
|
|
164
|
+
if style.border.bottom.color.rgb:
|
|
165
|
+
border_style_map['bottom']['Color'] = f'#{style.border.bottom.color.rgb[2:]}'
|
|
166
|
+
return border_style_map
|
|
167
|
+
|
|
168
|
+
def _get_alignment_style(self, style: CustomStyle) -> dict[str, str]:
|
|
169
|
+
ali_style_map = {}
|
|
170
|
+
|
|
171
|
+
if style.ali.horizontal:
|
|
172
|
+
ali_style_map['Horizontal'] = style.ali.horizontal
|
|
173
|
+
if style.ali.vertical:
|
|
174
|
+
ali_style_map['Vertical'] = style.ali.vertical
|
|
175
|
+
if style.ali.wrapText:
|
|
176
|
+
ali_style_map['WrapText'] = style.ali.wrapText
|
|
177
|
+
if style.ali.shrinkToFit:
|
|
178
|
+
ali_style_map['ShrinkToFit'] = style.ali.shrinkToFit
|
|
179
|
+
if style.ali.indent:
|
|
180
|
+
ali_style_map['Indent'] = style.ali.indent
|
|
181
|
+
if style.ali.readingOrder:
|
|
182
|
+
ali_style_map['ReadingOrder'] = style.ali.readingOrder
|
|
183
|
+
if style.ali.textRotation:
|
|
184
|
+
ali_style_map['TextRotation'] = style.ali.textRotation
|
|
185
|
+
if style.ali.justifyLastLine:
|
|
186
|
+
ali_style_map['JustifyLastLine'] = style.ali.justifyLastLine
|
|
187
|
+
if style.ali.relativeIndent:
|
|
188
|
+
ali_style_map['RelativeIndent'] = style.ali.relativeIndent
|
|
189
|
+
|
|
190
|
+
return ali_style_map
|
|
191
|
+
|
|
192
|
+
def _get_protection_style(self, style: CustomStyle) -> dict[str, str]:
|
|
193
|
+
protection_style_map = {}
|
|
194
|
+
if style.protection.locked:
|
|
195
|
+
protection_style_map['Locked'] = style.protection.locked
|
|
196
|
+
if style.protection.hidden:
|
|
197
|
+
protection_style_map['Hidden'] = style.protection.hidden
|
|
198
|
+
return protection_style_map
|