Skip to content

Commit e47e981

Browse files
committed
TST: test for GH4633, bool(obj) behavior
BUG: GH4633, rever to GH1073, whereby __nonzero__ always raises for all NDFrame objects
1 parent c472099 commit e47e981

File tree

10 files changed

+82
-27
lines changed

10 files changed

+82
-27
lines changed

doc/source/release.rst

+3
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ pandas 0.13
130130
now returns a ``MultiIndex`` rather than an ``Index``. (:issue:`4039`)
131131

132132
- Infer and downcast dtype if ``downcast='infer'`` is passed to ``fillna/ffill/bfill`` (:issue:`4604`)
133+
- Factored out excel_value_to_python_value from ExcelFile::_parse_excel (:issue:`4589`)
134+
- ``__nonzero__`` for all NDFrame objects, will now raise a ``ValueError``, this reverts back to (:issue:`1073`, :issue:`4633`)
135+
behavior.
133136

134137
**Internal Refactoring**
135138

doc/source/v0.13.0.txt

+12
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,18 @@ API changes
118118
index.set_names(["bob", "cranberry"], inplace=True)
119119

120120
- Infer and downcast dtype if ``downcast='infer'`` is passed to ``fillna/ffill/bfill`` (:issue:`4604`)
121+
- ``__nonzero__`` for all NDFrame objects, will now raise a ``ValueError``, this reverts back to (:issue:`1073`, :issue:`4633`)
122+
behavior.
123+
124+
This prevent behaviors like (which will now all raise ``ValueError``)
125+
126+
..code-block ::
127+
128+
if df:
129+
....
130+
131+
df1 and df2
132+
s1 and s2
121133

122134
Enhancements
123135
~~~~~~~~~~~~

pandas/core/generic.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,8 @@ def empty(self):
531531
return not all(len(self._get_axis(a)) > 0 for a in self._AXIS_ORDERS)
532532

533533
def __nonzero__(self):
534-
return not self.empty
534+
raise ValueError("The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()")
535+
535536
__bool__ = __nonzero__
536537

537538
#----------------------------------------------------------------------

pandas/core/groupby.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -2101,9 +2101,22 @@ def filter(self, func, dropna=True, *args, **kwargs):
21012101
else:
21022102
res = path(group)
21032103

2104-
if res:
2104+
def add_indexer():
21052105
indexers.append(self.obj.index.get_indexer(group.index))
21062106

2107+
# interpret the result of the filter
2108+
if isinstance(res,(bool,np.bool_)):
2109+
if res:
2110+
add_indexer()
2111+
else:
2112+
if getattr(res,'ndim',None) == 1:
2113+
if res.ravel()[0]:
2114+
add_indexer()
2115+
else:
2116+
2117+
# in theory you could do .all() on the boolean result ?
2118+
raise TypeError("the filter must return a boolean result")
2119+
21072120
if len(indexers) == 0:
21082121
filtered = self.obj.take([]) # because np.concatenate would fail
21092122
else:

pandas/core/series.py

-7
Original file line numberDiff line numberDiff line change
@@ -798,13 +798,6 @@ def __contains__(self, key):
798798
__long__ = _coerce_method(int)
799799
__int__ = _coerce_method(int)
800800

801-
def __nonzero__(self):
802-
# special case of a single element bool series degenerating to a scalar
803-
if self.dtype == np.bool_ and len(self) == 1:
804-
return bool(self.iloc[0])
805-
return not self.empty
806-
__bool__ = __nonzero__
807-
808801
# we are preserving name here
809802
def __getstate__(self):
810803
return dict(_data=self._data, name=self.name)

pandas/io/tests/test_pytables.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1519,19 +1519,19 @@ def test_table_values_dtypes_roundtrip(self):
15191519
with ensure_clean(self.path) as store:
15201520
df1 = DataFrame({'a': [1, 2, 3]}, dtype='f8')
15211521
store.append('df_f8', df1)
1522-
assert df1.dtypes == store['df_f8'].dtypes
1522+
assert_series_equal(df1.dtypes,store['df_f8'].dtypes)
15231523

15241524
df2 = DataFrame({'a': [1, 2, 3]}, dtype='i8')
15251525
store.append('df_i8', df2)
1526-
assert df2.dtypes == store['df_i8'].dtypes
1526+
assert_series_equal(df2.dtypes,store['df_i8'].dtypes)
15271527

15281528
# incompatible dtype
15291529
self.assertRaises(ValueError, store.append, 'df_i8', df1)
15301530

15311531
# check creation/storage/retrieval of float32 (a bit hacky to actually create them thought)
15321532
df1 = DataFrame(np.array([[1],[2],[3]],dtype='f4'),columns = ['A'])
15331533
store.append('df_f4', df1)
1534-
assert df1.dtypes == store['df_f4'].dtypes
1534+
assert_series_equal(df1.dtypes,store['df_f4'].dtypes)
15351535
assert df1.dtypes[0] == 'float32'
15361536

15371537
# check with mixed dtypes

pandas/tests/test_frame.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -10607,13 +10607,10 @@ def test_index_namedtuple(self):
1060710607
df = DataFrame([(1, 2), (3, 4)], index=index, columns=["A", "B"])
1060810608
self.assertEqual(df.ix[IndexType("foo", "bar")]["A"], 1)
1060910609

10610-
def test_bool_empty_nonzero(self):
10610+
def test_empty_nonzero(self):
1061110611
df = DataFrame([1, 2, 3])
10612-
self.assertTrue(bool(df))
1061310612
self.assertFalse(df.empty)
1061410613
df = DataFrame(index=['a', 'b'], columns=['c', 'd']).dropna()
10615-
self.assertFalse(bool(df))
10616-
self.assertFalse(bool(df.T))
1061710614
self.assertTrue(df.empty)
1061810615
self.assertTrue(df.T.empty)
1061910616

pandas/tests/test_generic.py

+46-4
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ def _construct(self, shape, value=None, **kwargs):
7373
arr = np.random.randn(*shape)
7474
return self._typ(arr,**kwargs)
7575

76-
7776
def _compare(self, result, expected):
7877
self._comparator(result,expected)
7978

@@ -82,14 +81,14 @@ def test_rename(self):
8281
# single axis
8382
for axis in self._axes():
8483
kwargs = { axis : list('ABCD') }
85-
o = self._construct(4,**kwargs)
84+
obj = self._construct(4,**kwargs)
8685

8786
# no values passed
8887
#self.assertRaises(Exception, o.rename(str.lower))
8988

9089
# rename a single axis
91-
result = o.rename(**{ axis : str.lower })
92-
expected = o.copy()
90+
result = obj.rename(**{ axis : str.lower })
91+
expected = obj.copy()
9392
setattr(expected,axis,list('abcd'))
9493
self._compare(result, expected)
9594

@@ -119,6 +118,41 @@ def test_get_numeric_data(self):
119118
self._compare(result, o)
120119

121120
# _get_numeric_data is includes _get_bool_data, so can't test for non-inclusion
121+
def test_nonzero(self):
122+
123+
# GH 4633
124+
# look at the boolean/nonzero behavior for objects
125+
obj = self._construct(shape=4)
126+
self.assertRaises(ValueError, lambda : bool(obj == 0))
127+
self.assertRaises(ValueError, lambda : bool(obj == 1))
128+
self.assertRaises(ValueError, lambda : bool(obj))
129+
130+
obj = self._construct(shape=4,value=1)
131+
self.assertRaises(ValueError, lambda : bool(obj == 0))
132+
self.assertRaises(ValueError, lambda : bool(obj == 1))
133+
self.assertRaises(ValueError, lambda : bool(obj))
134+
135+
obj = self._construct(shape=4,value=np.nan)
136+
self.assertRaises(ValueError, lambda : bool(obj == 0))
137+
self.assertRaises(ValueError, lambda : bool(obj == 1))
138+
self.assertRaises(ValueError, lambda : bool(obj))
139+
140+
# empty
141+
obj = self._construct(shape=0)
142+
self.assertRaises(ValueError, lambda : bool(obj))
143+
144+
# invalid behaviors
145+
146+
obj1 = self._construct(shape=4,value=1)
147+
obj2 = self._construct(shape=4,value=1)
148+
149+
def f():
150+
if obj1:
151+
print("this works and shouldn't")
152+
self.assertRaises(ValueError, f)
153+
self.assertRaises(ValueError, lambda : obj1 and obj2)
154+
self.assertRaises(ValueError, lambda : obj1 or obj2)
155+
self.assertRaises(ValueError, lambda : not obj1)
122156

123157
class TestSeries(unittest.TestCase, Generic):
124158
_typ = Series
@@ -154,6 +188,14 @@ def test_get_numeric_data_preserve_dtype(self):
154188
expected = Series([],dtype='M8[ns]')
155189
self._compare(result, expected)
156190

191+
def test_nonzero_single_element(self):
192+
193+
s = Series([True])
194+
self.assertRaises(ValueError, lambda : bool(s))
195+
196+
s = Series([False])
197+
self.assertRaises(ValueError, lambda : bool(s))
198+
157199
class TestDataFrame(unittest.TestCase, Generic):
158200
_typ = DataFrame
159201
_comparator = lambda self, x, y: assert_frame_equal(x,y)

pandas/tests/test_series.py

-6
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,6 @@ def test_scalar_conversion(self):
296296
self.assert_(int(Series([1.])) == 1)
297297
self.assert_(long(Series([1.])) == 1)
298298

299-
self.assert_(bool(Series([True])) == True)
300-
self.assert_(bool(Series([False])) == False)
301-
302-
self.assert_(bool(Series([True,True])) == True)
303-
self.assert_(bool(Series([False,True])) == True)
304-
305299
def test_astype(self):
306300
s = Series(np.random.randn(5),name='foo')
307301

pandas/tseries/tests/test_timeseries.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ def test_indexing(self):
256256
df = DataFrame(randn(5,5),columns=['open','high','low','close','volume'],index=date_range('2012-01-02 18:01:00',periods=5,tz='US/Central',freq='s'))
257257
expected = df.loc[[df.index[2]]]
258258
result = df['2012-01-02 18:01:02']
259-
self.assert_(result == expected)
259+
assert_frame_equal(result,expected)
260260

261261
# this is a single date, so will raise
262262
self.assertRaises(KeyError, df.__getitem__, df.index[2],)

0 commit comments

Comments
 (0)