You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

768 lines
28 KiB

6 months ago
"""
An exhaustive list of pandas methods exercising NDFrame.__finalize__.
"""
import operator
import re
import numpy as np
import pytest
import pandas as pd
import pandas._testing as tm
# TODO:
# * Binary methods (mul, div, etc.)
# * Binary outputs (align, etc.)
# * top-level methods (concat, merge, get_dummies, etc.)
# * window
# * cumulative reductions
not_implemented_mark = pytest.mark.xfail(reason="not implemented")
mi = pd.MultiIndex.from_product([["a", "b"], [0, 1]], names=["A", "B"])
frame_data = ({"A": [1]},)
frame_mi_data = ({"A": [1, 2, 3, 4]}, mi)
# Tuple of
# - Callable: Constructor (Series, DataFrame)
# - Tuple: Constructor args
# - Callable: pass the constructed value with attrs set to this.
_all_methods = [
(pd.Series, ([0],), operator.methodcaller("take", [])),
(pd.Series, ([0],), operator.methodcaller("__getitem__", [True])),
(pd.Series, ([0],), operator.methodcaller("repeat", 2)),
(pd.Series, ([0],), operator.methodcaller("reset_index")),
(pd.Series, ([0],), operator.methodcaller("reset_index", drop=True)),
(pd.Series, ([0],), operator.methodcaller("to_frame")),
(pd.Series, ([0, 0],), operator.methodcaller("drop_duplicates")),
(pd.Series, ([0, 0],), operator.methodcaller("duplicated")),
(pd.Series, ([0, 0],), operator.methodcaller("round")),
(pd.Series, ([0, 0],), operator.methodcaller("rename", lambda x: x + 1)),
(pd.Series, ([0, 0],), operator.methodcaller("rename", "name")),
(pd.Series, ([0, 0],), operator.methodcaller("set_axis", ["a", "b"])),
(pd.Series, ([0, 0],), operator.methodcaller("reindex", [1, 0])),
(pd.Series, ([0, 0],), operator.methodcaller("drop", [0])),
(pd.Series, (pd.array([0, pd.NA]),), operator.methodcaller("fillna", 0)),
(pd.Series, ([0, 0],), operator.methodcaller("replace", {0: 1})),
(pd.Series, ([0, 0],), operator.methodcaller("shift")),
(pd.Series, ([0, 0],), operator.methodcaller("isin", [0, 1])),
(pd.Series, ([0, 0],), operator.methodcaller("between", 0, 2)),
(pd.Series, ([0, 0],), operator.methodcaller("isna")),
(pd.Series, ([0, 0],), operator.methodcaller("isnull")),
(pd.Series, ([0, 0],), operator.methodcaller("notna")),
(pd.Series, ([0, 0],), operator.methodcaller("notnull")),
(pd.Series, ([1],), operator.methodcaller("add", pd.Series([1]))),
# TODO: mul, div, etc.
(
pd.Series,
([0], pd.period_range("2000", periods=1)),
operator.methodcaller("to_timestamp"),
),
(
pd.Series,
([0], pd.date_range("2000", periods=1)),
operator.methodcaller("to_period"),
),
pytest.param(
(
pd.DataFrame,
frame_data,
operator.methodcaller("dot", pd.DataFrame(index=["A"])),
),
marks=pytest.mark.xfail(reason="Implement binary finalize"),
),
(pd.DataFrame, frame_data, operator.methodcaller("transpose")),
(pd.DataFrame, frame_data, operator.methodcaller("__getitem__", "A")),
(pd.DataFrame, frame_data, operator.methodcaller("__getitem__", ["A"])),
(pd.DataFrame, frame_data, operator.methodcaller("__getitem__", np.array([True]))),
(pd.DataFrame, ({("A", "a"): [1]},), operator.methodcaller("__getitem__", ["A"])),
(pd.DataFrame, frame_data, operator.methodcaller("query", "A == 1")),
(pd.DataFrame, frame_data, operator.methodcaller("eval", "A + 1", engine="python")),
(pd.DataFrame, frame_data, operator.methodcaller("select_dtypes", include="int")),
(pd.DataFrame, frame_data, operator.methodcaller("assign", b=1)),
(pd.DataFrame, frame_data, operator.methodcaller("set_axis", ["A"])),
(pd.DataFrame, frame_data, operator.methodcaller("reindex", [0, 1])),
(pd.DataFrame, frame_data, operator.methodcaller("drop", columns=["A"])),
(pd.DataFrame, frame_data, operator.methodcaller("drop", index=[0])),
(pd.DataFrame, frame_data, operator.methodcaller("rename", columns={"A": "a"})),
(pd.DataFrame, frame_data, operator.methodcaller("rename", index=lambda x: x)),
(pd.DataFrame, frame_data, operator.methodcaller("fillna", "A")),
(pd.DataFrame, frame_data, operator.methodcaller("fillna", method="ffill")),
(pd.DataFrame, frame_data, operator.methodcaller("set_index", "A")),
(pd.DataFrame, frame_data, operator.methodcaller("reset_index")),
(pd.DataFrame, frame_data, operator.methodcaller("isna")),
(pd.DataFrame, frame_data, operator.methodcaller("isnull")),
(pd.DataFrame, frame_data, operator.methodcaller("notna")),
(pd.DataFrame, frame_data, operator.methodcaller("notnull")),
(pd.DataFrame, frame_data, operator.methodcaller("dropna")),
(pd.DataFrame, frame_data, operator.methodcaller("drop_duplicates")),
(pd.DataFrame, frame_data, operator.methodcaller("duplicated")),
(pd.DataFrame, frame_data, operator.methodcaller("sort_values", by="A")),
(pd.DataFrame, frame_data, operator.methodcaller("sort_index")),
(pd.DataFrame, frame_data, operator.methodcaller("nlargest", 1, "A")),
(pd.DataFrame, frame_data, operator.methodcaller("nsmallest", 1, "A")),
(pd.DataFrame, frame_mi_data, operator.methodcaller("swaplevel")),
(
pd.DataFrame,
frame_data,
operator.methodcaller("add", pd.DataFrame(*frame_data)),
),
# TODO: div, mul, etc.
(
pd.DataFrame,
frame_data,
operator.methodcaller("combine", pd.DataFrame(*frame_data), operator.add),
),
(
pd.DataFrame,
frame_data,
operator.methodcaller("combine_first", pd.DataFrame(*frame_data)),
),
pytest.param(
(
pd.DataFrame,
frame_data,
operator.methodcaller("update", pd.DataFrame(*frame_data)),
),
marks=not_implemented_mark,
),
(pd.DataFrame, frame_data, operator.methodcaller("pivot", columns="A")),
(
pd.DataFrame,
({"A": [1], "B": [1]},),
operator.methodcaller("pivot_table", columns="A"),
),
(
pd.DataFrame,
({"A": [1], "B": [1]},),
operator.methodcaller("pivot_table", columns="A", aggfunc=["mean", "sum"]),
),
(pd.DataFrame, frame_data, operator.methodcaller("stack")),
(pd.DataFrame, frame_data, operator.methodcaller("explode", "A")),
(pd.DataFrame, frame_mi_data, operator.methodcaller("unstack")),
(
pd.DataFrame,
({"A": ["a", "b", "c"], "B": [1, 3, 5], "C": [2, 4, 6]},),
operator.methodcaller("melt", id_vars=["A"], value_vars=["B"]),
),
(pd.DataFrame, frame_data, operator.methodcaller("map", lambda x: x)),
pytest.param(
(
pd.DataFrame,
frame_data,
operator.methodcaller("merge", pd.DataFrame({"A": [1]})),
),
marks=not_implemented_mark,
),
(pd.DataFrame, frame_data, operator.methodcaller("round", 2)),
(pd.DataFrame, frame_data, operator.methodcaller("corr")),
pytest.param(
(pd.DataFrame, frame_data, operator.methodcaller("cov")),
marks=[
pytest.mark.filterwarnings("ignore::RuntimeWarning"),
],
),
(
pd.DataFrame,
frame_data,
operator.methodcaller("corrwith", pd.DataFrame(*frame_data)),
),
(pd.DataFrame, frame_data, operator.methodcaller("count")),
(pd.DataFrame, frame_data, operator.methodcaller("nunique")),
(pd.DataFrame, frame_data, operator.methodcaller("idxmin")),
(pd.DataFrame, frame_data, operator.methodcaller("idxmax")),
(pd.DataFrame, frame_data, operator.methodcaller("mode")),
(pd.Series, [0], operator.methodcaller("mode")),
(pd.DataFrame, frame_data, operator.methodcaller("median")),
(
pd.DataFrame,
frame_data,
operator.methodcaller("quantile", numeric_only=True),
),
(
pd.DataFrame,
frame_data,
operator.methodcaller("quantile", q=[0.25, 0.75], numeric_only=True),
),
(
pd.DataFrame,
({"A": [pd.Timedelta(days=1), pd.Timedelta(days=2)]},),
operator.methodcaller("quantile", numeric_only=False),
),
(
pd.DataFrame,
({"A": [np.datetime64("2022-01-01"), np.datetime64("2022-01-02")]},),
operator.methodcaller("quantile", numeric_only=True),
),
(
pd.DataFrame,
({"A": [1]}, [pd.Period("2000", "D")]),
operator.methodcaller("to_timestamp"),
),
(
pd.DataFrame,
({"A": [1]}, [pd.Timestamp("2000")]),
operator.methodcaller("to_period", freq="D"),
),
(pd.DataFrame, frame_mi_data, operator.methodcaller("isin", [1])),
(pd.DataFrame, frame_mi_data, operator.methodcaller("isin", pd.Series([1]))),
(
pd.DataFrame,
frame_mi_data,
operator.methodcaller("isin", pd.DataFrame({"A": [1]})),
),
(pd.DataFrame, frame_mi_data, operator.methodcaller("droplevel", "A")),
(pd.DataFrame, frame_data, operator.methodcaller("pop", "A")),
# Squeeze on columns, otherwise we'll end up with a scalar
(pd.DataFrame, frame_data, operator.methodcaller("squeeze", axis="columns")),
(pd.Series, ([1, 2],), operator.methodcaller("squeeze")),
(pd.Series, ([1, 2],), operator.methodcaller("rename_axis", index="a")),
(pd.DataFrame, frame_data, operator.methodcaller("rename_axis", columns="a")),
# Unary ops
(pd.DataFrame, frame_data, operator.neg),
(pd.Series, [1], operator.neg),
(pd.DataFrame, frame_data, operator.pos),
(pd.Series, [1], operator.pos),
(pd.DataFrame, frame_data, operator.inv),
(pd.Series, [1], operator.inv),
(pd.DataFrame, frame_data, abs),
(pd.Series, [1], abs),
(pd.DataFrame, frame_data, round),
(pd.Series, [1], round),
(pd.DataFrame, frame_data, operator.methodcaller("take", [0, 0])),
(pd.DataFrame, frame_mi_data, operator.methodcaller("xs", "a")),
(pd.Series, (1, mi), operator.methodcaller("xs", "a")),
(pd.DataFrame, frame_data, operator.methodcaller("get", "A")),
(
pd.DataFrame,
frame_data,
operator.methodcaller("reindex_like", pd.DataFrame({"A": [1, 2, 3]})),
),
(
pd.Series,
frame_data,
operator.methodcaller("reindex_like", pd.Series([0, 1, 2])),
),
(pd.DataFrame, frame_data, operator.methodcaller("add_prefix", "_")),
(pd.DataFrame, frame_data, operator.methodcaller("add_suffix", "_")),
(pd.Series, (1, ["a", "b"]), operator.methodcaller("add_prefix", "_")),
(pd.Series, (1, ["a", "b"]), operator.methodcaller("add_suffix", "_")),
(pd.Series, ([3, 2],), operator.methodcaller("sort_values")),
(pd.Series, ([1] * 10,), operator.methodcaller("head")),
(pd.DataFrame, ({"A": [1] * 10},), operator.methodcaller("head")),
(pd.Series, ([1] * 10,), operator.methodcaller("tail")),
(pd.DataFrame, ({"A": [1] * 10},), operator.methodcaller("tail")),
(pd.Series, ([1, 2],), operator.methodcaller("sample", n=2, replace=True)),
(pd.DataFrame, (frame_data,), operator.methodcaller("sample", n=2, replace=True)),
(pd.Series, ([1, 2],), operator.methodcaller("astype", float)),
(pd.DataFrame, frame_data, operator.methodcaller("astype", float)),
(pd.Series, ([1, 2],), operator.methodcaller("copy")),
(pd.DataFrame, frame_data, operator.methodcaller("copy")),
(pd.Series, ([1, 2], None, object), operator.methodcaller("infer_objects")),
(
pd.DataFrame,
({"A": np.array([1, 2], dtype=object)},),
operator.methodcaller("infer_objects"),
),
(pd.Series, ([1, 2],), operator.methodcaller("convert_dtypes")),
(pd.DataFrame, frame_data, operator.methodcaller("convert_dtypes")),
(pd.Series, ([1, None, 3],), operator.methodcaller("interpolate")),
(pd.DataFrame, ({"A": [1, None, 3]},), operator.methodcaller("interpolate")),
(pd.Series, ([1, 2],), operator.methodcaller("clip", lower=1)),
(pd.DataFrame, frame_data, operator.methodcaller("clip", lower=1)),
(
pd.Series,
(1, pd.date_range("2000", periods=4)),
operator.methodcaller("asfreq", "h"),
),
(
pd.DataFrame,
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
operator.methodcaller("asfreq", "h"),
),
(
pd.Series,
(1, pd.date_range("2000", periods=4)),
operator.methodcaller("at_time", "12:00"),
),
(
pd.DataFrame,
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
operator.methodcaller("at_time", "12:00"),
),
(
pd.Series,
(1, pd.date_range("2000", periods=4)),
operator.methodcaller("between_time", "12:00", "13:00"),
),
(
pd.DataFrame,
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
operator.methodcaller("between_time", "12:00", "13:00"),
),
(
pd.Series,
(1, pd.date_range("2000", periods=4)),
operator.methodcaller("last", "3D"),
),
(
pd.DataFrame,
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
operator.methodcaller("last", "3D"),
),
(pd.Series, ([1, 2],), operator.methodcaller("rank")),
(pd.DataFrame, frame_data, operator.methodcaller("rank")),
(pd.Series, ([1, 2],), operator.methodcaller("where", np.array([True, False]))),
(pd.DataFrame, frame_data, operator.methodcaller("where", np.array([[True]]))),
(pd.Series, ([1, 2],), operator.methodcaller("mask", np.array([True, False]))),
(pd.DataFrame, frame_data, operator.methodcaller("mask", np.array([[True]]))),
(pd.Series, ([1, 2],), operator.methodcaller("truncate", before=0)),
(pd.DataFrame, frame_data, operator.methodcaller("truncate", before=0)),
(
pd.Series,
(1, pd.date_range("2000", periods=4, tz="UTC")),
operator.methodcaller("tz_convert", "CET"),
),
(
pd.DataFrame,
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4, tz="UTC")),
operator.methodcaller("tz_convert", "CET"),
),
(
pd.Series,
(1, pd.date_range("2000", periods=4)),
operator.methodcaller("tz_localize", "CET"),
),
(
pd.DataFrame,
({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
operator.methodcaller("tz_localize", "CET"),
),
(pd.Series, ([1, 2],), operator.methodcaller("describe")),
(pd.DataFrame, frame_data, operator.methodcaller("describe")),
(pd.Series, ([1, 2],), operator.methodcaller("pct_change")),
(pd.DataFrame, frame_data, operator.methodcaller("pct_change")),
(pd.Series, ([1],), operator.methodcaller("transform", lambda x: x - x.min())),
(
pd.DataFrame,
frame_mi_data,
operator.methodcaller("transform", lambda x: x - x.min()),
),
(pd.Series, ([1],), operator.methodcaller("apply", lambda x: x)),
(pd.DataFrame, frame_mi_data, operator.methodcaller("apply", lambda x: x)),
# Cumulative reductions
(pd.Series, ([1],), operator.methodcaller("cumsum")),
(pd.DataFrame, frame_data, operator.methodcaller("cumsum")),
(pd.Series, ([1],), operator.methodcaller("cummin")),
(pd.DataFrame, frame_data, operator.methodcaller("cummin")),
(pd.Series, ([1],), operator.methodcaller("cummax")),
(pd.DataFrame, frame_data, operator.methodcaller("cummax")),
(pd.Series, ([1],), operator.methodcaller("cumprod")),
(pd.DataFrame, frame_data, operator.methodcaller("cumprod")),
# Reductions
(pd.DataFrame, frame_data, operator.methodcaller("any")),
(pd.DataFrame, frame_data, operator.methodcaller("all")),
(pd.DataFrame, frame_data, operator.methodcaller("min")),
(pd.DataFrame, frame_data, operator.methodcaller("max")),
(pd.DataFrame, frame_data, operator.methodcaller("sum")),
(pd.DataFrame, frame_data, operator.methodcaller("std")),
(pd.DataFrame, frame_data, operator.methodcaller("mean")),
(pd.DataFrame, frame_data, operator.methodcaller("prod")),
(pd.DataFrame, frame_data, operator.methodcaller("sem")),
(pd.DataFrame, frame_data, operator.methodcaller("skew")),
(pd.DataFrame, frame_data, operator.methodcaller("kurt")),
]
def idfn(x):
xpr = re.compile(r"'(.*)?'")
m = xpr.search(str(x))
if m:
return m.group(1)
else:
return str(x)
@pytest.fixture(params=_all_methods, ids=lambda x: idfn(x[-1]))
def ndframe_method(request):
"""
An NDFrame method returning an NDFrame.
"""
return request.param
@pytest.mark.filterwarnings(
"ignore:DataFrame.fillna with 'method' is deprecated:FutureWarning",
"ignore:last is deprecated:FutureWarning",
)
def test_finalize_called(ndframe_method):
cls, init_args, method = ndframe_method
ndframe = cls(*init_args)
ndframe.attrs = {"a": 1}
result = method(ndframe)
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"data",
[
pd.Series(1, pd.date_range("2000", periods=4)),
pd.DataFrame({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
],
)
def test_finalize_first(data):
deprecated_msg = "first is deprecated"
data.attrs = {"a": 1}
with tm.assert_produces_warning(FutureWarning, match=deprecated_msg):
result = data.first("3D")
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"data",
[
pd.Series(1, pd.date_range("2000", periods=4)),
pd.DataFrame({"A": [1, 1, 1, 1]}, pd.date_range("2000", periods=4)),
],
)
def test_finalize_last(data):
# GH 53710
deprecated_msg = "last is deprecated"
data.attrs = {"a": 1}
with tm.assert_produces_warning(FutureWarning, match=deprecated_msg):
result = data.last("3D")
assert result.attrs == {"a": 1}
@not_implemented_mark
def test_finalize_called_eval_numexpr():
pytest.importorskip("numexpr")
df = pd.DataFrame({"A": [1, 2]})
df.attrs["A"] = 1
result = df.eval("A + 1", engine="numexpr")
assert result.attrs == {"A": 1}
# ----------------------------------------------------------------------------
# Binary operations
@pytest.mark.parametrize("annotate", ["left", "right", "both"])
@pytest.mark.parametrize(
"args",
[
(1, pd.Series([1])),
(1, pd.DataFrame({"A": [1]})),
(pd.Series([1]), 1),
(pd.DataFrame({"A": [1]}), 1),
(pd.Series([1]), pd.Series([1])),
(pd.DataFrame({"A": [1]}), pd.DataFrame({"A": [1]})),
(pd.Series([1]), pd.DataFrame({"A": [1]})),
(pd.DataFrame({"A": [1]}), pd.Series([1])),
],
ids=lambda x: f"({type(x[0]).__name__},{type(x[1]).__name__})",
)
def test_binops(request, args, annotate, all_binary_operators):
# This generates 624 tests... Is that needed?
left, right = args
if isinstance(left, (pd.DataFrame, pd.Series)):
left.attrs = {}
if isinstance(right, (pd.DataFrame, pd.Series)):
right.attrs = {}
if annotate == "left" and isinstance(left, int):
pytest.skip("left is an int and doesn't support .attrs")
if annotate == "right" and isinstance(right, int):
pytest.skip("right is an int and doesn't support .attrs")
if not (isinstance(left, int) or isinstance(right, int)) and annotate != "both":
if not all_binary_operators.__name__.startswith("r"):
if annotate == "right" and isinstance(left, type(right)):
request.applymarker(
pytest.mark.xfail(
reason=f"{all_binary_operators} doesn't work when right has "
f"attrs and both are {type(left)}"
)
)
if not isinstance(left, type(right)):
if annotate == "left" and isinstance(left, pd.Series):
request.applymarker(
pytest.mark.xfail(
reason=f"{all_binary_operators} doesn't work when the "
"objects are different Series has attrs"
)
)
elif annotate == "right" and isinstance(right, pd.Series):
request.applymarker(
pytest.mark.xfail(
reason=f"{all_binary_operators} doesn't work when the "
"objects are different Series has attrs"
)
)
else:
if annotate == "left" and isinstance(left, type(right)):
request.applymarker(
pytest.mark.xfail(
reason=f"{all_binary_operators} doesn't work when left has "
f"attrs and both are {type(left)}"
)
)
if not isinstance(left, type(right)):
if annotate == "right" and isinstance(right, pd.Series):
request.applymarker(
pytest.mark.xfail(
reason=f"{all_binary_operators} doesn't work when the "
"objects are different Series has attrs"
)
)
elif annotate == "left" and isinstance(left, pd.Series):
request.applymarker(
pytest.mark.xfail(
reason=f"{all_binary_operators} doesn't work when the "
"objects are different Series has attrs"
)
)
if annotate in {"left", "both"} and not isinstance(left, int):
left.attrs = {"a": 1}
if annotate in {"right", "both"} and not isinstance(right, int):
right.attrs = {"a": 1}
is_cmp = all_binary_operators in [
operator.eq,
operator.ne,
operator.gt,
operator.ge,
operator.lt,
operator.le,
]
if is_cmp and isinstance(left, pd.DataFrame) and isinstance(right, pd.Series):
# in 2.0 silent alignment on comparisons was removed xref GH#28759
left, right = left.align(right, axis=1, copy=False)
elif is_cmp and isinstance(left, pd.Series) and isinstance(right, pd.DataFrame):
right, left = right.align(left, axis=1, copy=False)
result = all_binary_operators(left, right)
assert result.attrs == {"a": 1}
# ----------------------------------------------------------------------------
# Accessors
@pytest.mark.parametrize(
"method",
[
operator.methodcaller("capitalize"),
operator.methodcaller("casefold"),
operator.methodcaller("cat", ["a"]),
operator.methodcaller("contains", "a"),
operator.methodcaller("count", "a"),
operator.methodcaller("encode", "utf-8"),
operator.methodcaller("endswith", "a"),
operator.methodcaller("extract", r"(\w)(\d)"),
operator.methodcaller("extract", r"(\w)(\d)", expand=False),
operator.methodcaller("find", "a"),
operator.methodcaller("findall", "a"),
operator.methodcaller("get", 0),
operator.methodcaller("index", "a"),
operator.methodcaller("len"),
operator.methodcaller("ljust", 4),
operator.methodcaller("lower"),
operator.methodcaller("lstrip"),
operator.methodcaller("match", r"\w"),
operator.methodcaller("normalize", "NFC"),
operator.methodcaller("pad", 4),
operator.methodcaller("partition", "a"),
operator.methodcaller("repeat", 2),
operator.methodcaller("replace", "a", "b"),
operator.methodcaller("rfind", "a"),
operator.methodcaller("rindex", "a"),
operator.methodcaller("rjust", 4),
operator.methodcaller("rpartition", "a"),
operator.methodcaller("rstrip"),
operator.methodcaller("slice", 4),
operator.methodcaller("slice_replace", 1, repl="a"),
operator.methodcaller("startswith", "a"),
operator.methodcaller("strip"),
operator.methodcaller("swapcase"),
operator.methodcaller("translate", {"a": "b"}),
operator.methodcaller("upper"),
operator.methodcaller("wrap", 4),
operator.methodcaller("zfill", 4),
operator.methodcaller("isalnum"),
operator.methodcaller("isalpha"),
operator.methodcaller("isdigit"),
operator.methodcaller("isspace"),
operator.methodcaller("islower"),
operator.methodcaller("isupper"),
operator.methodcaller("istitle"),
operator.methodcaller("isnumeric"),
operator.methodcaller("isdecimal"),
operator.methodcaller("get_dummies"),
],
ids=idfn,
)
def test_string_method(method):
s = pd.Series(["a1"])
s.attrs = {"a": 1}
result = method(s.str)
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"method",
[
operator.methodcaller("to_period"),
operator.methodcaller("tz_localize", "CET"),
operator.methodcaller("normalize"),
operator.methodcaller("strftime", "%Y"),
operator.methodcaller("round", "h"),
operator.methodcaller("floor", "h"),
operator.methodcaller("ceil", "h"),
operator.methodcaller("month_name"),
operator.methodcaller("day_name"),
],
ids=idfn,
)
def test_datetime_method(method):
s = pd.Series(pd.date_range("2000", periods=4))
s.attrs = {"a": 1}
result = method(s.dt)
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"attr",
[
"date",
"time",
"timetz",
"year",
"month",
"day",
"hour",
"minute",
"second",
"microsecond",
"nanosecond",
"dayofweek",
"day_of_week",
"dayofyear",
"day_of_year",
"quarter",
"is_month_start",
"is_month_end",
"is_quarter_start",
"is_quarter_end",
"is_year_start",
"is_year_end",
"is_leap_year",
"daysinmonth",
"days_in_month",
],
)
def test_datetime_property(attr):
s = pd.Series(pd.date_range("2000", periods=4))
s.attrs = {"a": 1}
result = getattr(s.dt, attr)
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"attr", ["days", "seconds", "microseconds", "nanoseconds", "components"]
)
def test_timedelta_property(attr):
s = pd.Series(pd.timedelta_range("2000", periods=4))
s.attrs = {"a": 1}
result = getattr(s.dt, attr)
assert result.attrs == {"a": 1}
@pytest.mark.parametrize("method", [operator.methodcaller("total_seconds")])
def test_timedelta_methods(method):
s = pd.Series(pd.timedelta_range("2000", periods=4))
s.attrs = {"a": 1}
result = method(s.dt)
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"method",
[
operator.methodcaller("add_categories", ["c"]),
operator.methodcaller("as_ordered"),
operator.methodcaller("as_unordered"),
lambda x: getattr(x, "codes"),
operator.methodcaller("remove_categories", "a"),
operator.methodcaller("remove_unused_categories"),
operator.methodcaller("rename_categories", {"a": "A", "b": "B"}),
operator.methodcaller("reorder_categories", ["b", "a"]),
operator.methodcaller("set_categories", ["A", "B"]),
],
)
@not_implemented_mark
def test_categorical_accessor(method):
s = pd.Series(["a", "b"], dtype="category")
s.attrs = {"a": 1}
result = method(s.cat)
assert result.attrs == {"a": 1}
# ----------------------------------------------------------------------------
# Groupby
@pytest.mark.parametrize(
"obj", [pd.Series([0, 0]), pd.DataFrame({"A": [0, 1], "B": [1, 2]})]
)
@pytest.mark.parametrize(
"method",
[
operator.methodcaller("sum"),
lambda x: x.apply(lambda y: y),
lambda x: x.agg("sum"),
lambda x: x.agg("mean"),
lambda x: x.agg("median"),
],
)
def test_groupby_finalize(obj, method):
obj.attrs = {"a": 1}
result = method(obj.groupby([0, 0], group_keys=False))
assert result.attrs == {"a": 1}
@pytest.mark.parametrize(
"obj", [pd.Series([0, 0]), pd.DataFrame({"A": [0, 1], "B": [1, 2]})]
)
@pytest.mark.parametrize(
"method",
[
lambda x: x.agg(["sum", "count"]),
lambda x: x.agg("std"),
lambda x: x.agg("var"),
lambda x: x.agg("sem"),
lambda x: x.agg("size"),
lambda x: x.agg("ohlc"),
],
)
@not_implemented_mark
def test_groupby_finalize_not_implemented(obj, method):
obj.attrs = {"a": 1}
result = method(obj.groupby([0, 0]))
assert result.attrs == {"a": 1}
def test_finalize_frame_series_name():
# https://github.com/pandas-dev/pandas/pull/37186/files#r506978889
# ensure we don't copy the column `name` to the Series.
df = pd.DataFrame({"name": [1, 2]})
result = pd.Series([1, 2]).__finalize__(df)
assert result.name is None