Skip to content

Commit 712a085

Browse files
jbrockmendeljreback
authored andcommitted
CLN: miscellaneous cleanups / fixes (pandas-dev#21861)
1 parent 31fb39a commit 712a085

File tree

10 files changed

+49
-7
lines changed

10 files changed

+49
-7
lines changed

doc/source/whatsnew/v0.24.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ Datetimelike
301301
^^^^^^^^^^^^
302302

303303
- Fixed bug where two :class:`DateOffset` objects with different ``normalize`` attributes could evaluate as equal (:issue:`21404`)
304+
- Fixed bug where :meth:`Timestamp.resolution` incorrectly returned 1-microsecond ``timedelta`` instead of 1-nanosecond :class:`Timedelta` (:issue:`21336`,:issue:`21365`)
304305

305306
Timedelta
306307
^^^^^^^^^
@@ -369,6 +370,7 @@ Missing
369370
^^^^^^^
370371

371372
- Bug in :func:`DataFrame.fillna` where a ``ValueError`` would raise when one column contained a ``datetime64[ns, tz]`` dtype (:issue:`15522`)
373+
- Bug in :func:`Series.hasnans` that could be incorrectly cached and return incorrect answers if null elements are introduced after an initial call (:issue:`19700`)
372374

373375
MultiIndex
374376
^^^^^^^^^^

pandas/_libs/tslibs/timestamps.pyx

+9
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,15 @@ cdef class _Timestamp(datetime):
407407
def asm8(self):
408408
return np.datetime64(self.value, 'ns')
409409

410+
@property
411+
def resolution(self):
412+
"""
413+
Return resolution describing the smallest difference between two
414+
times that can be represented by Timestamp object_state
415+
"""
416+
# GH#21336, GH#21365
417+
return Timedelta(nanoseconds=1)
418+
410419
def timestamp(self):
411420
"""Return POSIX timestamp as float."""
412421
# py27 compat, see GH#17329

pandas/core/dtypes/inference.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,15 @@ def is_list_like(obj):
278278
False
279279
>>> is_list_like(1)
280280
False
281+
>>> is_list_like(np.array([2]))
282+
True
283+
>>> is_list_like(np.array(2)))
284+
False
281285
"""
282286

283287
return (isinstance(obj, Iterable) and
284-
not isinstance(obj, string_and_binary_types))
288+
not isinstance(obj, string_and_binary_types) and
289+
not (isinstance(obj, np.ndarray) and obj.ndim == 0))
285290

286291

287292
def is_array_like(obj):

pandas/core/frame.py

+3
Original file line numberDiff line numberDiff line change
@@ -7679,6 +7679,9 @@ def convert(v):
76797679
try:
76807680
if is_list_like(values[0]) or hasattr(values[0], 'len'):
76817681
values = np.array([convert(v) for v in values])
7682+
elif isinstance(values[0], np.ndarray) and values[0].ndim == 0:
7683+
# GH#21861
7684+
values = np.array([convert(v) for v in values])
76827685
else:
76837686
values = convert(values)
76847687
except:

pandas/core/indexes/datetimes.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def _dt_index_cmp(opname, cls):
9393
def wrapper(self, other):
9494
func = getattr(super(DatetimeIndex, self), opname)
9595

96-
if isinstance(other, (datetime, compat.string_types)):
96+
if isinstance(other, (datetime, np.datetime64, compat.string_types)):
9797
if isinstance(other, datetime):
9898
# GH#18435 strings get a pass from tzawareness compat
9999
self._assert_tzawareness_compat(other)
@@ -105,8 +105,7 @@ def wrapper(self, other):
105105
else:
106106
if isinstance(other, list):
107107
other = DatetimeIndex(other)
108-
elif not isinstance(other, (np.datetime64, np.ndarray,
109-
Index, ABCSeries)):
108+
elif not isinstance(other, (np.ndarray, Index, ABCSeries)):
110109
# Following Timestamp convention, __eq__ is all-False
111110
# and __ne__ is all True, others raise TypeError.
112111
if opname == '__eq__':

pandas/core/series.py

+4
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ class Series(base.IndexOpsMixin, generic.NDFrame):
166166
['asobject', 'sortlevel', 'reshape', 'get_value', 'set_value',
167167
'from_csv', 'valid'])
168168

169+
# Override cache_readonly bc Series is mutable
170+
hasnans = property(base.IndexOpsMixin.hasnans.func,
171+
doc=base.IndexOpsMixin.hasnans.__doc__)
172+
169173
def __init__(self, data=None, index=None, dtype=None, name=None,
170174
copy=False, fastpath=False):
171175

pandas/core/tools/timedeltas.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def to_timedelta(arg, unit='ns', box=True, errors='raise'):
8585
elif isinstance(arg, ABCIndexClass):
8686
return _convert_listlike(arg, unit=unit, box=box,
8787
errors=errors, name=arg.name)
88-
elif is_list_like(arg) and getattr(arg, 'ndim', 1) == 0:
88+
elif isinstance(arg, np.ndarray) and arg.ndim == 0:
8989
# extract array scalar and process below
9090
arg = arg.item()
9191
elif is_list_like(arg) and getattr(arg, 'ndim', 1) == 1:

pandas/tests/dtypes/test_inference.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ def __getitem__(self):
6767
[
6868
[], [1], (1, ), (1, 2), {'a': 1},
6969
set([1, 'a']), Series([1]),
70-
Series([]), Series(['a']).str])
70+
Series([]), Series(['a']).str,
71+
np.array([2])])
7172
def test_is_list_like_passes(ll):
7273
assert inference.is_list_like(ll)
7374

7475

7576
@pytest.mark.parametrize(
76-
"ll", [1, '2', object(), str])
77+
"ll", [1, '2', object(), str, np.array(2)])
7778
def test_is_list_like_fails(ll):
7879
assert not inference.is_list_like(ll)
7980

pandas/tests/scalar/timestamp/test_timestamp.py

+5
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ def test_woy_boundary(self):
172172
2005, 1, 1), (2005, 1, 2)]])
173173
assert (result == [52, 52, 53, 53]).all()
174174

175+
def test_resolution(self):
176+
# GH#21336, GH#21365
177+
dt = Timestamp('2100-01-01 00:00:00')
178+
assert dt.resolution == Timedelta(nanoseconds=1)
179+
175180

176181
class TestTimestampConstructors(object):
177182

pandas/tests/series/test_internals.py

+14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from pandas import Series
1212
from pandas.core.indexes.datetimes import Timestamp
1313
import pandas._libs.lib as lib
14+
import pandas as pd
1415

1516
from pandas.util.testing import assert_series_equal
1617
import pandas.util.testing as tm
@@ -309,3 +310,16 @@ def test_convert_preserve_all_bool(self):
309310
r = s._convert(datetime=True, numeric=True)
310311
e = Series([False, True, False, False], dtype=bool)
311312
tm.assert_series_equal(r, e)
313+
314+
315+
def test_hasnans_unchached_for_series():
316+
# GH#19700
317+
idx = pd.Index([0, 1])
318+
assert not idx.hasnans
319+
assert 'hasnans' in idx._cache
320+
ser = idx.to_series()
321+
assert not ser.hasnans
322+
assert not hasattr(ser, '_cache')
323+
ser.iloc[-1] = np.nan
324+
assert ser.hasnans
325+
assert pd.Series.hasnans.__doc__ == pd.Index.hasnans.__doc__

0 commit comments

Comments
 (0)