Skip to content

Commit e153c12

Browse files
TomAugspurgerPingviinituutti
authored andcommitted
Test nested PandasArray (pandas-dev#24993)
1 parent b3c5b8c commit e153c12

File tree

5 files changed

+326
-36
lines changed

5 files changed

+326
-36
lines changed

pandas/core/arrays/numpy_.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def __getitem__(self, item):
222222
item = item._ndarray
223223

224224
result = self._ndarray[item]
225-
if not lib.is_scalar(result):
225+
if not lib.is_scalar(item):
226226
result = type(self)(result)
227227
return result
228228

pandas/tests/extension/numpy_/__init__.py

Whitespace-only changes.
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import numpy as np
2+
import pytest
3+
4+
from pandas.core.arrays.numpy_ import PandasArray
5+
6+
7+
@pytest.fixture
8+
def allow_in_pandas(monkeypatch):
9+
"""
10+
A monkeypatch to tell pandas to let us in.
11+
12+
By default, passing a PandasArray to an index / series / frame
13+
constructor will unbox that PandasArray to an ndarray, and treat
14+
it as a non-EA column. We don't want people using EAs without
15+
reason.
16+
17+
The mechanism for this is a check against ABCPandasArray
18+
in each constructor.
19+
20+
But, for testing, we need to allow them in pandas. So we patch
21+
the _typ of PandasArray, so that we evade the ABCPandasArray
22+
check.
23+
"""
24+
with monkeypatch.context() as m:
25+
m.setattr(PandasArray, '_typ', 'extension')
26+
yield
27+
28+
29+
@pytest.fixture
30+
def na_value():
31+
return np.nan
32+
33+
34+
@pytest.fixture
35+
def na_cmp():
36+
def cmp(a, b):
37+
return np.isnan(a) and np.isnan(b)
38+
return cmp

pandas/tests/extension/test_numpy.py renamed to pandas/tests/extension/numpy_/test_numpy.py

+1-35
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,14 @@
66
from pandas.core.arrays.numpy_ import PandasArray, PandasDtype
77
import pandas.util.testing as tm
88

9-
from . import base
9+
from .. import base
1010

1111

1212
@pytest.fixture
1313
def dtype():
1414
return PandasDtype(np.dtype('float'))
1515

1616

17-
@pytest.fixture
18-
def allow_in_pandas(monkeypatch):
19-
"""
20-
A monkeypatch to tells pandas to let us in.
21-
22-
By default, passing a PandasArray to an index / series / frame
23-
constructor will unbox that PandasArray to an ndarray, and treat
24-
it as a non-EA column. We don't want people using EAs without
25-
reason.
26-
27-
The mechanism for this is a check against ABCPandasArray
28-
in each constructor.
29-
30-
But, for testing, we need to allow them in pandas. So we patch
31-
the _typ of PandasArray, so that we evade the ABCPandasArray
32-
check.
33-
"""
34-
with monkeypatch.context() as m:
35-
m.setattr(PandasArray, '_typ', 'extension')
36-
yield
37-
38-
3917
@pytest.fixture
4018
def data(allow_in_pandas, dtype):
4119
return PandasArray(np.arange(1, 101, dtype=dtype._dtype))
@@ -46,18 +24,6 @@ def data_missing(allow_in_pandas):
4624
return PandasArray(np.array([np.nan, 1.0]))
4725

4826

49-
@pytest.fixture
50-
def na_value():
51-
return np.nan
52-
53-
54-
@pytest.fixture
55-
def na_cmp():
56-
def cmp(a, b):
57-
return np.isnan(a) and np.isnan(b)
58-
return cmp
59-
60-
6127
@pytest.fixture
6228
def data_for_sorting(allow_in_pandas):
6329
"""Length-3 array with a known sort order.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
"""
2+
Tests for PandasArray with nested data. Users typically won't create
3+
these objects via `pd.array`, but they can show up through `.array`
4+
on a Series with nested data.
5+
6+
We partition these tests into their own file, as many of the base
7+
tests fail, as they aren't appropriate for nested data. It is easier
8+
to have a seperate file with its own data generating fixtures, than
9+
trying to skip based upon the value of a fixture.
10+
"""
11+
import pytest
12+
13+
import pandas as pd
14+
from pandas.core.arrays.numpy_ import PandasArray, PandasDtype
15+
16+
from .. import base
17+
18+
# For NumPy <1.16, np.array([np.nan, (1,)]) raises
19+
# ValueError: setting an array element with a sequence.
20+
np = pytest.importorskip('numpy', minversion='1.16.0')
21+
22+
23+
@pytest.fixture
24+
def dtype():
25+
return PandasDtype(np.dtype('object'))
26+
27+
28+
@pytest.fixture
29+
def data(allow_in_pandas, dtype):
30+
return pd.Series([(i,) for i in range(100)]).array
31+
32+
33+
@pytest.fixture
34+
def data_missing(allow_in_pandas):
35+
return PandasArray(np.array([np.nan, (1,)]))
36+
37+
38+
@pytest.fixture
39+
def data_for_sorting(allow_in_pandas):
40+
"""Length-3 array with a known sort order.
41+
42+
This should be three items [B, C, A] with
43+
A < B < C
44+
"""
45+
# Use an empty tuple for first element, then remove,
46+
# to disable np.array's shape inference.
47+
return PandasArray(
48+
np.array([(), (2,), (3,), (1,)])[1:]
49+
)
50+
51+
52+
@pytest.fixture
53+
def data_missing_for_sorting(allow_in_pandas):
54+
"""Length-3 array with a known sort order.
55+
56+
This should be three items [B, NA, A] with
57+
A < B and NA missing.
58+
"""
59+
return PandasArray(
60+
np.array([(1,), np.nan, (0,)])
61+
)
62+
63+
64+
@pytest.fixture
65+
def data_for_grouping(allow_in_pandas):
66+
"""Data for factorization, grouping, and unique tests.
67+
68+
Expected to be like [B, B, NA, NA, A, A, B, C]
69+
70+
Where A < B < C and NA is missing
71+
"""
72+
a, b, c = (1,), (2,), (3,)
73+
return PandasArray(np.array(
74+
[b, b, np.nan, np.nan, a, a, b, c]
75+
))
76+
77+
78+
skip_nested = pytest.mark.skip(reason="Skipping for nested PandasArray")
79+
80+
81+
class BaseNumPyTests(object):
82+
pass
83+
84+
85+
class TestCasting(BaseNumPyTests, base.BaseCastingTests):
86+
87+
@skip_nested
88+
def test_astype_str(self, data):
89+
pass
90+
91+
92+
class TestConstructors(BaseNumPyTests, base.BaseConstructorsTests):
93+
@pytest.mark.skip(reason="We don't register our dtype")
94+
# We don't want to register. This test should probably be split in two.
95+
def test_from_dtype(self, data):
96+
pass
97+
98+
@skip_nested
99+
def test_array_from_scalars(self, data):
100+
pass
101+
102+
103+
class TestDtype(BaseNumPyTests, base.BaseDtypeTests):
104+
105+
@pytest.mark.skip(reason="Incorrect expected.")
106+
# we unsurprisingly clash with a NumPy name.
107+
def test_check_dtype(self, data):
108+
pass
109+
110+
111+
class TestGetitem(BaseNumPyTests, base.BaseGetitemTests):
112+
113+
@skip_nested
114+
def test_getitem_scalar(self, data):
115+
pass
116+
117+
@skip_nested
118+
def test_take_series(self, data):
119+
pass
120+
121+
122+
class TestGroupby(BaseNumPyTests, base.BaseGroupbyTests):
123+
@skip_nested
124+
def test_groupby_extension_apply(self, data_for_grouping, op):
125+
pass
126+
127+
128+
class TestInterface(BaseNumPyTests, base.BaseInterfaceTests):
129+
@skip_nested
130+
def test_array_interface(self, data):
131+
# NumPy array shape inference
132+
pass
133+
134+
135+
class TestMethods(BaseNumPyTests, base.BaseMethodsTests):
136+
137+
@pytest.mark.skip(reason="TODO: remove?")
138+
def test_value_counts(self, all_data, dropna):
139+
pass
140+
141+
@pytest.mark.skip(reason="Incorrect expected")
142+
# We have a bool dtype, so the result is an ExtensionArray
143+
# but expected is not
144+
def test_combine_le(self, data_repeated):
145+
super(TestMethods, self).test_combine_le(data_repeated)
146+
147+
@skip_nested
148+
def test_combine_add(self, data_repeated):
149+
# Not numeric
150+
pass
151+
152+
@skip_nested
153+
def test_shift_fill_value(self, data):
154+
# np.array shape inference. Shift implementation fails.
155+
super().test_shift_fill_value(data)
156+
157+
@skip_nested
158+
def test_unique(self, data, box, method):
159+
# Fails creating expected
160+
pass
161+
162+
@skip_nested
163+
def test_fillna_copy_frame(self, data_missing):
164+
# The "scalar" for this array isn't a scalar.
165+
pass
166+
167+
@skip_nested
168+
def test_fillna_copy_series(self, data_missing):
169+
# The "scalar" for this array isn't a scalar.
170+
pass
171+
172+
@skip_nested
173+
def test_hash_pandas_object_works(self, data, as_frame):
174+
# ndarray of tuples not hashable
175+
pass
176+
177+
@skip_nested
178+
def test_searchsorted(self, data_for_sorting, as_series):
179+
# Test setup fails.
180+
pass
181+
182+
@skip_nested
183+
def test_where_series(self, data, na_value, as_frame):
184+
# Test setup fails.
185+
pass
186+
187+
@skip_nested
188+
def test_repeat(self, data, repeats, as_series, use_numpy):
189+
# Fails creating expected
190+
pass
191+
192+
193+
class TestPrinting(BaseNumPyTests, base.BasePrintingTests):
194+
pass
195+
196+
197+
class TestMissing(BaseNumPyTests, base.BaseMissingTests):
198+
199+
@skip_nested
200+
def test_fillna_scalar(self, data_missing):
201+
# Non-scalar "scalar" values.
202+
pass
203+
204+
@skip_nested
205+
def test_fillna_series_method(self, data_missing, method):
206+
# Non-scalar "scalar" values.
207+
pass
208+
209+
@skip_nested
210+
def test_fillna_series(self, data_missing):
211+
# Non-scalar "scalar" values.
212+
pass
213+
214+
@skip_nested
215+
def test_fillna_frame(self, data_missing):
216+
# Non-scalar "scalar" values.
217+
pass
218+
219+
220+
class TestReshaping(BaseNumPyTests, base.BaseReshapingTests):
221+
222+
@pytest.mark.skip("Incorrect parent test")
223+
# not actually a mixed concat, since we concat int and int.
224+
def test_concat_mixed_dtypes(self, data):
225+
super(TestReshaping, self).test_concat_mixed_dtypes(data)
226+
227+
@skip_nested
228+
def test_merge(self, data, na_value):
229+
# Fails creating expected
230+
pass
231+
232+
@skip_nested
233+
def test_merge_on_extension_array(self, data):
234+
# Fails creating expected
235+
pass
236+
237+
@skip_nested
238+
def test_merge_on_extension_array_duplicates(self, data):
239+
# Fails creating expected
240+
pass
241+
242+
243+
class TestSetitem(BaseNumPyTests, base.BaseSetitemTests):
244+
245+
@skip_nested
246+
def test_setitem_scalar_series(self, data, box_in_series):
247+
pass
248+
249+
@skip_nested
250+
def test_setitem_sequence(self, data, box_in_series):
251+
pass
252+
253+
@skip_nested
254+
def test_setitem_sequence_mismatched_length_raises(self, data, as_array):
255+
pass
256+
257+
@skip_nested
258+
def test_setitem_sequence_broadcasts(self, data, box_in_series):
259+
pass
260+
261+
@skip_nested
262+
def test_setitem_loc_scalar_mixed(self, data):
263+
pass
264+
265+
@skip_nested
266+
def test_setitem_loc_scalar_multiple_homogoneous(self, data):
267+
pass
268+
269+
@skip_nested
270+
def test_setitem_iloc_scalar_mixed(self, data):
271+
pass
272+
273+
@skip_nested
274+
def test_setitem_iloc_scalar_multiple_homogoneous(self, data):
275+
pass
276+
277+
@skip_nested
278+
def test_setitem_mask_broadcast(self, data, setter):
279+
pass
280+
281+
@skip_nested
282+
def test_setitem_scalar_key_sequence_raise(self, data):
283+
pass
284+
285+
286+
# Skip Arithmetics, NumericReduce, BooleanReduce, Parsing

0 commit comments

Comments
 (0)