From 79b4b9763944bd0030d2aa3d847a12d05e5ca65d Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 12 Nov 2021 09:59:55 -0800 Subject: [PATCH] TST: collect/share Index tests --- pandas/tests/frame/indexing/test_setitem.py | 13 ++ .../tests/indexes/base_class/test_formats.py | 14 ++ pandas/tests/indexes/common.py | 60 -------- .../tests/indexes/datetimes/test_formats.py | 17 +++ .../tests/indexes/datetimes/test_indexing.py | 63 ++------- .../tests/indexes/interval/test_indexing.py | 35 +++++ .../tests/indexes/interval/test_interval.py | 37 ----- pandas/tests/indexes/interval/test_pickle.py | 13 ++ pandas/tests/indexes/multi/test_compat.py | 7 - pandas/tests/indexes/multi/test_pickle.py | 10 ++ pandas/tests/indexes/period/test_indexing.py | 8 -- pandas/tests/indexes/test_any_index.py | 6 + pandas/tests/indexes/test_base.py | 131 +----------------- pandas/tests/indexes/test_common.py | 64 ++++++++- pandas/tests/indexes/test_index_new.py | 92 ++++++++++++ .../tests/indexes/timedeltas/test_indexing.py | 8 -- pandas/tests/indexing/test_datetime.py | 15 +- pandas/tests/indexing/test_indexing.py | 46 +++--- pandas/tests/indexing/test_scalar.py | 7 + pandas/tests/series/indexing/test_getitem.py | 6 + 20 files changed, 311 insertions(+), 341 deletions(-) create mode 100644 pandas/tests/indexes/interval/test_pickle.py create mode 100644 pandas/tests/indexes/multi/test_pickle.py diff --git a/pandas/tests/frame/indexing/test_setitem.py b/pandas/tests/frame/indexing/test_setitem.py index d735f0dbec8a5..b202ec6d9365c 100644 --- a/pandas/tests/frame/indexing/test_setitem.py +++ b/pandas/tests/frame/indexing/test_setitem.py @@ -44,6 +44,19 @@ class TestDataFrameSetItem: + def test_setitem_str_subclass(self): + # GH#37366 + class mystring(str): + pass + + data = ["2020-10-22 01:21:00+00:00"] + index = DatetimeIndex(data) + df = DataFrame({"a": [1]}, index=index) + df["b"] = 2 + df[mystring("c")] = 3 + expected = DataFrame({"a": [1], "b": [2], mystring("c"): [3]}, index=index) + tm.assert_equal(df, expected) + @pytest.mark.parametrize("dtype", ["int32", "int64", "float32", "float64"]) def test_setitem_dtype(self, dtype, float_frame): arr = np.random.randn(len(float_frame)) diff --git a/pandas/tests/indexes/base_class/test_formats.py b/pandas/tests/indexes/base_class/test_formats.py index f07b06acbfbdb..9053d45dee623 100644 --- a/pandas/tests/indexes/base_class/test_formats.py +++ b/pandas/tests/indexes/base_class/test_formats.py @@ -122,6 +122,14 @@ def test_repr_summary(self): assert len(result) < 200 assert "..." in result + def test_summary_bug(self): + # GH#3869 + ind = Index(["{other}%s", "~:{range}:0"], name="A") + result = ind._summary() + # shouldn't be formatted accidentally. + assert "~:{range}:0" in result + assert "{other}%s" in result + def test_index_repr_bool_nan(self): # GH32146 arr = Index([True, False, np.nan], dtype=object) @@ -132,3 +140,9 @@ def test_index_repr_bool_nan(self): exp2 = repr(arr) out2 = "Index([True, False, nan], dtype='object')" assert out2 == exp2 + + def test_format_different_scalar_lengths(self): + # GH#35439 + idx = Index(["aaaaaaaaa", "b"]) + expected = ["aaaaaaaaa", "b"] + assert idx.format() == expected diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 33d2558613baf..a5ee743b5cd9a 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -69,26 +69,6 @@ def test_pickle_compat_construction(self): with pytest.raises(TypeError, match=msg): self._index_cls() - @pytest.mark.parametrize("name", [None, "new_name"]) - def test_to_frame(self, name, simple_index): - # see GH-15230, GH-22580 - idx = simple_index - - if name: - idx_name = name - else: - idx_name = idx.name or 0 - - df = idx.to_frame(name=idx_name) - - assert df.index is idx - assert len(df.columns) == 1 - assert df.columns[0] == idx_name - assert df[idx_name].values is not idx.values - - df = idx.to_frame(index=False, name=idx_name) - assert df.index is not idx - def test_shift(self, simple_index): # GH8083 test the base class for shift @@ -226,46 +206,6 @@ def test_repr_max_seq_item_setting(self, simple_index): repr(idx) assert "..." not in str(idx) - def test_copy_name(self, index): - # gh-12309: Check that the "name" argument - # passed at initialization is honored. - if isinstance(index, MultiIndex): - return - - first = type(index)(index, copy=True, name="mario") - second = type(first)(first, copy=False) - - # Even though "copy=False", we want a new object. - assert first is not second - - # Not using tm.assert_index_equal() since names differ. - assert index.equals(first) - - assert first.name == "mario" - assert second.name == "mario" - - s1 = Series(2, index=first) - s2 = Series(3, index=second[:-1]) - - if not isinstance(index, CategoricalIndex): - # See gh-13365 - s3 = s1 * s2 - assert s3.index.name == "mario" - - def test_copy_name2(self, index): - # gh-35592 - if isinstance(index, MultiIndex): - return - - assert index.copy(name="mario").name == "mario" - - with pytest.raises(ValueError, match="Length of new names must be 1, got 2"): - index.copy(name=["mario", "luigi"]) - - msg = f"{type(index).__name__}.name must be a hashable type" - with pytest.raises(TypeError, match=msg): - index.copy(name=[["mario"]]) - def test_ensure_copied_data(self, index): # Check the "copy" argument of each Index.__new__ is honoured # GH12309 diff --git a/pandas/tests/indexes/datetimes/test_formats.py b/pandas/tests/indexes/datetimes/test_formats.py index 36046aaeacaae..197038dbadaf7 100644 --- a/pandas/tests/indexes/datetimes/test_formats.py +++ b/pandas/tests/indexes/datetimes/test_formats.py @@ -254,3 +254,20 @@ def test_dti_custom_business_summary_dateutil(self): pd.bdate_range( "1/1/2005", "1/1/2009", freq="C", tz=dateutil.tz.tzutc() )._summary() + + +class TestFormat: + def test_format_with_name_time_info(self): + # bug I fixed 12/20/2011 + dates = pd.date_range("2011-01-01 04:00:00", periods=10, name="something") + + formatted = dates.format(name=True) + assert formatted[0] == "something" + + def test_format_datetime_with_time(self): + dti = DatetimeIndex([datetime(2012, 2, 7), datetime(2012, 2, 7, 23)]) + + result = dti.format() + expected = ["2012-02-07 00:00:00", "2012-02-07 23:00:00"] + assert len(result) == 2 + assert result == expected diff --git a/pandas/tests/indexes/datetimes/test_indexing.py b/pandas/tests/indexes/datetimes/test_indexing.py index c3152b77d39df..beca71969dfcd 100644 --- a/pandas/tests/indexes/datetimes/test_indexing.py +++ b/pandas/tests/indexes/datetimes/test_indexing.py @@ -21,25 +21,12 @@ ) import pandas._testing as tm -from pandas.tseries.offsets import ( - BDay, - CDay, -) +from pandas.tseries.frequencies import to_offset START, END = datetime(2009, 1, 1), datetime(2010, 1, 1) class TestGetItem: - def test_ellipsis(self): - # GH#21282 - idx = date_range( - "2011-01-01", "2011-01-31", freq="D", tz="Asia/Tokyo", name="idx" - ) - - result = idx[...] - assert result.equals(idx) - assert result is not idx - def test_getitem_slice_keeps_name(self): # GH4226 st = Timestamp("2013-07-01 00:00:00", tz="America/Los_Angeles") @@ -88,44 +75,17 @@ def test_getitem(self): tm.assert_index_equal(result, expected) assert result.freq == expected.freq - def test_dti_business_getitem(self): - rng = bdate_range(START, END) - smaller = rng[:5] - exp = DatetimeIndex(rng.view(np.ndarray)[:5], freq="B") - tm.assert_index_equal(smaller, exp) - assert smaller.freq == exp.freq - - assert smaller.freq == rng.freq - - sliced = rng[::5] - assert sliced.freq == BDay() * 5 - - fancy_indexed = rng[[4, 3, 2, 1, 0]] - assert len(fancy_indexed) == 5 - assert isinstance(fancy_indexed, DatetimeIndex) - assert fancy_indexed.freq is None - - # 32-bit vs. 64-bit platforms - assert rng[4] == rng[np.int_(4)] - - def test_dti_business_getitem_matplotlib_hackaround(self): - rng = bdate_range(START, END) - with tm.assert_produces_warning(FutureWarning): - # GH#30588 multi-dimensional indexing deprecated - values = rng[:, None] - expected = rng.values[:, None] - tm.assert_numpy_array_equal(values, expected) - - def test_dti_custom_getitem(self): - rng = bdate_range(START, END, freq="C") + @pytest.mark.parametrize("freq", ["B", "C"]) + def test_dti_business_getitem(self, freq): + rng = bdate_range(START, END, freq=freq) smaller = rng[:5] - exp = DatetimeIndex(rng.view(np.ndarray)[:5], freq="C") + exp = DatetimeIndex(rng.view(np.ndarray)[:5], freq=freq) tm.assert_index_equal(smaller, exp) assert smaller.freq == exp.freq assert smaller.freq == rng.freq sliced = rng[::5] - assert sliced.freq == CDay() * 5 + assert sliced.freq == to_offset(freq) * 5 fancy_indexed = rng[[4, 3, 2, 1, 0]] assert len(fancy_indexed) == 5 @@ -135,8 +95,9 @@ def test_dti_custom_getitem(self): # 32-bit vs. 64-bit platforms assert rng[4] == rng[np.int_(4)] - def test_dti_custom_getitem_matplotlib_hackaround(self): - rng = bdate_range(START, END, freq="C") + @pytest.mark.parametrize("freq", ["B", "C"]) + def test_dti_business_getitem_matplotlib_hackaround(self, freq): + rng = bdate_range(START, END, freq=freq) with tm.assert_produces_warning(FutureWarning): # GH#30588 multi-dimensional indexing deprecated values = rng[:, None] @@ -255,6 +216,12 @@ def test_where_tz(self): class TestTake: + def test_take_nan_first_datetime(self): + index = DatetimeIndex([pd.NaT, Timestamp("20130101"), Timestamp("20130102")]) + result = index.take([-1, 0, 1]) + expected = DatetimeIndex([index[-1], index[0], index[1]]) + tm.assert_index_equal(result, expected) + def test_take(self): # GH#10295 idx1 = date_range("2011-01-01", "2011-01-31", freq="D", name="idx") diff --git a/pandas/tests/indexes/interval/test_indexing.py b/pandas/tests/indexes/interval/test_indexing.py index 8df8eef69e9c9..f12f32724b9e1 100644 --- a/pandas/tests/indexes/interval/test_indexing.py +++ b/pandas/tests/indexes/interval/test_indexing.py @@ -11,6 +11,7 @@ Interval, IntervalIndex, NaT, + Series, Timedelta, date_range, timedelta_range, @@ -523,3 +524,37 @@ def test_putmask_td64(self): result = idx.putmask(mask, idx[-1]) expected = IntervalIndex([idx[-1]] * 3 + list(idx[3:])) tm.assert_index_equal(result, expected) + + +class TestGetValue: + @pytest.mark.parametrize("key", [[5], (2, 3)]) + def test_get_value_non_scalar_errors(self, key): + # GH#31117 + idx = IntervalIndex.from_tuples([(1, 3), (2, 4), (3, 5), (7, 10), (3, 10)]) + ser = Series(range(len(idx)), index=idx) + + msg = str(key) + with pytest.raises(InvalidIndexError, match=msg): + with tm.assert_produces_warning(FutureWarning): + idx.get_value(ser, key) + + +class TestContains: + # .__contains__, not .contains + + def test_contains_dunder(self): + + index = IntervalIndex.from_arrays([0, 1], [1, 2], closed="right") + + # __contains__ requires perfect matches to intervals. + assert 0 not in index + assert 1 not in index + assert 2 not in index + + assert Interval(0, 1, closed="right") in index + assert Interval(0, 2, closed="right") not in index + assert Interval(0, 0.5, closed="right") not in index + assert Interval(3, 5, closed="right") not in index + assert Interval(-1, 0, closed="left") not in index + assert Interval(0, 1, closed="left") not in index + assert Interval(0, 1, closed="both") not in index diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index 321d1aa34b9af..843885832690f 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -4,8 +4,6 @@ import numpy as np import pytest -from pandas.errors import InvalidIndexError - import pandas as pd from pandas import ( Index, @@ -500,23 +498,6 @@ def test_contains_method(self): ): i.contains(Interval(0, 1)) - def test_contains_dunder(self): - - index = IntervalIndex.from_arrays([0, 1], [1, 2], closed="right") - - # __contains__ requires perfect matches to intervals. - assert 0 not in index - assert 1 not in index - assert 2 not in index - - assert Interval(0, 1, closed="right") in index - assert Interval(0, 2, closed="right") not in index - assert Interval(0, 0.5, closed="right") not in index - assert Interval(3, 5, closed="right") not in index - assert Interval(-1, 0, closed="left") not in index - assert Interval(0, 1, closed="left") not in index - assert Interval(0, 1, closed="both") not in index - def test_dropna(self, closed): expected = IntervalIndex.from_tuples([(0.0, 1.0), (1.0, 2.0)], closed=closed) @@ -908,24 +889,6 @@ def test_is_all_dates(self): year_2017_index = IntervalIndex([year_2017]) assert not year_2017_index._is_all_dates - @pytest.mark.parametrize("key", [[5], (2, 3)]) - def test_get_value_non_scalar_errors(self, key): - # GH 31117 - idx = IntervalIndex.from_tuples([(1, 3), (2, 4), (3, 5), (7, 10), (3, 10)]) - s = pd.Series(range(len(idx)), index=idx) - - msg = str(key) - with pytest.raises(InvalidIndexError, match=msg): - with tm.assert_produces_warning(FutureWarning): - idx.get_value(s, key) - - @pytest.mark.parametrize("closed", ["left", "right", "both"]) - def test_pickle_round_trip_closed(self, closed): - # https://github.com/pandas-dev/pandas/issues/35658 - idx = IntervalIndex.from_tuples([(1, 2), (2, 3)], closed=closed) - result = tm.round_trip_pickle(idx) - tm.assert_index_equal(result, idx) - def test_dir(): # GH#27571 dir(interval_index) should not raise diff --git a/pandas/tests/indexes/interval/test_pickle.py b/pandas/tests/indexes/interval/test_pickle.py new file mode 100644 index 0000000000000..308a90e72eab5 --- /dev/null +++ b/pandas/tests/indexes/interval/test_pickle.py @@ -0,0 +1,13 @@ +import pytest + +from pandas import IntervalIndex +import pandas._testing as tm + + +class TestPickle: + @pytest.mark.parametrize("closed", ["left", "right", "both"]) + def test_pickle_round_trip_closed(self, closed): + # https://github.com/pandas-dev/pandas/issues/35658 + idx = IntervalIndex.from_tuples([(1, 2), (2, 3)], closed=closed) + result = tm.round_trip_pickle(idx) + tm.assert_index_equal(result, idx) diff --git a/pandas/tests/indexes/multi/test_compat.py b/pandas/tests/indexes/multi/test_compat.py index d2b5a595b8454..cbb4ae0b0d09b 100644 --- a/pandas/tests/indexes/multi/test_compat.py +++ b/pandas/tests/indexes/multi/test_compat.py @@ -96,10 +96,3 @@ def test_inplace_mutation_resets_values(): assert "_values" not in mi2._cache tm.assert_almost_equal(mi2.values, new_values) assert "_values" in mi2._cache - - -def test_pickle_compat_construction(): - # this is testing for pickle compat - # need an object to create with - with pytest.raises(TypeError, match="Must pass both levels and codes"): - MultiIndex() diff --git a/pandas/tests/indexes/multi/test_pickle.py b/pandas/tests/indexes/multi/test_pickle.py new file mode 100644 index 0000000000000..1d8b721404421 --- /dev/null +++ b/pandas/tests/indexes/multi/test_pickle.py @@ -0,0 +1,10 @@ +import pytest + +from pandas import MultiIndex + + +def test_pickle_compat_construction(): + # this is testing for pickle compat + # need an object to create with + with pytest.raises(TypeError, match="Must pass both levels and codes"): + MultiIndex() diff --git a/pandas/tests/indexes/period/test_indexing.py b/pandas/tests/indexes/period/test_indexing.py index 1b5e64bca03a0..df2f114e73df2 100644 --- a/pandas/tests/indexes/period/test_indexing.py +++ b/pandas/tests/indexes/period/test_indexing.py @@ -52,14 +52,6 @@ def non_comparable_idx(request): class TestGetItem: - def test_ellipsis(self): - # GH#21282 - idx = period_range("2011-01-01", "2011-01-31", freq="D", name="idx") - - result = idx[...] - assert result.equals(idx) - assert result is not idx - def test_getitem_slice_keeps_name(self): idx = period_range("20010101", periods=10, freq="D", name="bob") assert idx.name == idx[1:].name diff --git a/pandas/tests/indexes/test_any_index.py b/pandas/tests/indexes/test_any_index.py index f7dafd78a801f..91679959e7979 100644 --- a/pandas/tests/indexes/test_any_index.py +++ b/pandas/tests/indexes/test_any_index.py @@ -137,6 +137,12 @@ def test_pickle_preserves_name(self, index): class TestIndexing: + def test_getitem_ellipsis(self, index): + # GH#21282 + result = index[...] + assert result.equals(index) + assert result is not index + def test_slice_keeps_name(self, index): assert index.name == index[1:].name diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 7f9a5c0b50595..59ec66ecc1fe9 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1,8 +1,5 @@ from collections import defaultdict -from datetime import ( - datetime, - timedelta, -) +from datetime import datetime from io import StringIO import math import re @@ -10,10 +7,7 @@ import numpy as np import pytest -from pandas.compat import ( - IS64, - np_datetime64_compat, -) +from pandas.compat import IS64 from pandas.util._test_decorators import async_mark import pandas as pd @@ -27,7 +21,6 @@ RangeIndex, Series, TimedeltaIndex, - Timestamp, date_range, period_range, ) @@ -219,91 +212,6 @@ def test_constructor_simple_new(self, vals, dtype): result = index._simple_new(index.values, dtype) tm.assert_index_equal(result, index) - @pytest.mark.parametrize( - "vals", - [ - [1, 2, 3], - np.array([1, 2, 3]), - np.array([1, 2, 3], dtype=int), - # below should coerce - [1.0, 2.0, 3.0], - np.array([1.0, 2.0, 3.0], dtype=float), - ], - ) - def test_constructor_dtypes_to_int64(self, vals): - index = Index(vals, dtype=int) - assert isinstance(index, Int64Index) - - @pytest.mark.parametrize( - "vals", - [ - [1, 2, 3], - [1.0, 2.0, 3.0], - np.array([1.0, 2.0, 3.0]), - np.array([1, 2, 3], dtype=int), - np.array([1.0, 2.0, 3.0], dtype=float), - ], - ) - def test_constructor_dtypes_to_float64(self, vals): - index = Index(vals, dtype=float) - assert isinstance(index, Float64Index) - - @pytest.mark.parametrize( - "vals", - [ - [1, 2, 3], - np.array([1, 2, 3], dtype=int), - np.array( - [np_datetime64_compat("2011-01-01"), np_datetime64_compat("2011-01-02")] - ), - [datetime(2011, 1, 1), datetime(2011, 1, 2)], - ], - ) - def test_constructor_dtypes_to_categorical(self, vals): - index = Index(vals, dtype="category") - assert isinstance(index, CategoricalIndex) - - @pytest.mark.parametrize("cast_index", [True, False]) - @pytest.mark.parametrize( - "vals", - [ - Index( - np.array( - [ - np_datetime64_compat("2011-01-01"), - np_datetime64_compat("2011-01-02"), - ] - ) - ), - Index([datetime(2011, 1, 1), datetime(2011, 1, 2)]), - ], - ) - def test_constructor_dtypes_to_datetime(self, cast_index, vals): - if cast_index: - index = Index(vals, dtype=object) - assert isinstance(index, Index) - assert index.dtype == object - else: - index = Index(vals) - assert isinstance(index, DatetimeIndex) - - @pytest.mark.parametrize("cast_index", [True, False]) - @pytest.mark.parametrize( - "vals", - [ - np.array([np.timedelta64(1, "D"), np.timedelta64(1, "D")]), - [timedelta(1), timedelta(1)], - ], - ) - def test_constructor_dtypes_to_timedelta(self, cast_index, vals): - if cast_index: - index = Index(vals, dtype=object) - assert isinstance(index, Index) - assert index.dtype == object - else: - index = Index(vals) - assert isinstance(index, TimedeltaIndex) - @pytest.mark.filterwarnings("ignore:Passing keywords other:FutureWarning") @pytest.mark.parametrize("attr", ["values", "asi8"]) @pytest.mark.parametrize("klass", [Index, DatetimeIndex]) @@ -726,20 +634,6 @@ def test_is_all_dates(self, index, expected): def test_summary(self, index): index._summary() - def test_summary_bug(self): - # GH3869` - ind = Index(["{other}%s", "~:{range}:0"], name="A") - result = ind._summary() - # shouldn't be formatted accidentally. - assert "~:{range}:0" in result - assert "{other}%s" in result - - def test_format_different_scalar_lengths(self): - # GH35439 - idx = Index(["aaaaaaaaa", "b"]) - expected = ["aaaaaaaaa", "b"] - assert idx.format() == expected - def test_format_bug(self): # GH 14626 # windows has different precision on datetime.datetime.now (it doesn't @@ -767,21 +661,6 @@ def test_format_missing(self, vals, nulls_fixture): assert formatted == expected assert index[3] is nulls_fixture - def test_format_with_name_time_info(self): - # bug I fixed 12/20/2011 - dates = date_range("2011-01-01 04:00:00", periods=10, name="something") - - formatted = dates.format(name=True) - assert formatted[0] == "something" - - def test_format_datetime_with_time(self): - t = Index([datetime(2012, 2, 7), datetime(2012, 2, 7, 23)]) - - result = t.format() - expected = ["2012-02-07 00:00:00", "2012-02-07 23:00:00"] - assert len(result) == 2 - assert result == expected - @pytest.mark.parametrize("op", ["any", "all"]) def test_logical_compat(self, op, simple_index): index = simple_index @@ -1129,12 +1008,6 @@ def test_outer_join_sort(self): tm.assert_index_equal(result, expected) - def test_nan_first_take_datetime(self): - index = Index([pd.NaT, Timestamp("20130101"), Timestamp("20130102")]) - result = index.take([-1, 0, 1]) - expected = Index([index[-1], index[0], index[1]]) - tm.assert_index_equal(result, expected) - def test_take_fill_value(self): # GH 12631 index = Index(list("ABC"), name="xxx") diff --git a/pandas/tests/indexes/test_common.py b/pandas/tests/indexes/test_common.py index ed9243a5ba8d0..1592c34b48dd8 100644 --- a/pandas/tests/indexes/test_common.py +++ b/pandas/tests/indexes/test_common.py @@ -1,7 +1,7 @@ """ Collection of tests asserting things that should be true for -any index subclass. Makes use of the `indices` fixture defined -in pandas/tests/indexes/conftest.py. +any index subclass except for MultiIndex. Makes use of the `index_flat` +fixture defined in pandas/conftest.py. """ import re @@ -29,6 +29,26 @@ class TestCommon: + @pytest.mark.parametrize("name", [None, "new_name"]) + def test_to_frame(self, name, index_flat): + # see GH#15230, GH#22580 + idx = index_flat + + if name: + idx_name = name + else: + idx_name = idx.name or 0 + + df = idx.to_frame(name=idx_name) + + assert df.index is idx + assert len(df.columns) == 1 + assert df.columns[0] == idx_name + assert df[idx_name].values is not idx.values + + df = idx.to_frame(index=False, name=idx_name) + assert df.index is not idx + def test_droplevel(self, index): # GH 21115 if isinstance(index, MultiIndex): @@ -126,6 +146,46 @@ def test_copy_and_deepcopy(self, index_flat): new_copy = index.copy(deep=True, name="banana") assert new_copy.name == "banana" + def test_copy_name(self, index_flat): + # GH#12309: Check that the "name" argument + # passed at initialization is honored. + index = index_flat + + first = type(index)(index, copy=True, name="mario") + second = type(first)(first, copy=False) + + # Even though "copy=False", we want a new object. + assert first is not second + tm.assert_index_equal(first, second) + + # Not using tm.assert_index_equal() since names differ. + assert index.equals(first) + + assert first.name == "mario" + assert second.name == "mario" + + # TODO: belongs in series arithmetic tests? + s1 = pd.Series(2, index=first) + s2 = pd.Series(3, index=second[:-1]) + # See GH#13365 + s3 = s1 * s2 + assert s3.index.name == "mario" + + def test_copy_name2(self, index_flat): + # GH#35592 + index = index_flat + if isinstance(index, MultiIndex): + return + + assert index.copy(name="mario").name == "mario" + + with pytest.raises(ValueError, match="Length of new names must be 1, got 2"): + index.copy(name=["mario", "luigi"]) + + msg = f"{type(index).__name__}.name must be a hashable type" + with pytest.raises(TypeError, match=msg): + index.copy(name=[["mario"]]) + def test_unique_level(self, index_flat): # don't test a MultiIndex here (as its tested separated) index = index_flat diff --git a/pandas/tests/indexes/test_index_new.py b/pandas/tests/indexes/test_index_new.py index 5c5ec7219d2d7..deeaffaf5b9cc 100644 --- a/pandas/tests/indexes/test_index_new.py +++ b/pandas/tests/indexes/test_index_new.py @@ -1,11 +1,17 @@ """ Tests for the Index constructor conducting inference. """ +from datetime import ( + datetime, + timedelta, +) from decimal import Decimal import numpy as np import pytest +from pandas.compat import np_datetime64_compat + from pandas.core.dtypes.common import is_unsigned_integer_dtype from pandas import ( @@ -27,6 +33,7 @@ ) import pandas._testing as tm from pandas.core.api import ( + Float64Index, Int64Index, UInt64Index, ) @@ -232,6 +239,91 @@ def test_constructor_int_dtype_nan_raises(self, dtype): with pytest.raises(ValueError, match=msg): Index(data, dtype=dtype) + @pytest.mark.parametrize( + "vals", + [ + [1, 2, 3], + np.array([1, 2, 3]), + np.array([1, 2, 3], dtype=int), + # below should coerce + [1.0, 2.0, 3.0], + np.array([1.0, 2.0, 3.0], dtype=float), + ], + ) + def test_constructor_dtypes_to_int64(self, vals): + index = Index(vals, dtype=int) + assert isinstance(index, Int64Index) + + @pytest.mark.parametrize( + "vals", + [ + [1, 2, 3], + [1.0, 2.0, 3.0], + np.array([1.0, 2.0, 3.0]), + np.array([1, 2, 3], dtype=int), + np.array([1.0, 2.0, 3.0], dtype=float), + ], + ) + def test_constructor_dtypes_to_float64(self, vals): + index = Index(vals, dtype=float) + assert isinstance(index, Float64Index) + + @pytest.mark.parametrize( + "vals", + [ + [1, 2, 3], + np.array([1, 2, 3], dtype=int), + np.array( + [np_datetime64_compat("2011-01-01"), np_datetime64_compat("2011-01-02")] + ), + [datetime(2011, 1, 1), datetime(2011, 1, 2)], + ], + ) + def test_constructor_dtypes_to_categorical(self, vals): + index = Index(vals, dtype="category") + assert isinstance(index, CategoricalIndex) + + @pytest.mark.parametrize("cast_index", [True, False]) + @pytest.mark.parametrize( + "vals", + [ + Index( + np.array( + [ + np_datetime64_compat("2011-01-01"), + np_datetime64_compat("2011-01-02"), + ] + ) + ), + Index([datetime(2011, 1, 1), datetime(2011, 1, 2)]), + ], + ) + def test_constructor_dtypes_to_datetime(self, cast_index, vals): + if cast_index: + index = Index(vals, dtype=object) + assert isinstance(index, Index) + assert index.dtype == object + else: + index = Index(vals) + assert isinstance(index, DatetimeIndex) + + @pytest.mark.parametrize("cast_index", [True, False]) + @pytest.mark.parametrize( + "vals", + [ + np.array([np.timedelta64(1, "D"), np.timedelta64(1, "D")]), + [timedelta(1), timedelta(1)], + ], + ) + def test_constructor_dtypes_to_timedelta(self, cast_index, vals): + if cast_index: + index = Index(vals, dtype=object) + assert isinstance(index, Index) + assert index.dtype == object + else: + index = Index(vals) + assert isinstance(index, TimedeltaIndex) + class TestIndexConstructorUnwrapping: # Test passing different arraylike values to pd.Index diff --git a/pandas/tests/indexes/timedeltas/test_indexing.py b/pandas/tests/indexes/timedeltas/test_indexing.py index 66fdaa2778600..0c2f8d0103ceb 100644 --- a/pandas/tests/indexes/timedeltas/test_indexing.py +++ b/pandas/tests/indexes/timedeltas/test_indexing.py @@ -21,14 +21,6 @@ class TestGetItem: - def test_ellipsis(self): - # GH#21282 - idx = timedelta_range("1 day", "31 day", freq="D", name="idx") - - result = idx[...] - assert result.equals(idx) - assert result is not idx - def test_getitem_slice_keeps_name(self): # GH#4226 tdi = timedelta_range("1d", "5d", freq="H", name="timebucket") diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index e46eed05caa86..332ab02255911 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -130,7 +130,7 @@ def test_nanosecond_getitem_setitem_with_tz(self): expected = DataFrame(-1, index=index, columns=["a"]) tm.assert_frame_equal(result, expected) - def test_getitem_millisecond_resolution(self, frame_or_series): + def test_getitem_str_slice_millisecond_resolution(self, frame_or_series): # GH#33589 keys = [ @@ -152,16 +152,3 @@ def test_getitem_millisecond_resolution(self, frame_or_series): ], ) tm.assert_equal(result, expected) - - def test_str_subclass(self): - # GH 37366 - class mystring(str): - pass - - data = ["2020-10-22 01:21:00+00:00"] - index = pd.DatetimeIndex(data) - df = DataFrame({"a": [1]}, index=index) - df["b"] = 2 - df[mystring("c")] = 3 - expected = DataFrame({"a": [1], "b": [2], mystring("c"): [3]}, index=index) - tm.assert_equal(df, expected) diff --git a/pandas/tests/indexing/test_indexing.py b/pandas/tests/indexing/test_indexing.py index 7c7e9f79a77ae..5d6d023cedcc4 100644 --- a/pandas/tests/indexing/test_indexing.py +++ b/pandas/tests/indexing/test_indexing.py @@ -323,9 +323,9 @@ def test_dups_fancy_indexing3(self): def test_duplicate_int_indexing(self, indexer_sl): # GH 17347 - s = Series(range(3), index=[1, 1, 3]) - expected = s[1] - result = indexer_sl(s)[[1]] + ser = Series(range(3), index=[1, 1, 3]) + expected = Series(range(2), index=[1, 1]) + result = indexer_sl(ser)[[1]] tm.assert_series_equal(result, expected) def test_indexing_mixed_frame_bug(self): @@ -653,13 +653,6 @@ def test_loc_setitem_fullindex_views(self): df.loc[df.index] = df.loc[df.index] tm.assert_frame_equal(df, df2) - def test_float_index_at_iat(self): - s = Series([1, 2, 3], index=[0.1, 0.2, 0.3]) - for el, item in s.items(): - assert s.at[el] == item - for i in range(len(s)): - assert s.iat[i] == i + 1 - def test_rhs_alignment(self): # GH8258, tests that both rows & columns are aligned to what is # assigned to. covers both uniform data-type & multi-type cases @@ -709,21 +702,21 @@ def run_tests(df, rhs, right_loc, right_iloc): def test_str_label_slicing_with_negative_step(self): SLC = pd.IndexSlice - def assert_slices_equivalent(l_slc, i_slc): - tm.assert_series_equal(s.loc[l_slc], s.iloc[i_slc]) + def assert_slices_equivalent(ser, l_slc, i_slc): + tm.assert_series_equal(ser.loc[l_slc], ser.iloc[i_slc]) - if not idx.is_integer: + if not idx.is_integer(): # For integer indices, .loc and plain getitem are position-based. - tm.assert_series_equal(s[l_slc], s.iloc[i_slc]) - tm.assert_series_equal(s.loc[l_slc], s.iloc[i_slc]) + tm.assert_series_equal(ser[l_slc], ser.iloc[i_slc]) + tm.assert_series_equal(ser.loc[l_slc], ser.iloc[i_slc]) for idx in [_mklbl("A", 20), np.arange(20) + 100, np.linspace(100, 150, 20)]: idx = Index(idx) - s = Series(np.arange(20), index=idx) - assert_slices_equivalent(SLC[idx[9] :: -1], SLC[9::-1]) - assert_slices_equivalent(SLC[: idx[9] : -1], SLC[:8:-1]) - assert_slices_equivalent(SLC[idx[13] : idx[9] : -1], SLC[13:8:-1]) - assert_slices_equivalent(SLC[idx[9] : idx[13] : -1], SLC[:0]) + ser = Series(np.arange(20), index=idx) + assert_slices_equivalent(ser, SLC[idx[9] :: -1], SLC[9::-1]) + assert_slices_equivalent(ser, SLC[: idx[9] : -1], SLC[:8:-1]) + assert_slices_equivalent(ser, SLC[idx[13] : idx[9] : -1], SLC[13:8:-1]) + assert_slices_equivalent(ser, SLC[idx[9] : idx[13] : -1], SLC[:0]) def test_slice_with_zero_step_raises(self, indexer_sl, frame_or_series): obj = frame_or_series(np.arange(20), index=_mklbl("A", 20)) @@ -967,7 +960,11 @@ def test_extension_array_cross_section(): def test_extension_array_cross_section_converts(): # all numeric columns -> numeric series df = DataFrame( - {"A": pd.array([1, 2], dtype="Int64"), "B": np.array([1, 2])}, index=["a", "b"] + { + "A": pd.array([1, 2], dtype="Int64"), + "B": np.array([1, 2], dtype="int64"), + }, + index=["a", "b"], ) result = df.loc["a"] expected = Series([1, 1], dtype="Int64", index=["A", "B"], name="a") @@ -987,10 +984,3 @@ def test_extension_array_cross_section_converts(): result = df.iloc[0] tm.assert_series_equal(result, expected) - - -def test_getitem_object_index_float_string(): - # GH 17286 - s = Series([1] * 4, index=Index(["a", "b", "c", 1.0])) - assert s["a"] == 1 - assert s[1.0] == 1 diff --git a/pandas/tests/indexing/test_scalar.py b/pandas/tests/indexing/test_scalar.py index bf262e6755289..bcb76fb078e74 100644 --- a/pandas/tests/indexing/test_scalar.py +++ b/pandas/tests/indexing/test_scalar.py @@ -77,6 +77,13 @@ def _check(f, func, values=False): class TestAtAndiAT: # at and iat tests that don't need Base class + def test_float_index_at_iat(self): + ser = Series([1, 2, 3], index=[0.1, 0.2, 0.3]) + for el, item in ser.items(): + assert ser.at[el] == item + for i in range(len(ser)): + assert ser.iat[i] == i + 1 + def test_at_iat_coercion(self): # as timestamp is not a tuple! diff --git a/pandas/tests/series/indexing/test_getitem.py b/pandas/tests/series/indexing/test_getitem.py index 03b1c512f9053..4c17917b949ca 100644 --- a/pandas/tests/series/indexing/test_getitem.py +++ b/pandas/tests/series/indexing/test_getitem.py @@ -36,6 +36,12 @@ class TestSeriesGetitemScalars: + def test_getitem_object_index_float_string(self): + # GH#17286 + ser = Series([1] * 4, index=Index(["a", "b", "c", 1.0])) + assert ser["a"] == 1 + assert ser[1.0] == 1 + def test_getitem_float_keys_tuple_values(self): # see GH#13509