Skip to content

Commit 5fcc3cf

Browse files
committed
BUG: Catch TypeError when calling _get_dtype
The following functions were not catching the TypeError raised by _get_dtype: 1) is_string_dtype 2) is_string_like_dtype 3) is_timedelta64_ns_dtype Thus, when "None" was passed in, an Exception was raised instead of returning False, as other functions did.
1 parent 2b19fc8 commit 5fcc3cf

File tree

3 files changed

+117
-7
lines changed

3 files changed

+117
-7
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1068,6 +1068,7 @@ Conversion
10681068
- Bug in ``DataFrame.fillna()`` where the argument ``downcast`` was ignored when fillna value was of type ``dict`` (:issue:`15277`)
10691069
- Bug in ``.asfreq()``, where frequency was not set for empty ``Series`` (:issue:`14320`)
10701070
- Bug in ``DataFrame`` construction with nulls and datetimes in a list-like (:issue:`15869`)
1071+
- Bug in ``is_string_dtype``, ``is_timedelta64_ns_dtype``, and ``is_string_like_dtype`` in which an error was raised when ``None`` was passed in (:issue:`15941`)
10711072

10721073
Indexing
10731074
^^^^^^^^

pandas/tests/types/test_common.py

+13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from pandas.types.dtypes import DatetimeTZDtype, PeriodDtype, CategoricalDtype
77
from pandas.types.common import pandas_dtype, is_dtype_equal
88

9+
import pandas.types.common as com
910
import pandas.util.testing as tm
1011

1112

@@ -80,3 +81,15 @@ def test_dtype_equal_strict():
8081
assert not is_dtype_equal(
8182
pandas_dtype('datetime64[ns, US/Eastern]'),
8283
pandas_dtype('datetime64[ns, CET]'))
84+
85+
86+
def test_get_dtype_error_catch():
87+
# see gh-15941
88+
#
89+
# No exception should be raised.
90+
91+
assert not com.is_string_dtype(None)
92+
assert not com.is_string_like_dtype(None)
93+
assert not com.is_dtype_equal(None, None)
94+
assert not com.is_datetime64_ns_dtype(None)
95+
assert not com.is_timedelta64_ns_dtype(None)

pandas/types/common.py

+103-7
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,41 @@ def is_categorical_dtype(arr_or_dtype):
144144

145145

146146
def is_string_dtype(arr_or_dtype):
147-
dtype = _get_dtype(arr_or_dtype)
148-
return dtype.kind in ('O', 'S', 'U') and not is_period_dtype(dtype)
147+
"""
148+
Check whether the provided array or dtype is of the string dtype.
149+
150+
Parameters
151+
----------
152+
arr_or_dtype : ndarray, dtype, type
153+
The array or dtype to check.
154+
155+
Returns
156+
-------
157+
is_string_dtype : Whether or not the array or
158+
dtype is of the string dtype.
159+
160+
Examples
161+
--------
162+
>>> is_string_dtype(str)
163+
True
164+
>>> is_string_dtype(object)
165+
True
166+
>>> is_string_dtype(int)
167+
False
168+
>>>
169+
>>> is_string_dtype(np.array(['a', 'b']))
170+
True
171+
>>> is_string_dtype(np.array([1, 2]))
172+
False
173+
"""
174+
175+
# TODO: gh-15585: consider making the checks stricter.
176+
177+
try:
178+
dtype = _get_dtype(arr_or_dtype)
179+
return dtype.kind in ('O', 'S', 'U') and not is_period_dtype(dtype)
180+
except TypeError:
181+
return False
149182

150183

151184
def is_period_arraylike(arr):
@@ -237,8 +270,40 @@ def is_datetime64_ns_dtype(arr_or_dtype):
237270

238271

239272
def is_timedelta64_ns_dtype(arr_or_dtype):
240-
tipo = _get_dtype(arr_or_dtype)
241-
return tipo == _TD_DTYPE
273+
"""
274+
Check whether the provided array or dtype is of the timedelta64[ns] dtype.
275+
276+
This is a very specific dtype, so generic ones like `np.timedelta64`
277+
will return False if passed into this function.
278+
279+
Parameters
280+
----------
281+
arr_or_dtype : ndarray, dtype, type
282+
The array or dtype to check.
283+
284+
Returns
285+
-------
286+
is_timedelta64_ns_dtype : Whether or not the array or dtype
287+
is of the timedelta64[ns] dtype.
288+
289+
Examples
290+
--------
291+
>>> is_timedelta64_ns_dtype(np.dtype('m8[ns]')
292+
True
293+
>>> is_timedelta64_ns_dtype(np.dtype('m8[ps]') # Wrong frequency
294+
False
295+
>>>
296+
>>> is_timedelta64_ns_dtype(np.array([1, 2], dtype='m8[ns]'))
297+
True
298+
>>> is_timedelta64_ns_dtype(np.array([1, 2], dtype=np.timedelta64))
299+
False
300+
"""
301+
302+
try:
303+
tipo = _get_dtype(arr_or_dtype)
304+
return tipo == _TD_DTYPE
305+
except TypeError:
306+
return False
242307

243308

244309
def is_datetime_or_timedelta_dtype(arr_or_dtype):
@@ -342,9 +407,40 @@ def is_numeric_dtype(arr_or_dtype):
342407

343408

344409
def is_string_like_dtype(arr_or_dtype):
345-
# exclude object as its a mixed dtype
346-
dtype = _get_dtype(arr_or_dtype)
347-
return dtype.kind in ('S', 'U')
410+
"""
411+
Check whether the provided array or dtype is of a string-like dtype.
412+
413+
Unlike `is_string_dtype`, the object dtype is excluded because it
414+
is a mixed dtype.
415+
416+
Parameters
417+
----------
418+
arr_or_dtype : ndarray, dtype, type
419+
The array or dtype to check.
420+
421+
Returns
422+
-------
423+
is_string_dtype : Whether or not the array or
424+
dtype is of the string dtype.
425+
426+
Examples
427+
--------
428+
>>> is_string_like_dtype(str)
429+
True
430+
>>> is_string_like_dtype(object)
431+
False
432+
>>>
433+
>>> is_string_like_dtype(np.array(['a', 'b']))
434+
True
435+
>>> is_string_like_dtype(np.array([1, 2]))
436+
False
437+
"""
438+
439+
try:
440+
dtype = _get_dtype(arr_or_dtype)
441+
return dtype.kind in ('S', 'U')
442+
except TypeError:
443+
return False
348444

349445

350446
def is_float_dtype(arr_or_dtype):

0 commit comments

Comments
 (0)