Skip to content

Commit 24c7c7f

Browse files
committed
Merge pull request pandas-dev#4765 from cpcloud/series-isin-fix
API: raise a TypeError when isin is passed a string
2 parents b15a376 + 500fad8 commit 24c7c7f

File tree

6 files changed

+63
-4
lines changed

6 files changed

+63
-4
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ Indexing, iteration
451451
DataFrame.pop
452452
DataFrame.tail
453453
DataFrame.xs
454+
DataFrame.isin
454455

455456
Binary operator functions
456457
~~~~~~~~~~~~~~~~~~~~~~~~~

doc/source/release.rst

+3
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ pandas 0.13
148148
behavior.
149149
- ``DataFrame.update()`` no longer raises a ``DataConflictError``, it now
150150
will raise a ``ValueError`` instead (if necessary) (:issue:`4732`)
151+
- ``Series.isin()`` and ``DataFrame.isin()`` now raise a ``TypeError`` when
152+
passed a string (:issue:`4763`). Pass a ``list`` of one element (containing
153+
the string) instead.
151154

152155
**Internal Refactoring**
153156

pandas/core/frame.py

+5
Original file line numberDiff line numberDiff line change
@@ -4609,6 +4609,11 @@ def isin(self, values, iloc=False):
46094609

46104610

46114611
else:
4612+
if not com.is_list_like(values):
4613+
raise TypeError("only list-like or dict-like objects are"
4614+
" allowed to be passed to DataFrame.isin(), "
4615+
"you passed a "
4616+
"{0!r}".format(type(values).__name__))
46124617
return DataFrame(lib.ismember(self.values.ravel(),
46134618
set(values)).reshape(self.shape),
46144619
self.index,

pandas/core/series.py

+34-4
Original file line numberDiff line numberDiff line change
@@ -2805,17 +2805,47 @@ def take(self, indices, axis=0, convert=True):
28052805

28062806
def isin(self, values):
28072807
"""
2808-
Return boolean vector showing whether each element in the Series is
2809-
exactly contained in the passed sequence of values
2808+
Return a boolean :ref:`~pandas.Series` showing whether each element in
2809+
the ref:`~pandas.Series` is exactly contained in the passed sequence of
2810+
``values``.
28102811
28112812
Parameters
28122813
----------
2813-
values : sequence
2814+
values : list-like
2815+
The sequence of values to test. Passing in a single string will
2816+
raise a ``TypeError``:
2817+
2818+
.. code-block:: python
2819+
2820+
from pandas import Series
2821+
s = Series(list('abc'))
2822+
s.isin('a')
2823+
2824+
Instead, turn a single string into a ``list`` of one element:
2825+
2826+
.. code-block:: python
2827+
2828+
from pandas import Series
2829+
s = Series(list('abc'))
2830+
s.isin(['a'])
28142831
28152832
Returns
28162833
-------
2817-
isin : Series (boolean dtype)
2834+
isin : Series (bool dtype)
2835+
2836+
Raises
2837+
------
2838+
TypeError
2839+
* If ``values`` is a string
2840+
2841+
See Also
2842+
--------
2843+
pandas.DataFrame.isin
28182844
"""
2845+
if not com.is_list_like(values):
2846+
raise TypeError("only list-like objects are allowed to be passed"
2847+
" to Series.isin(), you passed a "
2848+
"{0!r}".format(type(values).__name__))
28192849
value_set = set(values)
28202850
result = lib.ismember(_values_from_object(self), value_set)
28212851
return self._constructor(result, self.index, name=self.name)

pandas/tests/test_frame.py

+10
Original file line numberDiff line numberDiff line change
@@ -10915,6 +10915,16 @@ def test_isin_dict(self):
1091510915
expected.iloc[0, 0] = True
1091610916
assert_frame_equal(result, expected)
1091710917

10918+
def test_isin_with_string_scalar(self):
10919+
#GH4763
10920+
df = DataFrame({'vals': [1, 2, 3, 4], 'ids': ['a', 'b', 'f', 'n'],
10921+
'ids2': ['a', 'n', 'c', 'n']},
10922+
index=['foo', 'bar', 'baz', 'qux'])
10923+
with tm.assertRaises(TypeError):
10924+
df.isin('a')
10925+
10926+
with tm.assertRaises(TypeError):
10927+
df.isin('aaa')
1091810928

1091910929
if __name__ == '__main__':
1092010930
# unittest.main()

pandas/tests/test_series.py

+10
Original file line numberDiff line numberDiff line change
@@ -4433,6 +4433,16 @@ def test_isin(self):
44334433
expected = Series([True, False, True, False, False, False, True, True])
44344434
assert_series_equal(result, expected)
44354435

4436+
def test_isin_with_string_scalar(self):
4437+
#GH4763
4438+
s = Series(['A', 'B', 'C', 'a', 'B', 'B', 'A', 'C'])
4439+
with tm.assertRaises(TypeError):
4440+
s.isin('a')
4441+
4442+
with tm.assertRaises(TypeError):
4443+
s = Series(['aaa', 'b', 'c'])
4444+
s.isin('aaa')
4445+
44364446
def test_fillna_int(self):
44374447
s = Series(np.random.randint(-100, 100, 50))
44384448
s.fillna(method='ffill', inplace=True)

0 commit comments

Comments
 (0)