diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index d22b4bd4d3f2b..69fa956b73f28 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -22,7 +22,6 @@ ensure_int64, ensure_object, ensure_platform_int, - is_categorical, is_categorical_dtype, is_datetime64_dtype, is_datetimelike, @@ -2659,18 +2658,18 @@ def _get_codes_for_values(values, categories): return coerce_indexer_dtype(t.lookup(vals), cats) -def _recode_for_categories(codes, old_categories, new_categories): +def _recode_for_categories(codes: np.ndarray, old_categories, new_categories): """ Convert a set of codes for to a new set of categories Parameters ---------- - codes : array + codes : np.ndarray old_categories, new_categories : Index Returns ------- - new_codes : array + new_codes : np.ndarray[np.int64] Examples -------- @@ -2725,17 +2724,15 @@ def _factorize_from_iterable(values): If `values` has a categorical dtype, then `categories` is a CategoricalIndex keeping the categories and order of `values`. """ - from pandas.core.indexes.category import CategoricalIndex - if not is_list_like(values): raise TypeError("Input must be list-like") - if is_categorical(values): - values = CategoricalIndex(values) - # The CategoricalIndex level we want to build has the same categories + if is_categorical_dtype(values): + values = extract_array(values) + # The Categorical we want to build has the same categories # as values but its codes are by def [0, ..., len(n_categories) - 1] cat_codes = np.arange(len(values.categories), dtype=values.codes.dtype) - categories = values._create_from_codes(cat_codes) + categories = Categorical.from_codes(cat_codes, dtype=values.dtype) codes = values.codes else: # The value of ordered is irrelevant since we don't use cat as such, diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 770870a466aa9..b3548a1dc20d6 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -161,8 +161,8 @@ def strftime(self, date_format): Returns ------- - Index - Index of formatted strings. + ndarray + NumPy ndarray of formatted strings. See Also -------- @@ -180,9 +180,7 @@ def strftime(self, date_format): 'March 10, 2018, 09:00:02 AM'], dtype='object') """ - from pandas import Index - - return Index(self._format_native_types(date_format=date_format)) + return self._format_native_types(date_format=date_format).astype(object) class TimelikeOps: @@ -1018,9 +1016,9 @@ def _add_delta_tdi(self, other): if isinstance(other, np.ndarray): # ndarray[timedelta64]; wrap in TimedeltaIndex for op - from pandas import TimedeltaIndex + from pandas.core.arrays import TimedeltaArray - other = TimedeltaIndex(other) + other = TimedeltaArray._from_sequence(other) self_i8 = self.asi8 other_i8 = other.asi8 diff --git a/pandas/core/arrays/sparse.py b/pandas/core/arrays/sparse.py index 47c7c72051150..476e2aa223d03 100644 --- a/pandas/core/arrays/sparse.py +++ b/pandas/core/arrays/sparse.py @@ -1781,11 +1781,11 @@ def sparse_arithmetic_method(self, other): @classmethod def _create_comparison_method(cls, op): - def cmp_method(self, other): - op_name = op.__name__ + op_name = op.__name__ + if op_name in {"and_", "or_"}: + op_name = op_name[:-1] - if op_name in {"and_", "or_"}: - op_name = op_name[:-1] + def cmp_method(self, other): if isinstance(other, (ABCSeries, ABCIndexClass)): # Rely on pandas to unbox and dispatch to us. diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 67de7b0196b8e..9f2b31f23d2fa 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -69,7 +69,7 @@ class DatetimeDelegateMixin(DatetimelikeDelegateMixin): # Some are "raw" methods, the result is not not re-boxed in an Index # We also have a few "extra" attrs, which may or may not be raw, # which we we dont' want to expose in the .dt accessor. - _extra_methods = ["to_period", "to_perioddelta", "to_julian_date"] + _extra_methods = ["to_period", "to_perioddelta", "to_julian_date", "strftime"] _extra_raw_methods = ["to_pydatetime", "_local_timestamps", "_has_same_tz"] _extra_raw_properties = ["_box_func", "tz", "tzinfo"] _delegated_properties = DatetimeArray._datetimelike_ops + _extra_raw_properties @@ -1184,7 +1184,6 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None): is_normalized = cache_readonly(DatetimeArray.is_normalized.fget) # type: ignore _resolution = cache_readonly(DatetimeArray._resolution.fget) # type: ignore - strftime = ea_passthrough(DatetimeArray.strftime) _has_same_tz = ea_passthrough(DatetimeArray._has_same_tz) @property diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index f6b3d1076043e..b0cc386f7783d 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -63,7 +63,10 @@ class PeriodDelegateMixin(DatetimelikeDelegateMixin): _delegate_class = PeriodArray _delegated_properties = PeriodArray._datetimelike_ops - _delegated_methods = set(PeriodArray._datetimelike_methods) | {"_addsub_int_array"} + _delegated_methods = set(PeriodArray._datetimelike_methods) | { + "_addsub_int_array", + "strftime", + } _raw_properties = {"is_leap_year"} diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index abc8a414eb37a..6af5dd6f1bf37 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -3202,7 +3202,9 @@ def read(self, start=None, stop=None, **kwargs): values = self.read_array( "block{idx}_values".format(idx=i), start=_start, stop=_stop ) - blk = make_block(values, placement=items.get_indexer(blk_items)) + blk = make_block( + values, placement=items.get_indexer(blk_items), ndim=len(axes) + ) blocks.append(blk) return self.obj_type(BlockManager(blocks, axes)) @@ -4462,7 +4464,7 @@ def read(self, where=None, columns=None, **kwargs): if values.ndim == 1 and isinstance(values, np.ndarray): values = values.reshape((1, values.shape[0])) - block = make_block(values, placement=np.arange(len(cols_))) + block = make_block(values, placement=np.arange(len(cols_)), ndim=2) mgr = BlockManager([block], [cols_, index_]) frames.append(DataFrame(mgr)) diff --git a/pandas/tests/arrays/test_datetimelike.py b/pandas/tests/arrays/test_datetimelike.py index ffda2f4de2700..0b3ccc0ae0e2d 100644 --- a/pandas/tests/arrays/test_datetimelike.py +++ b/pandas/tests/arrays/test_datetimelike.py @@ -462,6 +462,13 @@ def test_concat_same_type_different_freq(self): tm.assert_datetime_array_equal(result, expected) + def test_strftime(self, datetime_index): + arr = DatetimeArray(datetime_index) + + result = arr.strftime("%Y %b") + expected = np.array(datetime_index.strftime("%Y %b")) + tm.assert_numpy_array_equal(result, expected) + class TestTimedeltaArray(SharedTests): index_cls = pd.TimedeltaIndex @@ -652,6 +659,13 @@ def test_array_interface(self, period_index): expected = np.asarray(arr).astype("S20") tm.assert_numpy_array_equal(result, expected) + def test_strftime(self, period_index): + arr = PeriodArray(period_index) + + result = arr.strftime("%Y") + expected = np.array(period_index.strftime("%Y")) + tm.assert_numpy_array_equal(result, expected) + @pytest.mark.parametrize( "array,casting_nats", diff --git a/pandas/tests/arrays/test_integer.py b/pandas/tests/arrays/test_integer.py index 8fbfb4c12f4b2..50cd1469e5196 100644 --- a/pandas/tests/arrays/test_integer.py +++ b/pandas/tests/arrays/test_integer.py @@ -379,8 +379,6 @@ def test_compare_array(self, data, all_compare_operators): class TestCasting: - pass - @pytest.mark.parametrize("dropna", [True, False]) def test_construct_index(self, all_data, dropna): # ensure that we do not coerce to Float64Index, rather diff --git a/pandas/tests/series/test_period.py b/pandas/tests/series/test_period.py index 9b34b52bf39b9..4aeb211170d8f 100644 --- a/pandas/tests/series/test_period.py +++ b/pandas/tests/series/test_period.py @@ -71,10 +71,9 @@ def test_NaT_scalar(self): series[2] = val assert pd.isna(series[2]) - @pytest.mark.xfail(reason="PeriodDtype Series not supported yet") def test_NaT_cast(self): result = Series([np.nan]).astype("period[D]") - expected = Series([pd.NaT]) + expected = Series([pd.NaT], dtype="period[D]") tm.assert_series_equal(result, expected) def test_set_none(self):