123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- """
- This file contains a minimal set of tests for compliance with the extension
- array interface test suite, and should contain no other tests.
- The test suite for the full functionality of the array is located in
- `pandas/tests/arrays/`.
- The tests in this file are inherited from the BaseExtensionTests, and only
- minimal tweaks should be applied to get the tests passing (by overwriting a
- parent method).
- Additional tests should either be added to one of the BaseExtensionTests
- classes (if they are relevant for the extension interface for all dtypes), or
- be added to the array-specific tests in `pandas/tests/arrays/`.
- """
- import numpy as np
- import pytest
- from pandas.compat import (
- IS64,
- is_platform_windows,
- )
- import pandas as pd
- import pandas._testing as tm
- from pandas.api.types import (
- is_extension_array_dtype,
- is_integer_dtype,
- )
- from pandas.core.arrays.integer import (
- Int8Dtype,
- Int16Dtype,
- Int32Dtype,
- Int64Dtype,
- UInt8Dtype,
- UInt16Dtype,
- UInt32Dtype,
- UInt64Dtype,
- )
- from pandas.tests.extension import base
- def make_data():
- return list(range(1, 9)) + [pd.NA] + list(range(10, 98)) + [pd.NA] + [99, 100]
- @pytest.fixture(
- params=[
- Int8Dtype,
- Int16Dtype,
- Int32Dtype,
- Int64Dtype,
- UInt8Dtype,
- UInt16Dtype,
- UInt32Dtype,
- UInt64Dtype,
- ]
- )
- def dtype(request):
- return request.param()
- @pytest.fixture
- def data(dtype):
- return pd.array(make_data(), dtype=dtype)
- @pytest.fixture
- def data_for_twos(dtype):
- return pd.array(np.ones(100) * 2, dtype=dtype)
- @pytest.fixture
- def data_missing(dtype):
- return pd.array([pd.NA, 1], dtype=dtype)
- @pytest.fixture
- def data_for_sorting(dtype):
- return pd.array([1, 2, 0], dtype=dtype)
- @pytest.fixture
- def data_missing_for_sorting(dtype):
- return pd.array([1, pd.NA, 0], dtype=dtype)
- @pytest.fixture
- def na_cmp():
- # we are pd.NA
- return lambda x, y: x is pd.NA and y is pd.NA
- @pytest.fixture
- def na_value():
- return pd.NA
- @pytest.fixture
- def data_for_grouping(dtype):
- b = 1
- a = 0
- c = 2
- na = pd.NA
- return pd.array([b, b, na, na, a, a, b, c], dtype=dtype)
- class TestDtype(base.BaseDtypeTests):
- pass
- class TestArithmeticOps(base.BaseArithmeticOpsTests):
- def check_opname(self, s, op_name, other, exc=None):
- # overwriting to indicate ops don't raise an error
- super().check_opname(s, op_name, other, exc=None)
- def _check_op(self, s, op, other, op_name, exc=NotImplementedError):
- if exc is None:
- sdtype = tm.get_dtype(s)
- if (
- hasattr(other, "dtype")
- and not is_extension_array_dtype(other.dtype)
- and is_integer_dtype(other.dtype)
- and sdtype.is_unsigned_integer
- ):
- # TODO: comment below is inaccurate; other can be int8, int16, ...
- # and the trouble is that e.g. if s is UInt8 and other is int8,
- # then result is UInt16
- # other is np.int64 and would therefore always result in
- # upcasting, so keeping other as same numpy_dtype
- other = other.astype(sdtype.numpy_dtype)
- result = op(s, other)
- expected = self._combine(s, other, op)
- if op_name in ("__rtruediv__", "__truediv__", "__div__"):
- expected = expected.fillna(np.nan).astype("Float64")
- else:
- # combine method result in 'biggest' (int64) dtype
- expected = expected.astype(sdtype)
- self.assert_equal(result, expected)
- else:
- with pytest.raises(exc):
- op(s, other)
- def _check_divmod_op(self, s, op, other, exc=None):
- super()._check_divmod_op(s, op, other, None)
- class TestComparisonOps(base.BaseComparisonOpsTests):
- def _check_op(self, s, op, other, op_name, exc=NotImplementedError):
- if exc is None:
- result = op(s, other)
- # Override to do the astype to boolean
- expected = s.combine(other, op).astype("boolean")
- self.assert_series_equal(result, expected)
- else:
- with pytest.raises(exc):
- op(s, other)
- def check_opname(self, s, op_name, other, exc=None):
- super().check_opname(s, op_name, other, exc=None)
- def _compare_other(self, s, data, op, other):
- op_name = f"__{op.__name__}__"
- self.check_opname(s, op_name, other)
- class TestInterface(base.BaseInterfaceTests):
- pass
- class TestConstructors(base.BaseConstructorsTests):
- pass
- class TestReshaping(base.BaseReshapingTests):
- pass
- # for test_concat_mixed_dtypes test
- # concat of an Integer and Int coerces to object dtype
- # TODO(jreback) once integrated this would
- class TestGetitem(base.BaseGetitemTests):
- pass
- class TestSetitem(base.BaseSetitemTests):
- pass
- class TestIndex(base.BaseIndexTests):
- pass
- class TestMissing(base.BaseMissingTests):
- pass
- class TestMethods(base.BaseMethodsTests):
- _combine_le_expected_dtype = object # TODO: can we make this boolean?
- class TestCasting(base.BaseCastingTests):
- pass
- class TestGroupby(base.BaseGroupbyTests):
- pass
- class TestNumericReduce(base.BaseNumericReduceTests):
- def check_reduce(self, s, op_name, skipna):
- # overwrite to ensure pd.NA is tested instead of np.nan
- # https://github.com/pandas-dev/pandas/issues/30958
- if op_name == "count":
- result = getattr(s, op_name)()
- expected = getattr(s.dropna().astype("int64"), op_name)()
- else:
- result = getattr(s, op_name)(skipna=skipna)
- expected = getattr(s.dropna().astype("int64"), op_name)(skipna=skipna)
- if not skipna and s.isna().any():
- expected = pd.NA
- tm.assert_almost_equal(result, expected)
- @pytest.mark.skip(reason="Tested in tests/reductions/test_reductions.py")
- class TestBooleanReduce(base.BaseBooleanReduceTests):
- pass
- class TestAccumulation(base.BaseAccumulateTests):
- def check_accumulate(self, s, op_name, skipna):
- # overwrite to ensure pd.NA is tested instead of np.nan
- # https://github.com/pandas-dev/pandas/issues/30958
- length = 64
- if not IS64 or is_platform_windows():
- if not s.dtype.itemsize == 8:
- length = 32
- if s.dtype.name.startswith("U"):
- expected_dtype = f"UInt{length}"
- else:
- expected_dtype = f"Int{length}"
- if op_name == "cumsum":
- result = getattr(s, op_name)(skipna=skipna)
- expected = pd.Series(
- pd.array(
- getattr(s.astype("float64"), op_name)(skipna=skipna),
- dtype=expected_dtype,
- )
- )
- tm.assert_series_equal(result, expected)
- elif op_name in ["cummax", "cummin"]:
- result = getattr(s, op_name)(skipna=skipna)
- expected = pd.Series(
- pd.array(
- getattr(s.astype("float64"), op_name)(skipna=skipna),
- dtype=s.dtype,
- )
- )
- tm.assert_series_equal(result, expected)
- elif op_name == "cumprod":
- result = getattr(s[:12], op_name)(skipna=skipna)
- expected = pd.Series(
- pd.array(
- getattr(s[:12].astype("float64"), op_name)(skipna=skipna),
- dtype=expected_dtype,
- )
- )
- tm.assert_series_equal(result, expected)
- else:
- raise NotImplementedError(f"{op_name} not supported")
- @pytest.mark.parametrize("skipna", [True, False])
- def test_accumulate_series_raises(self, data, all_numeric_accumulations, skipna):
- pass
- class TestPrinting(base.BasePrintingTests):
- pass
- class TestParsing(base.BaseParsingTests):
- pass
- class Test2DCompat(base.Dim2CompatTests):
- pass
|