Skip to content

Commit 9777867

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 327d561 commit 9777867

File tree

3 files changed

+123
-9
lines changed

3 files changed

+123
-9
lines changed

doc/source/whatsnew/v0.20.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,7 @@ Conversion
11441144
- Bug in ``DataFrame.fillna()`` where the argument ``downcast`` was ignored when fillna value was of type ``dict`` (:issue:`15277`)
11451145
- Bug in ``.asfreq()``, where frequency was not set for empty ``Series`` (:issue:`14320`)
11461146
- Bug in ``DataFrame`` construction with nulls and datetimes in a list-like (:issue:`15869`)
1147+
- 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`)
11471148

11481149
Indexing
11491150
^^^^^^^^

pandas/tests/types/test_common.py

+20
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,22 @@ 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+
get_dtype_funcs = [
87+
(com.is_dtype_equal, 2),
88+
(com.is_string_dtype, 1),
89+
(com.is_string_like_dtype, 1),
90+
(com.is_datetime64_ns_dtype, 1),
91+
(com.is_timedelta64_ns_dtype, 1)
92+
]
93+
94+
95+
@pytest.mark.parametrize('func,none_count',
96+
get_dtype_funcs)
97+
def test_get_dtype_error_catch(func, none_count):
98+
# see gh-15941
99+
#
100+
# No exception should be raised.
101+
102+
assert not func(*[None] * none_count)

pandas/types/common.py

+102-9
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,40 @@ 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+
boolean : Whether or not the array or dtype is of the string dtype.
158+
159+
Examples
160+
--------
161+
>>> is_string_dtype(str)
162+
True
163+
>>> is_string_dtype(object)
164+
True
165+
>>> is_string_dtype(int)
166+
False
167+
>>>
168+
>>> is_string_dtype(np.array(['a', 'b']))
169+
True
170+
>>> is_string_dtype(np.array([1, 2]))
171+
False
172+
"""
173+
174+
# TODO: gh-15585: consider making the checks stricter.
175+
176+
try:
177+
dtype = _get_dtype(arr_or_dtype)
178+
return dtype.kind in ('O', 'S', 'U') and not is_period_dtype(dtype)
179+
except TypeError:
180+
return False
149181

150182

151183
def is_period_arraylike(arr):
@@ -237,8 +269,40 @@ def is_datetime64_ns_dtype(arr_or_dtype):
237269

238270

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

243307

244308
def is_datetime_or_timedelta_dtype(arr_or_dtype):
@@ -260,8 +324,7 @@ def _is_unorderable_exception(e):
260324
261325
Returns
262326
-------
263-
is_orderable_exc : Whether or not the exception raised is an
264-
unorderable exception.
327+
boolean : Whether or not the exception raised is an unorderable exception.
265328
"""
266329

267330
if PY36:
@@ -342,9 +405,39 @@ def is_numeric_dtype(arr_or_dtype):
342405

343406

344407
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')
408+
"""
409+
Check whether the provided array or dtype is of a string-like dtype.
410+
411+
Unlike `is_string_dtype`, the object dtype is excluded because it
412+
is a mixed dtype.
413+
414+
Parameters
415+
----------
416+
arr_or_dtype : ndarray, dtype, type
417+
The array or dtype to check.
418+
419+
Returns
420+
-------
421+
boolean : Whether or not the array or dtype is of the string dtype.
422+
423+
Examples
424+
--------
425+
>>> is_string_like_dtype(str)
426+
True
427+
>>> is_string_like_dtype(object)
428+
False
429+
>>>
430+
>>> is_string_like_dtype(np.array(['a', 'b']))
431+
True
432+
>>> is_string_like_dtype(np.array([1, 2]))
433+
False
434+
"""
435+
436+
try:
437+
dtype = _get_dtype(arr_or_dtype)
438+
return dtype.kind in ('S', 'U')
439+
except TypeError:
440+
return False
348441

349442

350443
def is_float_dtype(arr_or_dtype):

0 commit comments

Comments
 (0)