Skip to content

Commit 42b140b

Browse files
Justine Kosinskimathbruu
authored andcommitted
fix: fix with wrong formatting
1 parent 10102e6 commit 42b140b

File tree

1 file changed

+55
-27
lines changed

1 file changed

+55
-27
lines changed

pandas/io/formats/excel.py

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Utilities for conversion to writer-agnostic Excel representation.
33
"""
44

5-
from __future__ import annotations
5+
from _future_ import annotations
66

77
from collections.abc import (
88
Callable,
@@ -11,6 +11,7 @@
1111
Mapping,
1212
Sequence,
1313
)
14+
import pandas as pd
1415
import functools
1516
import itertools
1617
import re
@@ -63,10 +64,10 @@
6364

6465

6566
class ExcelCell:
66-
__fields__ = ("row", "col", "val", "style", "mergestart", "mergeend")
67-
__slots__ = __fields__
67+
_fields_ = ("row", "col", "val", "style", "mergestart", "mergeend")
68+
_slots_ = _fields_
6869

69-
def __init__(
70+
def _init_(
7071
self,
7172
row: int,
7273
col: int,
@@ -84,7 +85,7 @@ def __init__(
8485

8586

8687
class CssExcelCell(ExcelCell):
87-
def __init__(
88+
def _init_(
8889
self,
8990
row: int,
9091
col: int,
@@ -105,7 +106,7 @@ def __init__(
105106
unique_declarations = frozenset(declaration_dict.items())
106107
style = css_converter(unique_declarations)
107108

108-
super().__init__(row=row, col=col, val=val, style=style, **kwargs)
109+
super()._init_(row=row, col=col, val=val, style=style, **kwargs)
109110

110111

111112
class CSSToExcelConverter:
@@ -116,14 +117,14 @@ class CSSToExcelConverter:
116117
focusing on font styling, backgrounds, borders and alignment.
117118
118119
Operates by first computing CSS styles in a fairly generic
119-
way (see :meth:`compute_css`) then determining Excel style
120-
properties from CSS properties (see :meth:`build_xlstyle`).
120+
way (see :meth:⁠ compute_css ⁠) then determining Excel style
121+
properties from CSS properties (see :meth:⁠ build_xlstyle ⁠).
121122
122123
Parameters
123124
----------
124125
inherited : str, optional
125126
CSS declarations understood to be the containing scope for the
126-
CSS processed by :meth:`__call__`.
127+
CSS processed by :meth:⁠ __call__ ⁠.
127128
"""
128129

129130
NAMED_COLORS = CSS4_COLORS
@@ -183,25 +184,25 @@ class CSSToExcelConverter:
183184
]
184185
}
185186

186-
# NB: Most of the methods here could be classmethods, as only __init__
187-
# and __call__ make use of instance attributes. We leave them as
187+
# NB: Most of the methods here could be classmethods, as only _init_
188+
# and _call_ make use of instance attributes. We leave them as
188189
# instancemethods so that users can easily experiment with extensions
189190
# without monkey-patching.
190191
inherited: dict[str, str] | None
191192

192-
def __init__(self, inherited: str | None = None) -> None:
193+
def _init_(self, inherited: str | None = None) -> None:
193194
if inherited is not None:
194195
self.inherited = self.compute_css(inherited)
195196
else:
196197
self.inherited = None
197-
# We should avoid cache on the __call__ method.
198-
# Otherwise once the method __call__ has been called
198+
# We should avoid cache on the _call_ method.
199+
# Otherwise once the method _call_ has been called
199200
# garbage collection no longer deletes the instance.
200201
self._call_cached = functools.cache(self._call_uncached)
201202

202203
compute_css = CSSResolver()
203204

204-
def __call__(
205+
def _call_(
205206
self, declarations: str | frozenset[tuple[str, str]]
206207
) -> dict[str, dict[str, str]]:
207208
"""
@@ -517,27 +518,27 @@ class ExcelFormatter:
517518
output row names (index)
518519
index_label : str or sequence, default None
519520
Column label for index column(s) if desired. If None is given, and
520-
`header` and `index` are True, then the index names are used. A
521+
⁠ header ⁠ and ⁠ index ⁠ are True, then the index names are used. A
521522
sequence should be given if the DataFrame uses MultiIndex.
522523
merge_cells : bool or 'columns', default False
523524
Format MultiIndex column headers and Hierarchical Rows as merged cells
524525
if True. Merge MultiIndex column headers only if 'columns'.
525526
.. versionchanged:: 3.0.0
526527
Added the 'columns' option.
527-
inf_rep : str, default `'inf'`
528+
inf_rep : str, default ⁠ 'inf' ⁠
528529
representation for np.inf values (which aren't representable in Excel)
529-
A `'-'` sign will be added in front of -inf.
530+
A ⁠ '-' ⁠ sign will be added in front of -inf.
530531
style_converter : callable, optional
531532
This translates Styler styles (CSS) into ExcelWriter styles.
532-
Defaults to ``CSSToExcelConverter()``.
533+
Defaults to `⁠ CSSToExcelConverter() ⁠`.
533534
It should have signature css_declarations string -> excel style.
534535
This is only called for body cells.
535536
"""
536537

537538
max_rows = 2**20
538539
max_cols = 2**14
539540

540-
def __init__(
541+
def _init_(
541542
self,
542543
df,
543544
na_rep: str = "",
@@ -594,7 +595,11 @@ def _format_value(self, val):
594595
elif missing.isneginf_scalar(val):
595596
val = f"-{self.inf_rep}"
596597
elif self.float_format is not None:
597-
val = float(self.float_format % val)
598+
val = self.float_format % val
599+
else:
600+
# respecter l'affichage par défaut de pandas (console)
601+
val = repr(val)
602+
598603
if getattr(val, "tzinfo", None) is not None:
599604
raise ValueError(
600605
"Excel does not support datetimes with "
@@ -616,7 +621,20 @@ def _format_header_mi(self) -> Iterable[ExcelCell]:
616621

617622
columns = self.columns
618623
merge_columns = self.merge_cells in {True, "columns"}
619-
level_strs = columns._format_multi(sparsify=merge_columns, include_names=False)
624+
625+
# Replace NaN column header values with a non-breaking space so
626+
# Excel output matches console display (see user's _fix_headers).
627+
NBSP = "\u00A0"
628+
if isinstance(columns, MultiIndex):
629+
fixed_levels = []
630+
for lvl in range(columns.nlevels):
631+
vals = columns.get_level_values(lvl)
632+
fixed_levels.append([NBSP if pd.isna(v) else str(v) for v in vals])
633+
fixed_columns = MultiIndex.from_arrays(fixed_levels, names=columns.names)
634+
else:
635+
fixed_columns = Index([NBSP if pd.isna(v) else str(v) for v in columns], name=columns.name)
636+
637+
level_strs = fixed_columns._format_multi(sparsify=merge_columns, include_names=False)
620638
level_lengths = get_level_lengths(level_strs)
621639
coloffset = 0
622640
lnum = 0
@@ -625,17 +643,20 @@ def _format_header_mi(self) -> Iterable[ExcelCell]:
625643
coloffset = self.df.index.nlevels - 1
626644

627645
for lnum, name in enumerate(columns.names):
646+
val = NBSP if pd.isna(name) else str(name)
628647
yield ExcelCell(
629648
row=lnum,
630649
col=coloffset,
631-
val=name,
650+
val=val,
632651
style=None,
633652
)
634653

635654
for lnum, (spans, levels, level_codes) in enumerate(
636655
zip(level_lengths, columns.levels, columns.codes, strict=True)
637656
):
638-
values = levels.take(level_codes)
657+
# level.take(codes) on fixed_columns.levels yields string values
658+
values = level.take(codes).to_numpy()
659+
639660
for i, span_val in spans.items():
640661
mergestart, mergeend = None, None
641662
if merge_columns and span_val > 1:
@@ -652,6 +673,7 @@ def _format_header_mi(self) -> Iterable[ExcelCell]:
652673
mergestart=mergestart,
653674
mergeend=mergeend,
654675
)
676+
655677
self.rowcounter = lnum
656678

657679
def _format_header_regular(self) -> Iterable[ExcelCell]:
@@ -673,6 +695,12 @@ def _format_header_regular(self) -> Iterable[ExcelCell]:
673695
)
674696
colnames = self.header
675697

698+
# Normalize NaN column labels to a non-breaking space so Excel
699+
# header output matches console display (same behavior as
700+
# applied to MultiIndex headers in _format_header_mi).
701+
NBSP = "\u00A0"
702+
colnames = [NBSP if pd.isna(v) else str(v) for v in colnames]
703+
676704
for colindex, colname in enumerate(colnames):
677705
yield CssExcelCell(
678706
row=self.rowcounter,
@@ -899,8 +927,8 @@ def write(
899927
is to be frozen
900928
engine : string, default None
901929
write engine to use if writer is a path - you can also set this
902-
via the options ``io.excel.xlsx.writer``,
903-
or ``io.excel.xlsm.writer``.
930+
via the options `⁠ io.excel.xlsx.writer ⁠`,
931+
or `⁠ io.excel.xlsm.writer ⁠`.
904932
905933
{storage_options}
906934
@@ -942,4 +970,4 @@ def write(
942970
finally:
943971
# make sure to close opened file handles
944972
if need_save:
945-
writer.close()
973+
writer.close()

0 commit comments

Comments
 (0)