Skip to content

Commit 3ac9d08

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 3ac9d08

File tree

3 files changed

+113
-7
lines changed

3 files changed

+113
-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

+11
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,13 @@ 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+
# No exception should be raised.
88+
89+
assert not com.is_string_dtype(None)
90+
assert not com.is_string_like_dtype(None)
91+
assert not com.is_dtype_equal(None, None)
92+
assert not com.is_datetime64_ns_dtype(None)
93+
assert not com.is_timedelta64_ns_dtype(None)

pandas/types/common.py

+101-7
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,39 @@ 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+
try:
176+
dtype = _get_dtype(arr_or_dtype)
177+
return dtype.kind in ('O', 'S', 'U') and not is_period_dtype(dtype)
178+
except TypeError:
179+
return False
149180

150181

151182
def is_period_arraylike(arr):
@@ -237,8 +268,40 @@ def is_datetime64_ns_dtype(arr_or_dtype):
237268

238269

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

243306

244307
def is_datetime_or_timedelta_dtype(arr_or_dtype):
@@ -342,9 +405,40 @@ 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+
is_string_dtype : Whether or not the array or
422+
dtype is of the string dtype.
423+
424+
Examples
425+
--------
426+
>>> is_string_like_dtype(str)
427+
True
428+
>>> is_string_like_dtype(object)
429+
False
430+
>>>
431+
>>> is_string_like_dtype(np.array(['a', 'b']))
432+
True
433+
>>> is_string_like_dtype(np.array([1, 2]))
434+
False
435+
"""
436+
437+
try:
438+
dtype = _get_dtype(arr_or_dtype)
439+
return dtype.kind in ('S', 'U')
440+
except TypeError:
441+
return False
348442

349443

350444
def is_float_dtype(arr_or_dtype):

0 commit comments

Comments
 (0)