1515 TypeVar ,
1616 Union ,
1717)
18+ from unicodedata import east_asian_width
1819
1920from pandas ._config import get_option
2021
2122from pandas .core .dtypes .inference import is_sequence
2223
24+ from pandas .io .formats .console import get_console_size
25+
2326EscapeChars = 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 ()
0 commit comments