8000 Merge PR #2881 and fix unit test · pandas-dev/pandas@8f92d9a · GitHub
[go: up one dir, main page]

Skip to content
Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8f92d9a

Browse files
committed
Merge PR #2881 and fix unit test
2 parents ba774f5 + 7db1af4 commit 8f92d9a

File tree

3 files changed

+138
-62
lines changed

3 files changed

+138
-62
lines changed

pandas/core/config_init.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@ def mpl_style_cb(key):
212212
cf.register_option('mpl_style', None, pc_mpl_style_doc,
213213
validator=is_one_of_factory([None, False, 'default']),
214214
cb=mpl_style_cb)
215+
cf.register_option('height', 100, 'TODO', validator=is_int)
216+
cf.register_option('width',80, 'TODO', validator=is_int)
217+
cf.deprecate_option('display.line_width', msg='TODO', rkey='display.width')
215218

216219
tc_sim_interactive_doc = """
217220
: boolean

pandas/core/frame.py

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -599,44 +599,39 @@ def empty(self):
599599
def __nonzero__(self):
600600
raise ValueError("Cannot call bool() on DataFrame.")
601601

602-
def _need_info_repr_(self):
602+
def _repr_fits_boundaries_(self):
603603
"""
604-
Check if it is needed to use info/summary view to represent a
605-
particular DataFrame.
604+
Check if repr fits in boundaries imposed by the following sets of
605+
display options:
606+
* width, height
607+
* max_rows, max_columns
608+
In case off non-interactive session, no boundaries apply.
606609
"""
610+
if not com.in_interactive_session():
611+
return True
607612

608-
if com.in_qtconsole():
609-
terminal_width, terminal_height = 100, 100
610-
else:
611-
terminal_width, terminal_height = get_terminal_size()
612-
max_rows = (terminal_height if get_option("display.max_rows") == 0
613-
else get_option("display.max_rows"))
614-
max_columns = get_option("display.max_columns")
615-
expand_repr = get_option("display.expand_frame_repr")
613+
terminal_width, terminal_height = get_terminal_size()
616614

617-
if max_columns > 0:
618-
if (len(self.index) <= max_rows and
619-
(len(self.columns) <= max_columns and expand_repr)):
620-
return False
621-
else:
622-
return True
623-
else:
624-
# save us
625-
if (len(self.index) > max_rows or
626-
(com.in_interactive_session() and
627-
len(self.columns) > terminal_width // 2 and
628-
not expand_repr)):
629-
return True
630-
else:
631-
buf = StringIO()
632-
self.to_string(buf=buf)
633-
value = buf.getvalue()
634-
if (max([len(l) for l in value.split('\n')]) > terminal_width
635-
and com.in_interactive_session()
636-
and not expand_repr):
637-
return True
638-
else:
639-
return False
615+
# check vertical boundaries (excluding column axis area)
616+
max_rows = get_option("display.max_rows") or terminal_height
617+
display_height = get_option("display.height") or terminal_height
618+
if len(self.index) > min(max_rows, display_height):
619+
return False
620+
621+
# check horizontal boundaries (including index axis area)
622+
max_columns = get_option("display.max_columns")
623+
display_width = get_option("display.width") or terminal_width
624+
nb_columns = len(self.columns)
625+
if max_columns and nb_columns > max_columns:
626+
return False
627+
if nb_columns > (display_width // 2):
628+
return False
629+
630+
buf = StringIO()
631+
self.to_string(buf=buf)
632+
value = buf.getvalue()
633+
repr_width = max([len(l) for l in value.split('\n')])
634+
return repr_width <= display_width
640635

641636
def __str__(self):
642637
"""
@@ -668,26 +663,29 @@ def __unicode__(self):
668663
py2/py3.
669664
"""
670665
buf = StringIO(u"")
671-
if self._need_info_repr_():
672-
max_info_rows = get_option('display.max_info_rows')
673-
verbose = max_info_rows is None or self.shape[0] <= max_info_rows
674-
self.info(buf=buf, verbose=verbose)
666+
if self._repr_fits_boundaries_():
667+
self.to_string(buf=buf)
675668
else:
676-
is_wide = self._need_wide_repr()
677-
line_width = None
678-
if is_wide:
679-
line_width = get_option('display.line_width')
680-
self.to_string(buf=buf, line_width=line_width)
669+
terminal_width, terminal_height = get_terminal_size()
670+
max_rows = get_option("display.max_rows") or terminal_height
671+
# Expand or info? Decide based on option display.expand_frame_repr
672+
# and keep it sane for the number of display rows used by the
673+
# expanded repr.
674+
if (get_option("display.expand_frame_repr") and
675+
len(self.columns) < max_rows):
676+
line_width = get_option("display.width") or terminal_width
677+
self.to_string(buf=buf, line_width=line_width)
678+
else:
679+
max_info_rows = get_option('display.max_info_rows')
680+
verbose = (max_info_rows is None or
681+
self.shape[0] <= max_info_rows)
682+
self.info(buf=buf, verbose=verbose)
681683

682684
value = buf.getvalue()
683685
assert type(value) == unicode
684686

685687
return value
686688

687-
def _need_wide_repr(self):
688-
return (get_option("display.expand_frame_repr")
689-
and com.in_interactive_session())
690-
691689
def __repr__(self):
692690
"""
693691
Return a string representation for a particular DataFrame
@@ -705,12 +703,18 @@ def _repr_html_(self):
705703
raise ValueError('Disable HTML output in QtConsole')
706704

707705
if get_option("display.notebook_repr_html"):
708-
if self._need_info_repr_():
709-
return None
710-
else:
706+
if self._repr_fits_boundaries_():
711707
return ('<div style="max-height:1000px;'
712708
'max-width:1500px;overflow:auto;">\n' +
713709
self.to_html() + '\n</div>')
710+
else:
711+
buf = StringIO(u"")
712+
max_info_rows = get_option('display.max_info_rows')
713+
verbose = (max_info_rows is None or
714+
self.shape[0] <= max_info_rows)
715+
self.info(buf=buf, verbose=verbose)
716+
info = buf.getvalue().replace('<', '&lt').replace('>', '&gt')
717+
return ('<pre>\n' + info + '\n</pre>')
714718
else:
715719
return None
716720

pandas/tests/test_format.py

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from pandas.util.py3compat import lzip
2020
import pandas.core.format as fmt
2121
import pandas.util.testing as tm
22+
from pandas.util.terminal import get_terminal_size
2223
import pandas
2324
import pandas as pd
2425
from pandas.core.config import (set_option, get_option,
@@ -27,6 +28,22 @@
2728
_frame = DataFrame(tm.getSeriesData())
2829

2930

31+
def curpath():
32+
pth, _ = os.path.split(os.path.abspath(__file__))
33+
return pth
34+
35+
def has_info_repr(df):
36+
r = repr(df)
37+
return r.split('\n')[0].startswith("<class")
38+
39+
def has_expanded_repr(df):
40+
r = repr(df)
41+
for line in r.split('\n'):
42+
if line.endswith('\\'):
43+
return True
44+
return False
45+
46+
3047
class TestDataFrameFormatting(unittest.TestCase):
3148
_multiprocess_can_split_ = True
3249

@@ -139,6 +156,57 @@ def test_repr_no_backslash(self):
139156
df = DataFrame(np.random.randn(10, 4))
140157
self.assertTrue('\\' not in repr(df))
141158

159+
def test_expand_frame_repr(self):
160+
df_small = DataFrame('hello', [0], [0])
161+
df_wide = DataFrame('hello', [0], range(10))
162+
163+
with option_context('mode.sim_interactive', True):
164+
with option_context('display.width', 50):
165+
with option_context('display.expand_frame_repr', True):
166+
self.assertFalse(has_info_repr(df_small))
167+
self.assertFalse(has_expanded_repr(df_small))
168+
self.assertFalse(has_info_repr(df_wide))
169+
self.assertTrue(has_expanded_repr(df_wide))
170+
171+
with option_context('display.expand_frame_repr', False):
172+
self.assertFalse(has_info_repr(df_small))
173+
self.assertFalse(has_expanded_repr(df_small))
174+
self.assertTrue(has_info_repr(df_wide))
175+
self.assertFalse(has_expanded_repr(df_wide))
176+
177+
def test_repr_max_columns_max_rows(self):
178+
term_width, term_height = get_terminal_size()
179+
if term_width < 10 or term_height < 10:
180+
raise nose.SkipTest
181+
182+
def mkframe(n):
183+
index = ['%05d' % i for i in range(n)]
184+
return DataFrame(0, index, index)
185+
186+
with option_context('mode.sim_interactive', True):
187+
with option_context('display.width', term_width * 2):
188+
with option_context('display.max_rows', 5,
189+
'display.max_columns', 5):
190+
self.assertFalse(has_expanded_repr(mkframe(4)))
191+
self.assertFalse(has_expanded_repr(mkframe(5)))
192+
self.assertFalse(has_expanded_repr(mkframe(6)))
193+
self.assertTrue(has_info_repr(mkframe(6)))
194+
195+
with option_context('display.max_rows', 20,
196+
'display.max_columns', 5):
197+
# Out off max_columns boundary, but no extending
198+
# occurs ... can improve?
199+
self.assertFalse(has_expanded_repr(mkframe(6)))
200+
self.assertFalse(has_info_repr(mkframe(6)))
201+
202+
with option_context('display.max_columns', 0,
203+
'display.max_rows', term_width * 20,
204+
'display.width', 0):
205+
df = mkframe((term_width // 7) - 2)
206+
self.assertFalse(has_expanded_repr(df))
207+
df = mkframe((term_width // 7) + 2)
208+
self.assertTrue(has_expanded_repr(df))
209+
142210
def test_to_string_repr_unicode(self):
143211
buf = StringIO()
144212

@@ -525,19 +593,20 @@ def test_setting(value, nrows=3, ncols=2):
525593
else:
526594
raise ValueError("'value' must be int or None")
527595

528-
pd.set_option('display.max_rows', nrows - 1)
529-
pd.set_option('display.max_info_rows', value)
596+
with option_context('mode.sim_interactive', True):
597+
pd.set_option('display.max_rows', nrows - 1)
598+
pd.set_option('display.max_info_rows', value)
530599

531-
smallx = DataFrame(np.random.rand(nrows, ncols))
532-
repr_small = repr(smallx)
600+
smallx = DataFrame(np.random.rand(nrows, ncols))
601+
repr_small = repr(smallx)
533602

534-
bigx = DataFrame(np.random.rand(nrows + 1, ncols))
535-
repr_big = repr(bigx)
603+
bigx = DataFrame(np.random.rand(nrows + 1, ncols))
604+
repr_big = repr(bigx)
536605

537-
diff = len(repr_small.splitlines()) - len(repr_big.splitlines())
606+
diff = len(repr_small.splitlines()) - len(repr_big.splitlines())
538607

539-
# the difference in line count is the number of columns
D244 540-
self.assertEqual(diff, expected_difference)
608+
# the difference in line count is the number of columns
609+
self.assertEqual(diff, expected_difference)
541610

542611
test_setting(None)
543612
test_setting(3)
@@ -691,7 +760,7 @@ def test_index_with_nan(self):
691760
result = y.to_string()
692761
expected = u' id1 id3 value\nid2 \nNaN 1a3 78d 123\nNaN 9h4 79d 64'
693762
self.assert_(result == expected)
694-
763+
695764
# partial nan in mi
696765
df2 = df.copy()
697766
df2.ix[:,'id2'] = np.nan
@@ -1170,8 +1239,8 @@ def get_ipython():
11701239
self.assert_(repstr is not None)
11711240

11721241
fmt.set_printoptions(max_rows=5, max_columns=2)
1173-
1174-
self.assert_(self.frame._repr_html_() is None)
1242+
repstr = self.frame._repr_html_()
1243+
self.assert_('class' in repstr) # info fallback
11751244

11761245
fmt.reset_printoptions()
11771246

0 commit comments

Comments
 (0)
0