from distutils.version import LooseVersion from operator import methodcaller import numpy as np import pytest import pandas.util._test_decorators as td import pandas as pd from pandas import MultiIndex, Series, date_range import pandas.util.testing as tm from pandas.util.testing import assert_almost_equal, assert_series_equal from .test_generic import Generic try: import xarray _XARRAY_INSTALLED = True except ImportError: _XARRAY_INSTALLED = False class TestSeries(Generic): _typ = Series _comparator = lambda self, x, y: assert_series_equal(x, y) def setup_method(self): self.ts = tm.makeTimeSeries() # Was at top level in test_series self.ts.name = "ts" self.series = tm.makeStringSeries() self.series.name = "series" def test_rename_mi(self): s = Series( [11, 21, 31], index=MultiIndex.from_tuples([("A", x) for x in ["a", "B", "c"]]), ) s.rename(str.lower) def test_set_axis_name(self): s = Series([1, 2, 3], index=["a", "b", "c"]) funcs = ["rename_axis", "_set_axis_name"] name = "foo" for func in funcs: result = methodcaller(func, name)(s) assert s.index.name is None assert result.index.name == name def test_set_axis_name_mi(self): s = Series( [11, 21, 31], index=MultiIndex.from_tuples( [("A", x) for x in ["a", "B", "c"]], names=["l1", "l2"] ), ) funcs = ["rename_axis", "_set_axis_name"] for func in funcs: result = methodcaller(func, ["L1", "L2"])(s) assert s.index.name is None assert s.index.names == ["l1", "l2"] assert result.index.name is None assert result.index.names, ["L1", "L2"] def test_set_axis_name_raises(self): s = pd.Series([1]) with pytest.raises(ValueError): s._set_axis_name(name="a", axis=1) def test_get_numeric_data_preserve_dtype(self): # get the numeric data o = Series([1, 2, 3]) result = o._get_numeric_data() self._compare(result, o) o = Series([1, "2", 3.0]) result = o._get_numeric_data() expected = Series([], dtype=object, index=pd.Index([], dtype=object)) self._compare(result, expected) o = Series([True, False, True]) result = o._get_numeric_data() self._compare(result, o) o = Series([True, False, True]) result = o._get_bool_data() self._compare(result, o) o = Series(date_range("20130101", periods=3)) result = o._get_numeric_data() expected = Series([], dtype="M8[ns]", index=pd.Index([], dtype=object)) self._compare(result, expected) def test_nonzero_single_element(self): # allow single item via bool method s = Series([True]) assert s.bool() s = Series([False]) assert not s.bool() msg = "The truth value of a Series is ambiguous" # single item nan to raise for s in [Series([np.nan]), Series([pd.NaT]), Series([True]), Series([False])]: with pytest.raises(ValueError, match=msg): bool(s) msg = "bool cannot act on a non-boolean single element Series" for s in [Series([np.nan]), Series([pd.NaT])]: with pytest.raises(ValueError, match=msg): s.bool() # multiple bool are still an error msg = "The truth value of a Series is ambiguous" for s in [Series([True, True]), Series([False, False])]: with pytest.raises(ValueError, match=msg): bool(s) with pytest.raises(ValueError, match=msg): s.bool() # single non-bool are an error for s in [Series([1]), Series([0]), Series(["a"]), Series([0.0])]: msg = "The truth value of a Series is ambiguous" with pytest.raises(ValueError, match=msg): bool(s) msg = "bool cannot act on a non-boolean single element Series" with pytest.raises(ValueError, match=msg): s.bool() def test_metadata_propagation_indiv(self): # check that the metadata matches up on the resulting ops o = Series(range(3), range(3)) o.name = "foo" o2 = Series(range(3), range(3)) o2.name = "bar" result = o.T self.check_metadata(o, result) # resample ts = Series( np.random.rand(1000), index=date_range("20130101", periods=1000, freq="s"), name="foo", ) result = ts.resample("1T").mean() self.check_metadata(ts, result) result = ts.resample("1T").min() self.check_metadata(ts, result) result = ts.resample("1T").apply(lambda x: x.sum()) self.check_metadata(ts, result) _metadata = Series._metadata _finalize = Series.__finalize__ Series._metadata = ["name", "filename"] o.filename = "foo" o2.filename = "bar" def finalize(self, other, method=None, **kwargs): for name in self._metadata: if method == "concat" and name == "filename": value = "+".join( [getattr(o, name) for o in other.objs if getattr(o, name, None)] ) object.__setattr__(self, name, value) else: object.__setattr__(self, name, getattr(other, name, None)) return self Series.__finalize__ = finalize result = pd.concat([o, o2]) assert result.filename == "foo+bar" assert result.name is None # reset Series._metadata = _metadata Series.__finalize__ = _finalize @pytest.mark.skipif( not _XARRAY_INSTALLED or _XARRAY_INSTALLED and LooseVersion(xarray.__version__) < LooseVersion("0.10.0"), reason="xarray >= 0.10.0 required", ) @pytest.mark.parametrize( "index", [ "FloatIndex", "IntIndex", "StringIndex", "UnicodeIndex", "DateIndex", "PeriodIndex", "TimedeltaIndex", "CategoricalIndex", ], ) def test_to_xarray_index_types(self, index): from xarray import DataArray index = getattr(tm, "make{}".format(index)) s = Series(range(6), index=index(6)) s.index.name = "foo" result = s.to_xarray() repr(result) assert len(result) == 6 assert len(result.coords) == 1 assert_almost_equal(list(result.coords.keys()), ["foo"]) assert isinstance(result, DataArray) # idempotency assert_series_equal( result.to_series(), s, check_index_type=False, check_categorical=True ) @td.skip_if_no("xarray", min_version="0.7.0") def test_to_xarray(self): from xarray import DataArray s = Series([]) s.index.name = "foo" result = s.to_xarray() assert len(result) == 0 assert len(result.coords) == 1 assert_almost_equal(list(result.coords.keys()), ["foo"]) assert isinstance(result, DataArray) s = Series(range(6)) s.index.name = "foo" s.index = pd.MultiIndex.from_product( [["a", "b"], range(3)], names=["one", "two"] ) result = s.to_xarray() assert len(result) == 2 assert_almost_equal(list(result.coords.keys()), ["one", "two"]) assert isinstance(result, DataArray) assert_series_equal(result.to_series(), s) def test_valid_deprecated(self): # GH18800 with tm.assert_produces_warning(FutureWarning): pd.Series([]).valid() @pytest.mark.parametrize( "s", [ Series([np.arange(5)]), pd.date_range("1/1/2011", periods=24, freq="H"), pd.Series(range(5), index=pd.date_range("2017", periods=5)), ], ) @pytest.mark.parametrize("shift_size", [0, 1, 2]) def test_shift_always_copy(self, s, shift_size): # GH22397 assert s.shift(shift_size) is not s @pytest.mark.parametrize("move_by_freq", [pd.Timedelta("1D"), pd.Timedelta("1M")]) def test_datetime_shift_always_copy(self, move_by_freq): # GH22397 s = pd.Series(range(5), index=pd.date_range("2017", periods=5)) assert s.shift(freq=move_by_freq) is not s