From 5f7ae5e3091f21e24b266e2e603bd0d18f95bb2e Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 5 May 2020 09:22:27 -0700 Subject: [PATCH 01/11] CLN: remove unused out-of-bounds handling --- pandas/_libs/tslibs/conversion.pyx | 2 +- pandas/tseries/offsets.py | 87 ++++++++++-------------------- 2 files changed, 30 insertions(+), 59 deletions(-) diff --git a/pandas/_libs/tslibs/conversion.pyx b/pandas/_libs/tslibs/conversion.pyx index 5a8d0a0ec1670..6dd5b4b2fa798 100644 --- a/pandas/_libs/tslibs/conversion.pyx +++ b/pandas/_libs/tslibs/conversion.pyx @@ -265,7 +265,7 @@ cdef convert_to_tsobject(object ts, object tz, object unit, ts = ts except OverflowError: # GH#26651 re-raise as OutOfBoundsDatetime - raise OutOfBoundsDatetime(ts) + raise OutOfBoundsDatetime(f"Out of bounds nanosecond timestamp {ts}") if ts == NPY_NAT: obj.value = NPY_NAT else: diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index c1ab752bf9550..e1de9d1bcf832 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -8,7 +8,6 @@ from pandas._libs.tslibs import ( NaT, - OutOfBoundsDatetime, Period, Timedelta, Timestamp, @@ -16,9 +15,7 @@ conversion, delta_to_nanoseconds, frequencies as libfrequencies, - normalize_date, offsets as liboffsets, - timezones, ) from pandas._libs.tslibs.offsets import ( ApplyTypeError, @@ -76,73 +73,47 @@ "DateOffset", ] -# convert to/from datetime/timestamp to allow invalid Timestamp ranges to -# pass thru - - -def as_timestamp(obj): - if isinstance(obj, Timestamp): - return obj - try: - return Timestamp(obj) - except (OutOfBoundsDatetime): - pass - return obj - def apply_wraps(func): @functools.wraps(func) def wrapper(self, other): if other is NaT: return NaT - elif isinstance(other, (timedelta, Tick, DateOffset)): + elif isinstance(other, (timedelta, DateOffset)): # timedelta path return func(self, other) elif isinstance(other, (np.datetime64, datetime, date)): - other = as_timestamp(other) - - tz = getattr(other, "tzinfo", None) - nano = getattr(other, "nanosecond", 0) - - try: - if self._adjust_dst and isinstance(other, Timestamp): - other = other.tz_localize(None) - - result = func(self, other) - - if self._adjust_dst: - result = conversion.localize_pydatetime(result, tz) + other = Timestamp(other) + else: + raise TypeError(other) - result = Timestamp(result) - if self.normalize: - result = result.normalize() + tz = other.tzinfo + nano = other.nanosecond - # nanosecond may be deleted depending on offset process - if not self.normalize and nano != 0: - if not isinstance(self, Nano) and result.nanosecond != nano: - if result.tz is not None: - # convert to UTC - value = conversion.tz_convert_single( - result.value, timezones.UTC, result.tz - ) - else: - value = result.value - result = Timestamp(value + nano) + if self._adjust_dst: + other = other.tz_localize(None) - if tz is not None and result.tzinfo is None: - result = conversion.localize_pydatetime(result, tz) + result = func(self, other) - except OutOfBoundsDatetime: - result = func(self, as_datetime(other)) + result = Timestamp(result) + if self._adjust_dst: + result = result.tz_localize(tz) - if self.normalize: - # normalize_date returns normal datetime - result = normalize_date(result) + if self.normalize: + result = result.normalize() - if tz is not None and result.tzinfo is None: - result = conversion.localize_pydatetime(result, tz) + # nanosecond may be deleted depending on offset process + if not self.normalize and nano != 0: + if not isinstance(self, Nano) and result.nanosecond != nano: + if result.tz is not None: + # convert to UTC + value = result.tz_localize(None).value + else: + value = result.value + result = Timestamp(value + nano) - result = Timestamp(result) + if tz is not None and result.tzinfo is None: + result = result.tz_localize(tz) return result @@ -290,7 +261,7 @@ def apply(self, other): # bring tz back from UTC calculation other = conversion.localize_pydatetime(other, tzinfo) - return as_timestamp(other) + return Timestamp(other) else: return other + timedelta(self.n) @@ -394,7 +365,7 @@ def rollback(self, dt): TimeStamp Rolled timestamp if not on offset, otherwise unchanged timestamp. """ - dt = as_timestamp(dt) + dt = Timestamp(dt) if not self.is_on_offset(dt): dt = dt - type(self)(1, normalize=self.normalize, **self.kwds) return dt @@ -408,7 +379,7 @@ def rollforward(self, dt): TimeStamp Rolled timestamp if not on offset, otherwise unchanged timestamp. """ - dt = as_timestamp(dt) + dt = Timestamp(dt) if not self.is_on_offset(dt): dt = dt + type(self)(1, normalize=self.normalize, **self.kwds) return dt @@ -2505,7 +2476,7 @@ def apply(self, other): raise OverflowError return result elif isinstance(other, (datetime, np.datetime64, date)): - return as_timestamp(other) + self + return Timestamp(other) + self if isinstance(other, timedelta): return other + self.delta From 1b958df184820aa3e340b26e632b9fba710c7f91 Mon Sep 17 00:00:00 2001 From: Vikas Pandey Date: Tue, 5 May 2020 14:36:17 +0530 Subject: [PATCH 02/11] DOC: update conf.py to use new numpy doc url (#33954) --- doc/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index d2404b757ca11..ee0d4ca3f2a24 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -410,7 +410,7 @@ intersphinx_mapping = { "dateutil": ("https://dateutil.readthedocs.io/en/latest/", None), "matplotlib": ("https://matplotlib.org/", None), - "numpy": ("https://docs.scipy.org/doc/numpy/", None), + "numpy": ("https://numpy.org/doc/stable/", None), "pandas-gbq": ("https://pandas-gbq.readthedocs.io/en/latest/", None), "py": ("https://pylib.readthedocs.io/en/latest/", None), "python": ("https://docs.python.org/3/", None), From d09e5e18e0ff193bab7e29906ad9e1d1af041e0b Mon Sep 17 00:00:00 2001 From: Kaiqi Dong Date: Tue, 5 May 2020 14:23:17 +0200 Subject: [PATCH 03/11] DEPR: Deprecate try_sort (#33902) --- pandas/core/common.py | 8 -------- pandas/core/indexes/api.py | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/pandas/core/common.py b/pandas/core/common.py index 8b152162dc95a..bb911c0617242 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -200,14 +200,6 @@ def count_not_none(*args) -> int: return sum(x is not None for x in args) -def try_sort(iterable): - listed = list(iterable) - try: - return sorted(listed) - except TypeError: - return listed - - def asarray_tuplesafe(values, dtype=None): if not (isinstance(values, (list, tuple)) or hasattr(values, "__array__")): diff --git a/pandas/core/indexes/api.py b/pandas/core/indexes/api.py index 0a23d38ace37e..fcce82e7a69db 100644 --- a/pandas/core/indexes/api.py +++ b/pandas/core/indexes/api.py @@ -256,8 +256,7 @@ def _sanitize_and_check(indexes): if list in kinds: if len(kinds) > 1: indexes = [ - Index(com.try_sort(x)) if not isinstance(x, Index) else x - for x in indexes + Index(list(x)) if not isinstance(x, Index) else x for x in indexes ] kinds.remove(list) else: From 4c69b74b4d9204275cca6867c03195fc31f85da7 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 5 May 2020 09:18:00 -0500 Subject: [PATCH 04/11] Fix expected dtype in test_reindex_with_same_tz (#33969) --- pandas/tests/indexes/datetimes/test_datetime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/datetimes/test_datetime.py b/pandas/tests/indexes/datetimes/test_datetime.py index 50983dbd8db22..ec4162f87010f 100644 --- a/pandas/tests/indexes/datetimes/test_datetime.py +++ b/pandas/tests/indexes/datetimes/test_datetime.py @@ -53,7 +53,7 @@ def test_reindex_with_same_tz(self): expected1 = DatetimeIndex( expected_list1, dtype="datetime64[ns, UTC]", freq=None, ) - expected2 = np.array([0] + [-1] * 21 + [23], dtype=np.int64,) + expected2 = np.array([0] + [-1] * 21 + [23], dtype=np.dtype("intp")) tm.assert_index_equal(result1, expected1) tm.assert_numpy_array_equal(result2, expected2) From 5bce7f2d2529c64edd68ddeb3fc00ac0c53a3011 Mon Sep 17 00:00:00 2001 From: kota matsuoka Date: Tue, 5 May 2020 23:18:57 +0900 Subject: [PATCH 05/11] BUG: fix memory_usage method with deep of StringArray (#33985) --- doc/source/whatsnew/v1.1.0.rst | 1 + pandas/core/arrays/string_.py | 6 ++++++ pandas/tests/arrays/string_/test_string.py | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index c3396a73f62ed..816ef4e5c9eb6 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -758,6 +758,7 @@ ExtensionArray - Fixed bug where :meth:`Series.value_counts` would raise on empty input of ``Int64`` dtype (:issue:`33317`) - Fixed bug in :class:`Series` construction with EA dtype and index but no data or scalar data fails (:issue:`26469`) - Fixed bug that caused :meth:`Series.__repr__()` to crash for extension types whose elements are multidimensional arrays (:issue:`33770`). +- Fixed bug where :meth:`StringArray.memory_usage` was not implemented (:issue:`33963`) Other diff --git a/pandas/core/arrays/string_.py b/pandas/core/arrays/string_.py index 51bbe182a002b..537b1cf3dd439 100644 --- a/pandas/core/arrays/string_.py +++ b/pandas/core/arrays/string_.py @@ -292,6 +292,12 @@ def value_counts(self, dropna=False): return value_counts(self._ndarray, dropna=dropna).astype("Int64") + def memory_usage(self, deep=False): + result = self._ndarray.nbytes + if deep: + return result + lib.memory_usage_of_objects(self._ndarray) + return result + # Override parent because we have different return types. @classmethod def _create_arithmetic_method(cls, op): diff --git a/pandas/tests/arrays/string_/test_string.py b/pandas/tests/arrays/string_/test_string.py index eb89798a1ad96..b681abf03a2b3 100644 --- a/pandas/tests/arrays/string_/test_string.py +++ b/pandas/tests/arrays/string_/test_string.py @@ -303,3 +303,10 @@ def test_value_counts_na(): result = arr.value_counts(dropna=True) expected = pd.Series([2, 1], index=["a", "b"], dtype="Int64") tm.assert_series_equal(result, expected) + + +def test_memory_usage(): + # GH 33963 + series = pd.Series(["a", "b", "c"], dtype="string") + + assert 0 < series.nbytes <= series.memory_usage() < series.memory_usage(deep=True) From 2606589e03894cc8d9a889c9042b2824be9c60c3 Mon Sep 17 00:00:00 2001 From: Daniel Saxton <2658661+dsaxton@users.noreply.github.com> Date: Tue, 5 May 2020 11:27:24 -0500 Subject: [PATCH 06/11] BUG: Fix Series.update ExtensionArray issue (#33984) --- doc/source/whatsnew/v1.1.0.rst | 1 + pandas/core/internals/blocks.py | 2 +- pandas/tests/series/methods/test_update.py | 24 ++++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 816ef4e5c9eb6..9c424f70b1ee0 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -758,6 +758,7 @@ ExtensionArray - Fixed bug where :meth:`Series.value_counts` would raise on empty input of ``Int64`` dtype (:issue:`33317`) - Fixed bug in :class:`Series` construction with EA dtype and index but no data or scalar data fails (:issue:`26469`) - Fixed bug that caused :meth:`Series.__repr__()` to crash for extension types whose elements are multidimensional arrays (:issue:`33770`). +- Fixed bug where :meth:`Series.update` would raise a ``ValueError`` for ``ExtensionArray`` dtypes with missing values (:issue:`33980`) - Fixed bug where :meth:`StringArray.memory_usage` was not implemented (:issue:`33963`) diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index d028d840448ea..e4dcffae45f67 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1599,7 +1599,7 @@ def putmask( new_values = self.values if inplace else self.values.copy() - if isinstance(new, np.ndarray) and len(new) == len(mask): + if isinstance(new, (np.ndarray, ExtensionArray)) and len(new) == len(mask): new = new[mask] mask = _safe_reshape(mask, new_values.shape) diff --git a/pandas/tests/series/methods/test_update.py b/pandas/tests/series/methods/test_update.py index 98959599569a9..9cb6d8f81fff7 100644 --- a/pandas/tests/series/methods/test_update.py +++ b/pandas/tests/series/methods/test_update.py @@ -74,3 +74,27 @@ def test_update_from_non_series(self, series, other, expected): # GH 33215 series.update(other) tm.assert_series_equal(series, expected) + + @pytest.mark.parametrize( + "result, target, expected", + [ + ( + Series(["a", None], dtype="string"), + Series([None, "b"], dtype="string"), + Series(["a", "b"], dtype="string"), + ), + ( + Series([1, None], dtype="Int64"), + Series([None, 2], dtype="Int64"), + Series([1, 2], dtype="Int64"), + ), + ( + Series([True, None], dtype="boolean"), + Series([None, False], dtype="boolean"), + Series([True, False], dtype="boolean"), + ), + ], + ) + def test_update_extension_array_series(self, result, target, expected): + result.update(target) + tm.assert_series_equal(result, expected) From 4add5dbc5144ab43d9992466a0303d95714a1553 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 5 May 2020 09:45:39 -0700 Subject: [PATCH 07/11] PERF: make _Tick into a cdef class (#33979) --- pandas/_libs/tslibs/offsets.pxd | 2 ++ pandas/_libs/tslibs/offsets.pyx | 24 +++++++++++++++++++----- pandas/compat/pickle_compat.py | 7 +++++++ pandas/io/pickle.py | 3 ++- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/pandas/_libs/tslibs/offsets.pxd b/pandas/_libs/tslibs/offsets.pxd index 5a553be537e52..e75cd8bdf1baf 100644 --- a/pandas/_libs/tslibs/offsets.pxd +++ b/pandas/_libs/tslibs/offsets.pxd @@ -1 +1,3 @@ cdef to_offset(object obj) +cdef bint is_offset_object(object obj) +cdef bint is_tick_object(object obj) diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 3dfaa36888f62..9fbe717fa8c2c 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -86,6 +86,14 @@ for _d in DAYS: # --------------------------------------------------------------------- # Misc Helpers +cdef bint is_offset_object(object obj): + return isinstance(obj, _BaseOffset) + + +cdef bint is_tick_object(object obj): + return isinstance(obj, _Tick) + + cdef to_offset(object obj): """ Wrap pandas.tseries.frequencies.to_offset to keep centralize runtime @@ -608,7 +616,7 @@ class BaseOffset(_BaseOffset): return -self + other -class _Tick: +cdef class _Tick: """ dummy class to mix into tseries.offsets.Tick so that in tslibs.period we can do isinstance checks on _Tick and avoid importing tseries.offsets @@ -618,12 +626,18 @@ class _Tick: __array_priority__ = 1000 def __truediv__(self, other): - result = self.delta.__truediv__(other) + if not isinstance(self, _Tick): + # cython semantics mean the args are sometimes swapped + result = other.delta.__rtruediv__(self) + else: + result = self.delta.__truediv__(other) return _wrap_timedelta_result(result) - def __rtruediv__(self, other): - result = self.delta.__rtruediv__(other) - return _wrap_timedelta_result(result) + def __reduce__(self): + return (type(self), (self.n,)) + + def __setstate__(self, state): + object.__setattr__(self, "n", state["n"]) class BusinessMixin: diff --git a/pandas/compat/pickle_compat.py b/pandas/compat/pickle_compat.py index 3f4acca8bce18..cd2ded874c08c 100644 --- a/pandas/compat/pickle_compat.py +++ b/pandas/compat/pickle_compat.py @@ -9,6 +9,8 @@ from pandas import Index +from pandas.tseries.offsets import Tick + if TYPE_CHECKING: from pandas import Series, DataFrame @@ -38,6 +40,11 @@ def load_reduce(self): return except TypeError: pass + elif args and issubclass(args[0], Tick): + # TypeError: object.__new__(Day) is not safe, use Day.__new__() + cls = args[0] + stack[-1] = cls.__new__(*args) + return raise diff --git a/pandas/io/pickle.py b/pandas/io/pickle.py index 6faebf56a11ab..3b35b54a6dc16 100644 --- a/pandas/io/pickle.py +++ b/pandas/io/pickle.py @@ -173,7 +173,8 @@ def read_pickle( # 3) try pickle_compat with latin-1 encoding upon a UnicodeDecodeError try: - excs_to_catch = (AttributeError, ImportError, ModuleNotFoundError) + excs_to_catch = (AttributeError, ImportError, ModuleNotFoundError, TypeError) + # TypeError for Cython complaints about object.__new__ vs Tick.__new__ try: with warnings.catch_warnings(record=True): # We want to silence any warnings about, e.g. moved modules. From b8bdd70f3d7abd3fec40afd9e71613b060b1657e Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 5 May 2020 10:17:54 -0700 Subject: [PATCH 08/11] BUG: CategoricalIndex.__contains__ incorrect NaTs (#33947) --- pandas/core/arrays/categorical.py | 4 +- pandas/core/indexes/category.py | 5 +-- .../indexes/categorical/test_indexing.py | 37 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 0c9db271edf37..9cdb5dfc47776 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -37,7 +37,7 @@ from pandas.core.dtypes.dtypes import CategoricalDtype from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries from pandas.core.dtypes.inference import is_hashable -from pandas.core.dtypes.missing import isna, notna +from pandas.core.dtypes.missing import is_valid_nat_for_dtype, isna, notna from pandas.core import ops from pandas.core.accessor import PandasDelegate, delegate_names @@ -1834,7 +1834,7 @@ def __contains__(self, key) -> bool: Returns True if `key` is in this Categorical. """ # if key is a NaN, check if any NaN is in self. - if is_scalar(key) and isna(key): + if is_valid_nat_for_dtype(key, self.categories.dtype): return self.isna().any() return contains(self, key, container=self._codes) diff --git a/pandas/core/indexes/category.py b/pandas/core/indexes/category.py index 0cf6698d316bb..80d3e5c8a0dbe 100644 --- a/pandas/core/indexes/category.py +++ b/pandas/core/indexes/category.py @@ -19,7 +19,7 @@ is_scalar, ) from pandas.core.dtypes.dtypes import CategoricalDtype -from pandas.core.dtypes.missing import isna +from pandas.core.dtypes.missing import is_valid_nat_for_dtype, isna from pandas.core import accessor from pandas.core.algorithms import take_1d @@ -365,10 +365,9 @@ def _has_complex_internals(self) -> bool: @doc(Index.__contains__) def __contains__(self, key: Any) -> bool: # if key is a NaN, check if any NaN is in self. - if is_scalar(key) and isna(key): + if is_valid_nat_for_dtype(key, self.categories.dtype): return self.hasnans - hash(key) return contains(self, key, container=self._engine) @doc(Index.astype) diff --git a/pandas/tests/indexes/categorical/test_indexing.py b/pandas/tests/indexes/categorical/test_indexing.py index a36568bbbe633..9cf901c0797d8 100644 --- a/pandas/tests/indexes/categorical/test_indexing.py +++ b/pandas/tests/indexes/categorical/test_indexing.py @@ -285,6 +285,43 @@ def test_contains_nan(self): ci = CategoricalIndex(list("aabbca") + [np.nan], categories=list("cabdef")) assert np.nan in ci + @pytest.mark.parametrize("unwrap", [True, False]) + def test_contains_na_dtype(self, unwrap): + dti = pd.date_range("2016-01-01", periods=100).insert(0, pd.NaT) + pi = dti.to_period("D") + tdi = dti - dti[-1] + ci = CategoricalIndex(dti) + + obj = ci + if unwrap: + obj = ci._data + + assert np.nan in obj + assert None in obj + assert pd.NaT in obj + assert np.datetime64("NaT") in obj + assert np.timedelta64("NaT") not in obj + + obj2 = CategoricalIndex(tdi) + if unwrap: + obj2 = obj2._data + + assert np.nan in obj2 + assert None in obj2 + assert pd.NaT in obj2 + assert np.datetime64("NaT") not in obj2 + assert np.timedelta64("NaT") in obj2 + + obj3 = CategoricalIndex(pi) + if unwrap: + obj3 = obj3._data + + assert np.nan in obj3 + assert None in obj3 + assert pd.NaT in obj3 + assert np.datetime64("NaT") not in obj3 + assert np.timedelta64("NaT") not in obj3 + @pytest.mark.parametrize( "item, expected", [ From a2a15821ce8490000e290185e8348b0567b027b0 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 5 May 2020 15:56:28 -0700 Subject: [PATCH 09/11] CLN: remove normalize_date --- pandas/core/arrays/datetimes.py | 11 +++--- pandas/tests/tslibs/test_api.py | 1 - pandas/tests/tslibs/test_normalize_date.py | 41 ---------------------- 3 files changed, 6 insertions(+), 47 deletions(-) delete mode 100644 pandas/tests/tslibs/test_normalize_date.py diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index f7408e69f7dec..8a1cacfe304ca 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -1,5 +1,5 @@ from datetime import datetime, time, timedelta -from typing import Union +from typing import Optional, Union import warnings import numpy as np @@ -13,7 +13,6 @@ conversion, fields, iNaT, - normalize_date, resolution as libresolution, timezones, tzconversion, @@ -2288,19 +2287,21 @@ def _infer_tz_from_endpoints(start, end, tz): return tz -def _maybe_normalize_endpoints(start, end, normalize): +def _maybe_normalize_endpoints( + start: Optional[Timestamp], end: Optional[Timestamp], normalize: bool +): _normalized = True if start is not None: if normalize: - start = normalize_date(start) + start = start.normalize() _normalized = True else: _normalized = _normalized and start.time() == _midnight if end is not None: if normalize: - end = normalize_date(end) + end = end.normalize() _normalized = True else: _normalized = _normalized and end.time() == _midnight diff --git a/pandas/tests/tslibs/test_api.py b/pandas/tests/tslibs/test_api.py index 7a8a6d511aa69..a4c2e3f0787d0 100644 --- a/pandas/tests/tslibs/test_api.py +++ b/pandas/tests/tslibs/test_api.py @@ -38,7 +38,6 @@ def test_namespace(): "delta_to_nanoseconds", "ints_to_pytimedelta", "localize_pydatetime", - "normalize_date", "tz_convert_single", ] diff --git a/pandas/tests/tslibs/test_normalize_date.py b/pandas/tests/tslibs/test_normalize_date.py deleted file mode 100644 index 2a41836f456ec..0000000000000 --- a/pandas/tests/tslibs/test_normalize_date.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Tests for functions from pandas._libs.tslibs""" - -from datetime import date, datetime - -import pytest - -from pandas._libs import tslibs -from pandas._libs.tslibs.timestamps import Timestamp - - -@pytest.mark.parametrize( - "value,expected", - [ - (date(2012, 9, 7), datetime(2012, 9, 7)), - (datetime(2012, 9, 7, 12), datetime(2012, 9, 7)), - (datetime(2007, 10, 1, 1, 12, 5, 10), datetime(2007, 10, 1)), - ], -) -def test_normalize_date(value, expected): - result = tslibs.normalize_date(value) - assert result == expected - - -class SubDatetime(datetime): - pass - - -@pytest.mark.parametrize( - "dt, expected", - [ - (Timestamp(2000, 1, 1, 1), Timestamp(2000, 1, 1, 0)), - (datetime(2000, 1, 1, 1), datetime(2000, 1, 1, 0)), - (SubDatetime(2000, 1, 1, 1), SubDatetime(2000, 1, 1, 0)), - ], -) -def test_normalize_date_sub_types(dt, expected): - # GH 25851 - # ensure that subclassed datetime works with - # normalize_date - result = tslibs.normalize_date(dt) - assert result == expected From 59a4acfe76f6513fd31cb00b2b7e529928c7965b Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 5 May 2020 15:58:46 -0700 Subject: [PATCH 10/11] remove import --- pandas/_libs/tslibs/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/tslibs/__init__.py b/pandas/_libs/tslibs/__init__.py index 4a4e53eaa45fa..c16728922ee42 100644 --- a/pandas/_libs/tslibs/__init__.py +++ b/pandas/_libs/tslibs/__init__.py @@ -17,7 +17,7 @@ ] -from .conversion import localize_pydatetime, normalize_date +from .conversion import localize_pydatetime from .nattype import NaT, NaTType, iNaT, is_null_datetimelike from .np_datetime import OutOfBoundsDatetime from .period import IncompatibleFrequency, Period From eac1bc3f43ff9f591d37f49e14d3d9d302518db5 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Tue, 5 May 2020 17:38:06 -0700 Subject: [PATCH 11/11] update __all__ --- pandas/_libs/tslibs/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/_libs/tslibs/__init__.py b/pandas/_libs/tslibs/__init__.py index c16728922ee42..47b35aa6eabff 100644 --- a/pandas/_libs/tslibs/__init__.py +++ b/pandas/_libs/tslibs/__init__.py @@ -1,6 +1,5 @@ __all__ = [ "localize_pydatetime", - "normalize_date", "NaT", "NaTType", "iNaT",