Initial commit: 首次建仓,建立目录结构
This commit is contained in:
@ -0,0 +1,392 @@
|
||||
from collections.abc import Callable
|
||||
import copy
|
||||
from datetime import datetime
|
||||
import operator
|
||||
import re
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.properties import cache_readonly
|
||||
|
||||
import pandas as pd
|
||||
import pandas._testing as tm
|
||||
from pandas.api.typing import Expression
|
||||
from pandas.tests.test_register_accessor import ensure_removed
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("expr", "expected_values", "expected_str"),
|
||||
[
|
||||
(pd.col("a"), [1, 2], "col('a')"),
|
||||
(pd.col("a") * 2, [2, 4], "col('a') * 2"),
|
||||
(pd.col("a").sum(), [3, 3], "col('a').sum()"),
|
||||
(pd.col("a") + 1, [2, 3], "col('a') + 1"),
|
||||
(1 + pd.col("a"), [2, 3], "1 + col('a')"),
|
||||
(pd.col("a") - 1, [0, 1], "col('a') - 1"),
|
||||
(1 - pd.col("a"), [0, -1], "1 - col('a')"),
|
||||
(pd.col("a") * 1, [1, 2], "col('a') * 1"),
|
||||
(1 * pd.col("a"), [1, 2], "1 * col('a')"),
|
||||
(2 ** pd.col("a"), [2, 4], "2 ** col('a')"),
|
||||
(pd.col("a") ** 2, [1, 4], "col('a') ** 2"),
|
||||
(pd.col("a") / 1, [1.0, 2.0], "col('a') / 1"),
|
||||
(1 / pd.col("a"), [1.0, 0.5], "1 / col('a')"),
|
||||
(pd.col("a") // 1, [1, 2], "col('a') // 1"),
|
||||
(1 // pd.col("a"), [1, 0], "1 // col('a')"),
|
||||
(pd.col("a") % 1, [0, 0], "col('a') % 1"),
|
||||
(1 % pd.col("a"), [0, 1], "1 % col('a')"),
|
||||
(pd.col("a") > 1, [False, True], "col('a') > 1"),
|
||||
(pd.col("a") >= 1, [True, True], "col('a') >= 1"),
|
||||
(pd.col("a") < 1, [False, False], "col('a') < 1"),
|
||||
(pd.col("a") <= 1, [True, False], "col('a') <= 1"),
|
||||
(pd.col("a") == 1, [True, False], "col('a') == 1"),
|
||||
(np.power(pd.col("a"), 2), [1, 4], "power(col('a'), 2)"),
|
||||
(np.divide(pd.col("a"), pd.col("a")), [1.0, 1.0], "divide(col('a'), col('a'))"),
|
||||
(
|
||||
(pd.col("a") + 1) * (pd.col("b") + 2),
|
||||
[10, 18],
|
||||
"(col('a') + 1) * (col('b') + 2)",
|
||||
),
|
||||
(
|
||||
(pd.col("a") - 1).astype("bool"),
|
||||
[False, True],
|
||||
"(col('a') - 1).astype('bool')",
|
||||
),
|
||||
# Unary operators
|
||||
(-pd.col("a"), [-1, -2], "-col('a')"),
|
||||
(+pd.col("a"), [1, 2], "+col('a')"),
|
||||
(-(pd.col("a") + 1), [-2, -3], "-(col('a') + 1)"),
|
||||
(-pd.col("a") * 2, [-2, -4], "(-col('a')) * 2"),
|
||||
(abs(pd.col("a")), [1, 2], "abs(col('a'))"),
|
||||
(abs(pd.col("a") - 2), [1, 0], "abs(col('a') - 2)"),
|
||||
],
|
||||
)
|
||||
def test_col_simple(
|
||||
expr: Expression, expected_values: list[object], expected_str: str
|
||||
) -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/64267
|
||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2], "b": [3, 4], "c": expected_values})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
assert str(expr) == expected_str
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("op", "expected_values", "expected_str"),
|
||||
[
|
||||
(operator.iadd, [3, 4], "col('a') + 2"),
|
||||
(operator.iand, [0, 2], "col('a') & 2"),
|
||||
(operator.ifloordiv, [0, 1], "col('a') // 2"),
|
||||
(operator.imod, [1, 0], "col('a') % 2"),
|
||||
(operator.imul, [2, 4], "col('a') * 2"),
|
||||
(operator.ior, [3, 2], "col('a') | 2"),
|
||||
(operator.ipow, [1, 4], "col('a') ** 2"),
|
||||
(operator.isub, [-1, 0], "col('a') - 2"),
|
||||
(operator.itruediv, [0.5, 1.0], "col('a') / 2"),
|
||||
(operator.ixor, [3, 0], "col('a') ^ 2"),
|
||||
],
|
||||
)
|
||||
def test_inplace_ops(
|
||||
op: Callable, expected_values: list[object], expected_str: str
|
||||
) -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/64267
|
||||
df = pd.DataFrame({"a": [1, 2]})
|
||||
expr = pd.col("a")
|
||||
expr = op(expr, 2)
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2], "c": expected_values})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
assert str(expr) == expected_str
|
||||
|
||||
|
||||
def test_matmul():
|
||||
# https://github.com/pandas-dev/pandas/pull/64267
|
||||
df = pd.DataFrame({"a": [1, 2]})
|
||||
|
||||
expr = pd.col("a") @ [3, 4]
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2], "c": [11, 11]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
assert str(expr) == "col('a') @ [3, 4]"
|
||||
|
||||
expr = [3, 4] @ pd.col("a")
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2], "c": [11, 11]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
assert str(expr) == "[3, 4] @ col('a')"
|
||||
|
||||
|
||||
def test_frame_getitem() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
expr = pd.col("a") == 2
|
||||
result = df[expr]
|
||||
expected = df.iloc[[1]]
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_frame_setitem() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
expr = pd.col("a") == 2
|
||||
|
||||
result = df.copy()
|
||||
result[expr] = 100
|
||||
expected = pd.DataFrame({"a": [1, 100], "b": [3, 100]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_frame_loc() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
expr = pd.col("a") == 2
|
||||
result = df.copy()
|
||||
result.loc[expr, "b"] = 100
|
||||
expected = pd.DataFrame({"a": [1, 2], "b": [3, 100]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_frame_iloc() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
expr = pd.col("a") == 2
|
||||
result = df.copy()
|
||||
result.iloc[expr, 1] = 100
|
||||
expected = pd.DataFrame({"a": [1, 2], "b": [3, 100]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("expr", "expected_values", "expected_str"),
|
||||
[
|
||||
(pd.col("a").dt.year, [2020], "col('a').dt.year"),
|
||||
(pd.col("a").dt.strftime("%B"), ["January"], "col('a').dt.strftime('%B')"),
|
||||
(pd.col("b").str.upper(), ["FOO"], "col('b').str.upper()"),
|
||||
],
|
||||
)
|
||||
def test_namespaces(
|
||||
expr: Expression, expected_values: list[object], expected_str: str
|
||||
) -> None:
|
||||
df = pd.DataFrame({"a": [datetime(2020, 1, 1)], "b": ["foo"]})
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame(
|
||||
{"a": [datetime(2020, 1, 1)], "b": ["foo"], "c": expected_values}
|
||||
)
|
||||
tm.assert_frame_equal(result, expected, check_dtype=False)
|
||||
assert str(expr) == expected_str
|
||||
|
||||
|
||||
def test_invalid() -> None:
|
||||
df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
with pytest.raises(ValueError, match=r"did you mean one of \['a', 'b'\] instead"):
|
||||
df.assign(c=pd.col("c").mean())
|
||||
df = pd.DataFrame({f"col_{i}": [0] for i in range(11)})
|
||||
msg = (
|
||||
"did you mean one of "
|
||||
r"\['col_0', 'col_1', 'col_2', 'col_3', "
|
||||
"'col_4', 'col_5', 'col_6', 'col_7', "
|
||||
r"'col_8', 'col_9',\.\.\.\] instead"
|
||||
)
|
||||
""
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
df.assign(c=pd.col("c").mean())
|
||||
|
||||
|
||||
def test_custom_accessor() -> None:
|
||||
df = pd.DataFrame({"a": [1, 2, 3]})
|
||||
|
||||
class XYZAccessor:
|
||||
def __init__(self, pandas_obj):
|
||||
self._obj = pandas_obj
|
||||
|
||||
def mean(self):
|
||||
return self._obj.mean()
|
||||
|
||||
with ensure_removed(pd.Series, "xyz"):
|
||||
pd.api.extensions.register_series_accessor("xyz")(XYZAccessor)
|
||||
result = df.assign(b=pd.col("a").xyz.mean())
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": [2.0, 2.0, 2.0]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("expr", "expected_values", "expected_str"),
|
||||
[
|
||||
(
|
||||
pd.col("a") & pd.col("b"),
|
||||
[False, False, True, False],
|
||||
"col('a') & col('b')",
|
||||
),
|
||||
(
|
||||
pd.col("a") & True,
|
||||
[True, False, True, False],
|
||||
"col('a') & True",
|
||||
),
|
||||
(
|
||||
pd.col("a") | pd.col("b"),
|
||||
[True, True, True, True],
|
||||
"col('a') | col('b')",
|
||||
),
|
||||
(
|
||||
pd.col("a") | False,
|
||||
[True, False, True, False],
|
||||
"col('a') | False",
|
||||
),
|
||||
(
|
||||
pd.col("a") ^ pd.col("b"),
|
||||
[True, True, False, True],
|
||||
"col('a') ^ col('b')",
|
||||
),
|
||||
(
|
||||
pd.col("a") ^ True,
|
||||
[False, True, False, True],
|
||||
"col('a') ^ True",
|
||||
),
|
||||
(
|
||||
~pd.col("a"),
|
||||
[False, True, False, True],
|
||||
"~col('a')",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_col_logical_ops(
|
||||
expr: Expression, expected_values: list[bool], expected_str: str
|
||||
) -> None:
|
||||
# https://github.com/pandas-dev/pandas/issues/63322
|
||||
df = pd.DataFrame({"a": [True, False, True, False], "b": [False, True, True, True]})
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame(
|
||||
{
|
||||
"a": [True, False, True, False],
|
||||
"b": [False, True, True, True],
|
||||
"c": expected_values,
|
||||
}
|
||||
)
|
||||
tm.assert_frame_equal(result, expected)
|
||||
assert str(expr) == expected_str
|
||||
|
||||
# Test that the expression works with .loc
|
||||
result = df.loc[expr]
|
||||
expected = df[expected_values]
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_expression_getitem() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2, 3]})
|
||||
expr = pd.col("a")[1]
|
||||
expected_str = "col('a')[1]"
|
||||
|
||||
assert str(expr) == expected_str
|
||||
|
||||
result = df.assign(b=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": [2, 2, 2]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_property() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2, 3]})
|
||||
expr = pd.col("a").index
|
||||
expected_str = "col('a').index"
|
||||
|
||||
assert str(expr) == expected_str
|
||||
|
||||
result = df.assign(b=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": [0, 1, 2]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_cached_property() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
# Ensure test is valid
|
||||
assert isinstance(pd.Index.dtype, cache_readonly)
|
||||
|
||||
df = pd.DataFrame({"a": [1, 2, 3]})
|
||||
expr = pd.col("a").index.dtype
|
||||
expected_str = "col('a').index.dtype"
|
||||
assert str(expr) == expected_str
|
||||
|
||||
result = df.assign(b=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": np.int64})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_qcut() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2, 3]})
|
||||
expr = pd.qcut(pd.col("a"), 3)
|
||||
expected_str = "qcut(x=col('a'), q=3, labels=None, retbins=False, precision=3)"
|
||||
assert str(expr) == expected_str, str(expr)
|
||||
|
||||
result = df.assign(b=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": pd.qcut(df["a"], 3)})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
def test_where() -> None:
|
||||
# https://github.com/pandas-dev/pandas/pull/63439
|
||||
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
|
||||
expr = pd.col("a").where(pd.col("b") == 5, 100)
|
||||
expected_str = "col('a').where(col('b') == 5, 100)"
|
||||
assert str(expr) == expected_str, str(expr)
|
||||
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [100, 2, 100]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
expr = pd.col("a").where(pd.col("b") == 5, pd.col("a") + 1)
|
||||
expected_str = "col('a').where(col('b') == 5, col('a') + 1)"
|
||||
assert str(expr) == expected_str, str(expr)
|
||||
|
||||
result = df.assign(c=expr)
|
||||
expected = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [2, 2, 4]})
|
||||
tm.assert_frame_equal(result, expected)
|
||||
|
||||
|
||||
# Unsupported ops
|
||||
def test_bool():
|
||||
with pytest.raises(TypeError, match="boolean value of an expression is ambiguous"):
|
||||
bool(pd.col("a"))
|
||||
|
||||
|
||||
def test_iter():
|
||||
with pytest.raises(TypeError, match="Expression objects are not iterable"):
|
||||
iter(pd.col("a"))
|
||||
|
||||
|
||||
def test_contains():
|
||||
# Python 3.14 changes the message from "is not iterable" to
|
||||
# "is not a container or iterable"
|
||||
with pytest.raises(
|
||||
TypeError, match="argument of type 'Expression' is not .*iterable"
|
||||
):
|
||||
1 in pd.col("a")
|
||||
|
||||
|
||||
def test_copy():
|
||||
with pytest.raises(TypeError, match="Expression objects are not copiable"):
|
||||
copy.copy(pd.col("a"))
|
||||
|
||||
|
||||
def test_deepcopy():
|
||||
with pytest.raises(TypeError, match="Expression objects are not copiable"):
|
||||
copy.deepcopy(pd.col("a"))
|
||||
|
||||
|
||||
def test_divmod():
|
||||
msg = re.escape("unsupported operand type(s) for divmod(): 'Expression' and 'int'")
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
divmod(pd.col("a"), 2)
|
||||
|
||||
|
||||
def test_len():
|
||||
with pytest.raises(TypeError, match="object of type 'Expression' has no len()"):
|
||||
len(pd.col("a"))
|
||||
|
||||
|
||||
def test_round():
|
||||
msg = "type Expression doesn't define __round__ method"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
round(pd.col("a"), 2)
|
||||
Reference in New Issue
Block a user