Skip to content

Commit

Permalink
BUG: Raise when casting NaT to int (pandas-dev#28492)
Browse files Browse the repository at this point in the history
* BUG: Raise when casting NaT to int

* Add release note

* Add PR number

* Use isna

* Parametrize test

* Check all integer dtypes

* Fix merge

* Edit release note

* Check for np.int64

* Handle timedelta64

* Add astype_nansafe datetime tests

* Add test for NaT object casting
  • Loading branch information
dsaxton authored and hweecat committed Jan 1, 2020
1 parent 7b0714c commit f4d3806
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,7 @@ Datetimelike
- Bug in :class:`Timestamp` subtraction when subtracting a :class:`Timestamp` from a ``np.datetime64`` object incorrectly raising ``TypeError`` (:issue:`28286`)
- Addition and subtraction of integer or integer-dtype arrays with :class:`Timestamp` will now raise ``NullFrequencyError`` instead of ``ValueError`` (:issue:`28268`)
- Bug in :class:`Series` and :class:`DataFrame` with integer dtype failing to raise ``TypeError`` when adding or subtracting a ``np.datetime64`` object (:issue:`28080`)
- Bug in :meth:`Series.astype`, :meth:`Index.astype`, and :meth:`DataFrame.astype` failing to handle ``NaT`` when casting to an integer dtype (:issue:`28492`)
- Bug in :class:`Week` with ``weekday`` incorrectly raising ``AttributeError`` instead of ``TypeError`` when adding or subtracting an invalid type (:issue:`28530`)
- Bug in :class:`DataFrame` arithmetic operations when operating with a :class:`Series` with dtype `'timedelta64[ns]'` (:issue:`28049`)
- Bug in :func:`pandas.core.groupby.generic.SeriesGroupBy.apply` raising ``ValueError`` when a column in the original DataFrame is a datetime and the column labels are not standard integers (:issue:`28247`)
Expand Down
4 changes: 4 additions & 0 deletions pandas/core/dtypes/cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,8 @@ def astype_nansafe(arr, dtype, copy: bool = True, skipna: bool = False):
if is_object_dtype(dtype):
return tslib.ints_to_pydatetime(arr.view(np.int64))
elif dtype == np.int64:
if isna(arr).any():
raise ValueError("Cannot convert NaT values to integer")
return arr.view(dtype)

# allow frequency conversions
Expand All @@ -835,6 +837,8 @@ def astype_nansafe(arr, dtype, copy: bool = True, skipna: bool = False):
if is_object_dtype(dtype):
return tslibs.ints_to_pytimedelta(arr.view(np.int64))
elif dtype == np.int64:
if isna(arr).any():
raise ValueError("Cannot convert NaT values to integer")
return arr.view(dtype)

if dtype not in [_INT64_DTYPE, _TD_DTYPE]:
Expand Down
41 changes: 41 additions & 0 deletions pandas/tests/dtypes/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import pandas.util._test_decorators as td

from pandas.core.dtypes.cast import astype_nansafe
import pandas.core.dtypes.common as com
from pandas.core.dtypes.dtypes import (
CategoricalDtype,
Expand All @@ -13,6 +14,7 @@
IntervalDtype,
PeriodDtype,
)
from pandas.core.dtypes.missing import isna

import pandas as pd
from pandas.conftest import (
Expand Down Expand Up @@ -709,3 +711,42 @@ def test__get_dtype_fails(input_param, expected_error_message):
)
def test__is_dtype_type(input_param, result):
assert com._is_dtype_type(input_param, lambda tipo: tipo == result)


@pytest.mark.parametrize("val", [np.datetime64("NaT"), np.timedelta64("NaT")])
@pytest.mark.parametrize("typ", [np.int64])
def test_astype_nansafe(val, typ):
arr = np.array([val])

msg = "Cannot convert NaT values to integer"
with pytest.raises(ValueError, match=msg):
astype_nansafe(arr, dtype=typ)


@pytest.mark.parametrize("from_type", [np.datetime64, np.timedelta64])
@pytest.mark.parametrize(
"to_type",
[
np.uint8,
np.uint16,
np.uint32,
np.int8,
np.int16,
np.int32,
np.float16,
np.float32,
],
)
def test_astype_datetime64_bad_dtype_raises(from_type, to_type):
arr = np.array([from_type("2018")])

with pytest.raises(TypeError, match="cannot astype"):
astype_nansafe(arr, dtype=to_type)


@pytest.mark.parametrize("from_type", [np.datetime64, np.timedelta64])
def test_astype_object_preserves_datetime_na(from_type):
arr = np.array([from_type("NaT")])
result = astype_nansafe(arr, dtype="object")

assert isna(result)[0]

0 comments on commit f4d3806

Please sign in to comment.