Skip to content

Commit 216f92e

Browse files
author
MomIsBestFriend
committed
TYP: Type hints in pandas/io/formats/excel.py
1 parent 3577b5a commit 216f92e

File tree

1 file changed

+99
-53
lines changed

1 file changed

+99
-53
lines changed

pandas/io/formats/excel.py

Lines changed: 99 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
"""Utilities for conversion to writer-agnostic Excel representation
1+
"""
2+
Utilities for conversion to writer-agnostic Excel representation.
23
"""
34

45
from functools import reduce
56
import itertools
67
import re
8+
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
79
import warnings
810

911
import numpy as np
@@ -25,7 +27,9 @@ class ExcelCell:
2527
__fields__ = ("row", "col", "val", "style", "mergestart", "mergeend")
2628
__slots__ = __fields__
2729

28-
def __init__(self, row, col, val, style=None, mergestart=None, mergeend=None):
30+
def __init__(
31+
self, row: int, col: int, val, style=None, mergestart=None, mergeend=None
32+
):
2933
self.row = row
3034
self.col = col
3135
self.val = val
@@ -35,7 +39,8 @@ def __init__(self, row, col, val, style=None, mergestart=None, mergeend=None):
3539

3640

3741
class CSSToExcelConverter:
38-
"""A callable for converting CSS declarations to ExcelWriter styles
42+
"""
43+
A callable for converting CSS declarations to ExcelWriter styles.
3944
4045
Supports parts of CSS 2.2, with minimal CSS 3.0 support (e.g. text-shadow),
4146
focusing on font styling, backgrounds, borders and alignment.
@@ -56,15 +61,15 @@ class CSSToExcelConverter:
5661
# instancemethods so that users can easily experiment with extensions
5762
# without monkey-patching.
5863

59-
def __init__(self, inherited=None):
64+
def __init__(self, inherited: Optional[str] = None):
6065
if inherited is not None:
6166
inherited = self.compute_css(inherited)
6267

6368
self.inherited = inherited
6469

6570
compute_css = CSSResolver()
6671

67-
def __call__(self, declarations_str: str):
72+
def __call__(self, declarations_str: str) -> Dict[str, Dict]:
6873
"""
6974
Convert CSS declarations to ExcelWriter style.
7075
@@ -76,15 +81,23 @@ def __call__(self, declarations_str: str):
7681
7782
Returns
7883
-------
79-
xlstyle : dict
80-
A style as interpreted by ExcelWriter when found in
81-
ExcelCell.style.
84+
Dict
85+
A style as interpreted by ExcelWriter when found in ExcelCell.style.
8286
"""
8387
# TODO: memoize?
8488
properties = self.compute_css(declarations_str, self.inherited)
8589
return self.build_xlstyle(properties)
8690

87-
def build_xlstyle(self, props):
91+
def build_xlstyle(self, props: Dict) -> Dict[str, Dict]:
92+
"""
93+
Parameters
94+
----------
95+
props : Dict
96+
97+
Returns
98+
-------
99+
Dict
100+
"""
88101
out = {
89102
"alignment": self.build_alignment(props),
90103
"border": self.build_border(props),
@@ -95,8 +108,14 @@ def build_xlstyle(self, props):
95108

96109
# TODO: handle cell width and height: needs support in pandas.io.excel
97110

98-
def remove_none(d):
99-
"""Remove key where value is None, through nested dicts"""
111+
def remove_none(d: Dict[str, Any]) -> None:
112+
"""
113+
Remove key where value is None, through nested dicts.
114+
115+
Parameters
116+
----------
117+
d : Dict
118+
"""
100119
for k, v in list(d.items()):
101120
if v is None:
102121
del d[k]
@@ -118,7 +137,12 @@ def remove_none(d):
118137
# OpenXML also has 'justify', 'distributed'
119138
}
120139

121-
def build_alignment(self, props):
140+
def build_alignment(self, props) -> Dict[str, Any]:
141+
"""
142+
Returns
143+
-------
144+
Dict
145+
"""
122146
# TODO: text-indent, padding-left -> alignment.indent
123147
return {
124148
"horizontal": props.get("text-align"),
@@ -130,7 +154,16 @@ def build_alignment(self, props):
130154
),
131155
}
132156

133-
def build_border(self, props):
157+
def build_border(self, props: Dict) -> Dict[str, Any]:
158+
"""
159+
Parameters
160+
----------
161+
props : Dict
162+
163+
Returns
164+
-------
165+
Dict
166+
"""
134167
return {
135168
side: {
136169
"style": self._border_style(
@@ -142,7 +175,7 @@ def build_border(self, props):
142175
for side in ["top", "right", "bottom", "left"]
143176
}
144177

145-
def _border_style(self, style, width):
178+
def _border_style(self, style: Optional[str], width):
146179
# convert styles and widths to openxml, one of:
147180
# 'dashDot'
148181
# 'dashDotDot'
@@ -191,7 +224,12 @@ def _border_style(self, style, width):
191224
return "dashed"
192225
return "mediumDashed"
193226

194-
def build_fill(self, props):
227+
def build_fill(self, props: Dict):
228+
"""
229+
Parameters
230+
----------
231+
props : Dict
232+
"""
195233
# TODO: perhaps allow for special properties
196234
# -excel-pattern-bgcolor and -excel-pattern-type
197235
fill_color = props.get("background-color")
@@ -215,7 +253,12 @@ def build_fill(self, props):
215253
}
216254
ITALIC_MAP = {"normal": False, "italic": True, "oblique": True}
217255

218-
def build_font(self, props):
256+
def build_font(self, props) -> Dict[str, Union[bool, int, str, None]]:
257+
"""
258+
Returns
259+
-------
260+
Dict
261+
"""
219262
size = props.get("font-size")
220263
if size is not None:
221264
assert size.endswith("pt")
@@ -311,7 +354,12 @@ def build_font(self, props):
311354
"white": "FFFFFF",
312355
}
313356

314-
def color_to_excel(self, val):
357+
def color_to_excel(self, val: Optional[str]):
358+
"""
359+
Parameters
360+
----------
361+
val : str, optional
362+
"""
315363
if val is None:
316364
return None
317365
if val.startswith("#") and len(val) == 7:
@@ -323,37 +371,39 @@ def color_to_excel(self, val):
323371
except KeyError:
324372
warnings.warn(f"Unhandled color format: {repr(val)}", CSSWarning)
325373

326-
def build_number_format(self, props):
374+
def build_number_format(self, props: Dict) -> Dict[str, Any]:
327375
return {"format_code": props.get("number-format")}
328376

329377

330378
class ExcelFormatter:
331379
"""
332-
Class for formatting a DataFrame to a list of ExcelCells,
380+
Class for formatting a DataFrame to a list of ExcelCells.
333381
334382
Parameters
335383
----------
336384
df : DataFrame or Styler
337-
na_rep: na representation
338-
float_format : string, default None
339-
Format string for floating point numbers
340-
cols : sequence, optional
341-
Columns to write
342-
header : boolean or list of string, default True
343-
Write out column names. If a list of string is given it is
344-
assumed to be aliases for the column names
345-
index : boolean, default True
346-
output row names (index)
347-
index_label : string or sequence, default None
348-
Column label for index column(s) if desired. If None is given, and
349-
`header` and `index` are True, then the index names are used. A
350-
sequence should be given if the DataFrame uses MultiIndex.
351-
merge_cells : boolean, default False
385+
na_rep: str
386+
An na representation.
387+
float_format : str, optional
388+
Format string for floating point numbers.
389+
cols : Sequence, optional
390+
Columns to write.
391+
header : Union[bool, List[str]], default True
392+
Write out column names.
393+
If a list of string is given it is assumed to be aliases for the column names
394+
index : bool, default True
395+
Output row names (index).
396+
index_label : Union[str, Sequence, None], default None
397+
Column label for index column(s) if desired.
398+
If None is given, and `header` and `index` are True,
399+
then the index names are used.
400+
A Sequence should be given if the DataFrame uses MultiIndex.
401+
merge_cells : bool, default False
352402
Format MultiIndex and Hierarchical Rows as merged cells.
353-
inf_rep : string, default `'inf'`
403+
inf_rep : str, default `'inf'`
354404
representation for np.inf values (which aren't representable in Excel)
355405
A `'-'` sign will be added in front of -inf.
356-
style_converter : callable, optional
406+
style_converter : Callable, optional
357407
This translates Styler styles (CSS) into ExcelWriter styles.
358408
Defaults to ``CSSToExcelConverter()``.
359409
It should have signature css_declarations string -> excel style.
@@ -366,15 +416,15 @@ class ExcelFormatter:
366416
def __init__(
367417
self,
368418
df,
369-
na_rep="",
370-
float_format=None,
371-
cols=None,
372-
header=True,
373-
index=True,
374-
index_label=None,
375-
merge_cells=False,
376-
inf_rep="inf",
377-
style_converter=None,
419+
na_rep: str = "",
420+
float_format: Optional[str] = None,
421+
cols: Optional[Sequence] = None,
422+
header: Union[bool, List[str]] = True,
423+
index: bool = True,
424+
index_label: Union[str, Sequence, None] = None,
425+
merge_cells: bool = False,
426+
inf_rep: str = "inf",
427+
style_converter: Optional[Callable] = None,
378428
):
379429
self.rowcounter = 0
380430
self.na_rep = na_rep
@@ -442,10 +492,8 @@ def _format_header_mi(self):
442492
if self.columns.nlevels > 1:
443493
if not self.index:
444494
raise NotImplementedError(
445-
"Writing to Excel with MultiIndex"
446-
" columns and no index "
447-
"('index'=False) is not yet "
448-
"implemented."
495+
"Writing to Excel with MultiIndex columns and no "
496+
"index ('index'=False) is not yet implemented."
449497
)
450498

451499
has_aliases = isinstance(self.header, (tuple, list, np.ndarray, Index))
@@ -540,7 +588,6 @@ def _format_header(self):
540588
return itertools.chain(gen, gen2)
541589

542590
def _format_body(self):
543-
544591
if isinstance(self.df.index, ABCMultiIndex):
545592
return self._format_hierarchical_rows()
546593
else:
@@ -706,7 +753,7 @@ def write(
706753
freeze_panes : tuple of integer (length 2), default None
707754
Specifies the one-based bottommost row and rightmost column that
708755
is to be frozen
709-
engine : string, default None
756+
engine : str, default None
710757
write engine to use if writer is a path - you can also set this
711758
via the options ``io.excel.xlsx.writer``, ``io.excel.xls.writer``,
712759
and ``io.excel.xlsm.writer``.
@@ -716,8 +763,7 @@ def write(
716763
num_rows, num_cols = self.df.shape
717764
if num_rows > self.max_rows or num_cols > self.max_cols:
718765
raise ValueError(
719-
"This sheet is too large! Your sheet size is: "
720-
f"{num_rows}, {num_cols} "
766+
f"This sheet is too large! Your sheet size is: {num_rows}, {num_cols} "
721767
f"Max sheet size is: {self.max_rows}, {self.max_cols}"
722768
)
723769

0 commit comments

Comments
 (0)