Skip to content

Commit e22bfb3

Browse files
authored
REF: avoid circular imports in formats (#55467)
* REF: avoid circular import of get_adjustment * revert
1 parent 1025151 commit e22bfb3

File tree

6 files changed

+92
-86
lines changed

6 files changed

+92
-86
lines changed

pandas/core/indexes/multi.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@
107107
lexsort_indexer,
108108
)
109109

110-
from pandas.io.formats.printing import pprint_thing
110+
from pandas.io.formats.printing import (
111+
get_adjustment,
112+
pprint_thing,
113+
)
111114

112115
if TYPE_CHECKING:
113116
from pandas import (
@@ -1437,8 +1440,6 @@ def format(
14371440
)
14381441

14391442
if adjoin:
1440-
from pandas.io.formats.format import get_adjustment
1441-
14421443
adj = get_adjustment()
14431444
return adj.adjoin(space, *result_levels).split("\n")
14441445
else:

pandas/io/common.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@
6868
is_integer,
6969
is_list_like,
7070
)
71+
from pandas.core.dtypes.generic import ABCMultiIndex
7172

72-
from pandas.core.indexes.api import MultiIndex
7373
from pandas.core.shared_docs import _shared_docs
7474

7575
_VALID_URLS = set(uses_relative + uses_netloc + uses_params)
@@ -91,6 +91,8 @@
9191
WriteBuffer,
9292
)
9393

94+
from pandas import MultiIndex
95+
9496

9597
@dataclasses.dataclass
9698
class IOArgs:
@@ -1228,7 +1230,7 @@ def is_potential_multi_index(
12281230

12291231
return bool(
12301232
len(columns)
1231-
and not isinstance(columns, MultiIndex)
1233+
and not isinstance(columns, ABCMultiIndex)
12321234
and all(isinstance(c, tuple) for c in columns if c not in list(index_col))
12331235
)
12341236

pandas/io/formats/format.py

+4-69
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from collections.abc import (
88
Generator,
99
Hashable,
10-
Iterable,
1110
Mapping,
1211
Sequence,
1312
)
@@ -26,7 +25,6 @@
2625
Final,
2726
cast,
2827
)
29-
from unicodedata import east_asian_width
3028

3129
import numpy as np
3230

@@ -226,7 +224,7 @@ def __init__(
226224
float_format = get_option("display.float_format")
227225
self.float_format = float_format
228226
self.dtype = dtype
229-
self.adj = get_adjustment()
227+
self.adj = printing.get_adjustment()
230228

231229
self._chk_truncate()
232230

@@ -347,69 +345,6 @@ def to_string(self) -> str:
347345
return str("".join(result))
348346

349347

350-
class _TextAdjustment:
351-
def __init__(self) -> None:
352-
self.encoding = get_option("display.encoding")
353-
354-
def len(self, text: str) -> int:
355-
return len(text)
356-
357-
def justify(self, texts: Any, max_len: int, mode: str = "right") -> list[str]:
358-
return printing.justify(texts, max_len, mode=mode)
359-
360-
def adjoin(self, space: int, *lists, **kwargs) -> str:
361-
return printing.adjoin(
362-
space, *lists, strlen=self.len, justfunc=self.justify, **kwargs
363-
)
364-
365-
366-
class _EastAsianTextAdjustment(_TextAdjustment):
367-
def __init__(self) -> None:
368-
super().__init__()
369-
if get_option("display.unicode.ambiguous_as_wide"):
370-
self.ambiguous_width = 2
371-
else:
372-
self.ambiguous_width = 1
373-
374-
# Definition of East Asian Width
375-
# https://unicode.org/reports/tr11/
376-
# Ambiguous width can be changed by option
377-
self._EAW_MAP = {"Na": 1, "N": 1, "W": 2, "F": 2, "H": 1}
378-
379-
def len(self, text: str) -> int:
380-
"""
381-
Calculate display width considering unicode East Asian Width
382-
"""
383-
if not isinstance(text, str):
384-
return len(text)
385-
386-
return sum(
387-
self._EAW_MAP.get(east_asian_width(c), self.ambiguous_width) for c in text
388-
)
389-
390-
def justify(
391-
self, texts: Iterable[str], max_len: int, mode: str = "right"
392-
) -> list[str]:
393-
# re-calculate padding space per str considering East Asian Width
394-
def _get_pad(t):
395-
return max_len - self.len(t) + len(t)
396-
397-
if mode == "left":
398-
return [x.ljust(_get_pad(x)) for x in texts]
399-
elif mode == "center":
400-
return [x.center(_get_pad(x)) for x in texts]
401-
else:
402-
return [x.rjust(_get_pad(x)) for x in texts]
403-
404-
405-
def get_adjustment() -> _TextAdjustment:
406-
use_east_asian_width = get_option("display.unicode.east_asian_width")
407-
if use_east_asian_width:
408-
return _EastAsianTextAdjustment()
409-
else:
410-
return _TextAdjustment()
411-
412-
413348
def get_dataframe_repr_params() -> dict[str, Any]:
414349
"""Get the parameters used to repr(dataFrame) calls using DataFrame.to_string.
415350
@@ -529,7 +464,7 @@ def __init__(
529464

530465
self.tr_frame = self.frame
531466
self.truncate()
532-
self.adj = get_adjustment()
467+
self.adj = printing.get_adjustment()
533468

534469
def get_strcols(self) -> list[list[str]]:
535470
"""
@@ -1789,13 +1724,13 @@ def _make_fixed_width(
17891724
strings: list[str],
17901725
justify: str = "right",
17911726
minimum: int | None = None,
1792-
adj: _TextAdjustment | None = None,
1727+
adj: printing._TextAdjustment | None = None,
17931728
) -> list[str]:
17941729
if len(strings) == 0 or justify == "all":
17951730
return strings
17961731

17971732
if adj is None:
1798-
adjustment = get_adjustment()
1733+
adjustment = printing.get_adjustment()
17991734
else:
18001735
adjustment = adj
18011736

pandas/io/formats/printing.py

+74-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
TypeVar,
1616
Union,
1717
)
18+
from unicodedata import east_asian_width
1819

1920
from pandas._config import get_option
2021

2122
from pandas.core.dtypes.inference import is_sequence
2223

24+
from pandas.io.formats.console import get_console_size
25+
2326
EscapeChars = Union[Mapping[str, str], Iterable[str]]
2427
_KT = TypeVar("_KT")
2528
_VT = TypeVar("_VT")
@@ -42,7 +45,7 @@ def adjoin(space: int, *lists: list[str], **kwargs) -> str:
4245
function used to justify str. Needed for unicode handling.
4346
"""
4447
strlen = kwargs.pop("strlen", len)
45-
justfunc = kwargs.pop("justfunc", justify)
48+
justfunc = kwargs.pop("justfunc", _adj_justify)
4649

4750
newLists = []
4851
lengths = [max(map(strlen, x)) + space for x in lists[:-1]]
@@ -57,7 +60,7 @@ def adjoin(space: int, *lists: list[str], **kwargs) -> str:
5760
return "\n".join("".join(lines) for lines in toJoin)
5861

5962

60-
def justify(texts: Iterable[str], max_len: int, mode: str = "right") -> list[str]:
63+
def _adj_justify(texts: Iterable[str], max_len: int, mode: str = "right") -> list[str]:
6164
"""
6265
Perform ljust, center, rjust against string or list-like
6366
"""
@@ -314,9 +317,6 @@ def format_object_summary(
314317
-------
315318
summary string
316319
"""
317-
from pandas.io.formats.console import get_console_size
318-
from pandas.io.formats.format import get_adjustment
319-
320320
display_width, _ = get_console_size()
321321
if display_width is None:
322322
display_width = get_option("display.width") or 80
@@ -501,3 +501,72 @@ class PrettyDict(dict[_KT, _VT]):
501501

502502
def __repr__(self) -> str:
503503
return pprint_thing(self)
504+
505+
506+
class _TextAdjustment:
507+
def __init__(self) -> None:
508+
self.encoding = get_option("display.encoding")
509+
510+
def len(self, text: str) -> int:
511+
return len(text)
512+
513+
def justify(self, texts: Any, max_len: int, mode: str = "right") -> list[str]:
514+
"""
515+
Perform ljust, center, rjust against string or list-like
516+
"""
517+
if mode == "left":
518+
return [x.ljust(max_len) for x in texts]
519+
elif mode == "center":
520+
return [x.center(max_len) for x in texts]
521+
else:
522+
return [x.rjust(max_len) for x in texts]
523+
524+
def adjoin(self, space: int, *lists, **kwargs) -> str:
525+
return adjoin(space, *lists, strlen=self.len, justfunc=self.justify, **kwargs)
526+
527+
528+
class _EastAsianTextAdjustment(_TextAdjustment):
529+
def __init__(self) -> None:
530+
super().__init__()
531+
if get_option("display.unicode.ambiguous_as_wide"):
532+
self.ambiguous_width = 2
533+
else:
534+
self.ambiguous_width = 1
535+
536+
# Definition of East Asian Width
537+
# https://unicode.org/reports/tr11/
538+
# Ambiguous width can be changed by option
539+
self._EAW_MAP = {"Na": 1, "N": 1, "W": 2, "F": 2, "H": 1}
540+
541+
def len(self, text: str) -> int:
542+
"""
543+
Calculate display width considering unicode East Asian Width
544+
"""
545+
if not isinstance(text, str):
546+
return len(text)
547+
548+
return sum(
549+
self._EAW_MAP.get(east_asian_width(c), self.ambiguous_width) for c in text
550+
)
551+
552+
def justify(
553+
self, texts: Iterable[str], max_len: int, mode: str = "right"
554+
) -> list[str]:
555+
# re-calculate padding space per str considering East Asian Width
556+
def _get_pad(t):
557+
return max_len - self.len(t) + len(t)
558+
559+
if mode == "left":
560+
return [x.ljust(_get_pad(x)) for x in texts]
561+
elif mode == "center":
562+
return [x.center(_get_pad(x)) for x in texts]
563+
else:
564+
return [x.rjust(_get_pad(x)) for x in texts]
565+
566+
567+
def get_adjustment() -> _TextAdjustment:
568+
use_east_asian_width = get_option("display.unicode.east_asian_width")
569+
if use_east_asian_width:
570+
return _EastAsianTextAdjustment()
571+
else:
572+
return _TextAdjustment()

pandas/tests/io/formats/test_format.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def test_repr_truncation(self):
212212
r = repr(df)
213213
r = r[r.find("\n") + 1 :]
214214

215-
adj = fmt.get_adjustment()
215+
adj = printing.get_adjustment()
216216

217217
for line, value in zip(r.split("\n"), df["B"]):
218218
if adj.len(value) + 1 > max_len:

pandas/tests/io/formats/test_printing.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import pandas as pd
99

1010
from pandas.io.formats import printing
11-
import pandas.io.formats.format as fmt
1211

1312

1413
def test_adjoin():
@@ -48,7 +47,7 @@ def test_adjoin_unicode(self):
4847
adjoined = printing.adjoin(2, *data)
4948
assert adjoined == expected
5049

51-
adj = fmt._EastAsianTextAdjustment()
50+
adj = printing._EastAsianTextAdjustment()
5251

5352
expected = """あ dd ggg
5453
b ええ hhh
@@ -73,7 +72,7 @@ def test_adjoin_unicode(self):
7372
assert adj.len(cols[2]) == 26
7473

7574
def test_justify(self):
76-
adj = fmt._EastAsianTextAdjustment()
75+
adj = printing._EastAsianTextAdjustment()
7776

7877
def just(x, *args, **kwargs):
7978
# wrapper to test single str
@@ -95,7 +94,7 @@ def just(x, *args, **kwargs):
9594
assert just("パンダ", 10, mode="right") == " パンダ"
9695

9796
def test_east_asian_len(self):
98-
adj = fmt._EastAsianTextAdjustment()
97+
adj = printing._EastAsianTextAdjustment()
9998

10099
assert adj.len("abc") == 3
101100
assert adj.len("abc") == 3
@@ -106,11 +105,11 @@ def test_east_asian_len(self):
106105
assert adj.len("パンダpanda") == 10
107106

108107
def test_ambiguous_width(self):
109-
adj = fmt._EastAsianTextAdjustment()
108+
adj = printing._EastAsianTextAdjustment()
110109
assert adj.len("¡¡ab") == 4
111110

112111
with cf.option_context("display.unicode.ambiguous_as_wide", True):
113-
adj = fmt._EastAsianTextAdjustment()
112+
adj = printing._EastAsianTextAdjustment()
114113
assert adj.len("¡¡ab") == 6
115114

116115
data = [["あ", "b", "c"], ["dd", "ええ", "ff"], ["ggg", "¡¡ab", "いいい"]]

0 commit comments

Comments
 (0)