Skip to content

Commit

Permalink
rebase & cleanup, fixup some edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
jreback committed May 21, 2017
1 parent 04ad63f commit 405f9f1
Show file tree
Hide file tree
Showing 13 changed files with 383 additions and 340 deletions.
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v0.21.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ Bug Fixes
Conversion
^^^^^^^^^^

- Bug in assignment against datetime-like data with ``int`` may incorrectly converted to datetime-like (:issue:`14145`)
- Inconsistent behavior in ``.where()`` with datetimelikes which would raise rather than coerce to ``object`` (:issue:`16402`)
- Bug in assignment against datetime-like data with ``int`` may incorrectly convert to datetime-like (:issue:`14145`)
- Bug in assignment against ``int64`` data with ``np.ndarray`` with ``float64`` dtype may keep ``int64`` dtype (:issue:`14001`)


Expand Down
19 changes: 13 additions & 6 deletions pandas/_libs/index.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ cimport tslib
from hashtable cimport *
from pandas._libs import tslib, algos, hashtable as _hash
from pandas._libs.tslib import Timestamp, Timedelta
from datetime import datetime, timedelta

from datetime cimport (get_datetime64_value, _pydatetime_to_dts,
pandas_datetimestruct)
Expand Down Expand Up @@ -507,24 +508,30 @@ cdef class TimedeltaEngine(DatetimeEngine):
return 'm8[ns]'

cpdef convert_scalar(ndarray arr, object value):
# we don't turn intgers
# into datetimes/timedeltas

if arr.descr.type_num == NPY_DATETIME:
if isinstance(value, np.ndarray):
pass
elif isinstance(value, Timestamp):
return value.value
elif isinstance(value, datetime):
return Timestamp(value).value
elif value is None or value != value:
return iNaT
else:
elif util.is_string_object(value):
return Timestamp(value).value
raise ValueError("cannot set a Timestamp with a non-timestamp")

elif arr.descr.type_num == NPY_TIMEDELTA:
if isinstance(value, np.ndarray):
pass
elif isinstance(value, Timedelta):
return value.value
elif isinstance(value, timedelta):
return Timedelta(value).value
elif value is None or value != value:
return iNaT
else:
elif util.is_string_object(value):
return Timedelta(value).value
raise ValueError("cannot set a Timedelta with a non-timedelta")

if issubclass(arr.dtype.type, (np.integer, np.bool_)):
if util.is_float_object(value) and value != value:
Expand Down
18 changes: 15 additions & 3 deletions pandas/core/dtypes/cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import warnings

from pandas._libs import tslib, lib
from pandas._libs.tslib import iNaT
from pandas._libs.tslib import iNaT, Timestamp
from pandas.compat import string_types, text_type, PY3
from .common import (_ensure_object, is_bool, is_integer, is_float,
is_complex, is_datetimetz, is_categorical_dtype,
Expand Down Expand Up @@ -1028,13 +1028,25 @@ def find_common_type(types):
return np.find_common_type(types, [])


def _cast_scalar_to_array(shape, value, dtype=None):
def cast_scalar_to_array(shape, value, dtype=None):
"""
create np.ndarray of specified shape and dtype, filled with values
Parameters
----------
shape : tuple
value : scalar value
dtype : np.dtype, optional
dtype to coerce
Returns
-------
ndarray of shape, filled with value, of specified / inferred dtype
"""

if dtype is None:
dtype, fill_value = _infer_dtype_from_scalar(value)
dtype, fill_value = infer_dtype_from_scalar(value)
else:
fill_value = value

Expand Down
11 changes: 6 additions & 5 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@
import numpy.ma as ma

from pandas.core.dtypes.cast import (
maybe_upcast, infer_dtype_from_scalar,
maybe_upcast,
maybe_cast_to_datetime,
maybe_infer_to_datetimelike,
maybe_convert_platform,
maybe_downcast_to_dtype,
invalidate_string_dtypes,
coerce_to_dtypes,
maybe_upcast_putmask,
cast_scalar_to_array,
find_common_type)
from pandas.core.dtypes.common import (
is_categorical_dtype,
Expand Down Expand Up @@ -343,8 +344,8 @@ def __init__(self, data=None, index=None, columns=None, dtype=None,
raise_with_traceback(exc)

if arr.ndim == 0 and index is not None and columns is not None:
values = _cast_scalar_to_array((len(index), len(columns)),
data, dtype=dtype)
values = cast_scalar_to_array((len(index), len(columns)),
data, dtype=dtype)
mgr = self._init_ndarray(values, index, columns,
dtype=values.dtype, copy=False)
else:
Expand Down Expand Up @@ -2734,8 +2735,8 @@ def reindexer(value):

else:
# upcast the scalar
value = _cast_scalar_to_array(len(self.index), value)
value = _possibly_cast_to_datetime(value, value.dtype)
value = cast_scalar_to_array(len(self.index), value)
value = maybe_cast_to_datetime(value, value.dtype)

# return internal types directly
if is_extension_type(value):
Expand Down
43 changes: 0 additions & 43 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from pandas._libs import tslib, lib
from pandas.core.dtypes.common import (
_ensure_int64,
needs_i8_conversion,
is_scalar,
is_number,
is_integer, is_bool,
Expand Down Expand Up @@ -5030,48 +5029,6 @@ def _where(self, cond, other=np.nan, inplace=False, axis=None, level=None,
raise NotImplemented("cannot align with a higher dimensional "
"NDFrame")

elif is_list_like(other):

if self.ndim == 1:

# try to set the same dtype as ourselves
try:
new_other = np.array(other, dtype=self.dtype)
except ValueError:
new_other = np.array(other)
except TypeError:
new_other = other

# we can end up comparing integers and m8[ns]
# which is a numpy no no
is_i8 = needs_i8_conversion(self.dtype)
if is_i8:
matches = False
else:
matches = (new_other == np.array(other))

if matches is False or not matches.all():

# coerce other to a common dtype if we can
if needs_i8_conversion(self.dtype):
try:
other = np.array(other, dtype=self.dtype)
except:
other = np.array(other)
else:
other = np.asarray(other)
other = np.asarray(other,
dtype=np.common_type(other,
new_other))

# we need to use the new dtype
try_quick = False
else:
other = new_other
else:

other = np.array(other)

if isinstance(other, np.ndarray):

if other.shape != self.shape:
Expand Down
Loading

0 comments on commit 405f9f1

Please sign in to comment.