Skip to content

Commit b8752f3

Browse files
committed
Merge branch 'master' into PR_TOOL_MERGE_PR_19714
2 parents 6647c9f + e362281 commit b8752f3

30 files changed

+259
-125
lines changed

ci/lint.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ if [ "$LINT" ]; then
111111
RET=1
112112
fi
113113

114+
# Check for the following code in the extension array base tests
115+
# tm.assert_frame_equal
116+
# tm.assert_series_equal
117+
grep -r -E --include '*.py' --exclude base.py 'tm.assert_(series|frame)_equal' pandas/tests/extension/base
118+
119+
if [ $? = "0" ]; then
120+
RET=1
121+
fi
122+
114123
echo "Check for invalid testing DONE"
115124

116125
# Check for imports from pandas.core.common instead

doc/source/whatsnew/v0.23.0.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,10 @@ Other Enhancements
295295
- ``IntervalIndex.astype`` now supports conversions between subtypes when passed an ``IntervalDtype`` (:issue:`19197`)
296296
- :class:`IntervalIndex` and its associated constructor methods (``from_arrays``, ``from_breaks``, ``from_tuples``) have gained a ``dtype`` parameter (:issue:`19262`)
297297
- Added :func:`SeriesGroupBy.is_monotonic_increasing` and :func:`SeriesGroupBy.is_monotonic_decreasing` (:issue:`17015`)
298+
- For subclassed ``DataFrames``, :func:`DataFrame.apply` will now preserve the ``Series`` subclass (if defined) when passing the data to the applied function (:issue:`19822`)
298299
- :func:`DataFrame.from_dict` now accepts a ``columns`` argument that can be used to specify the column names when ``orient='index'`` is used (:issue:`18529`)
299300

301+
300302
.. _whatsnew_0230.api_breaking:
301303

302304
Backwards incompatible API changes
@@ -730,7 +732,8 @@ Categorical
730732
``self`` but in a different order (:issue:`19551`)
731733
- Bug in :meth:`Index.astype` with a categorical dtype where the resultant index is not converted to a :class:`CategoricalIndex` for all types of index (:issue:`18630`)
732734
- Bug in :meth:`Series.astype` and ``Categorical.astype()`` where an existing categorical data does not get updated (:issue:`10696`, :issue:`18593`)
733-
- Bug in :class:`Index` constructor with ``dtype=CategoricalDtype(...)`` where ``categories`` and ``ordered`` are not maintained (:issue:`19032`)
735+
- Bug in :class:`Index` constructor with ``dtype=CategoricalDtype(...)`` where ``categories`` and ``ordered`` are not maintained (issue:`19032`)
736+
- Bug in :class:`Series` constructor with scalar and ``dtype=CategoricalDtype(...)`` where ``categories`` and ``ordered`` are not maintained (issue:`19565`)
734737

735738
Datetimelike
736739
^^^^^^^^^^^^
@@ -909,3 +912,4 @@ Other
909912
^^^^^
910913

911914
- Improved error message when attempting to use a Python keyword as an identifier in a ``numexpr`` backed query (:issue:`18221`)
915+
- Bug in accessing a :func:`pandas.get_option`, which raised ``KeyError`` rather than ``OptionError`` when looking up a non-existant option key in some cases (:issue:`19789`)

pandas/core/apply.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def apply_empty_result(self):
162162
pass
163163

164164
if reduce:
165-
return Series(np.nan, index=self.agg_axis)
165+
return self.obj._constructor_sliced(np.nan, index=self.agg_axis)
166166
else:
167167
return self.obj.copy()
168168

@@ -175,11 +175,13 @@ def apply_raw(self):
175175
result = np.apply_along_axis(self.f, self.axis, self.values)
176176

177177
# TODO: mixed type case
178-
from pandas import DataFrame, Series
179178
if result.ndim == 2:
180-
return DataFrame(result, index=self.index, columns=self.columns)
179+
return self.obj._constructor(result,
180+
index=self.index,
181+
columns=self.columns)
181182
else:
182-
return Series(result, index=self.agg_axis)
183+
return self.obj._constructor_sliced(result,
184+
index=self.agg_axis)
183185

184186
def apply_broadcast(self, target):
185187
result_values = np.empty_like(target.values)
@@ -232,7 +234,7 @@ def apply_standard(self):
232234
axis=self.axis,
233235
dummy=dummy,
234236
labels=labels)
235-
return Series(result, index=labels)
237+
return self.obj._constructor_sliced(result, index=labels)
236238
except Exception:
237239
pass
238240

@@ -291,8 +293,7 @@ def wrap_results(self):
291293
return self.wrap_results_for_axis()
292294

293295
# dict of scalars
294-
from pandas import Series
295-
result = Series(results)
296+
result = self.obj._constructor_sliced(results)
296297
result.index = self.res_index
297298

298299
return result
@@ -379,7 +380,6 @@ def wrap_results_for_axis(self):
379380
# we have a non-series and don't want inference
380381
elif not isinstance(results[0], ABCSeries):
381382
from pandas import Series
382-
383383
result = Series(results)
384384
result.index = self.res_index
385385

pandas/core/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,10 @@ def __getattr__(self, key):
196196
if prefix:
197197
prefix += "."
198198
prefix += key
199-
v = object.__getattribute__(self, "d")[key]
199+
try:
200+
v = object.__getattribute__(self, "d")[key]
201+
except KeyError:
202+
raise OptionError("No such option")
200203
if isinstance(v, dict):
201204
return DictWrapper(v, prefix)
202205
else:

pandas/core/dtypes/cast.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ def construct_1d_arraylike_from_scalar(value, length, dtype):
11781178
subarr = DatetimeIndex([value] * length, dtype=dtype)
11791179
elif is_categorical_dtype(dtype):
11801180
from pandas import Categorical
1181-
subarr = Categorical([value] * length)
1181+
subarr = Categorical([value] * length, dtype=dtype)
11821182
else:
11831183
if not isinstance(dtype, (np.dtype, type(np.dtype))):
11841184
dtype = dtype.dtype

pandas/tests/dtypes/test_cast.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
maybe_convert_string_to_object,
2323
maybe_convert_scalar,
2424
find_common_type,
25-
construct_1d_object_array_from_listlike)
25+
construct_1d_object_array_from_listlike,
26+
construct_1d_arraylike_from_scalar)
2627
from pandas.core.dtypes.dtypes import (
2728
CategoricalDtype,
2829
DatetimeTZDtype,
@@ -422,3 +423,15 @@ def test_cast_1d_array(self, datum1, datum2):
422423
@pytest.mark.parametrize('val', [1, 2., None])
423424
def test_cast_1d_array_invalid_scalar(self, val):
424425
pytest.raises(TypeError, construct_1d_object_array_from_listlike, val)
426+
427+
def test_cast_1d_arraylike_from_scalar_categorical(self):
428+
# GH 19565 - Categorical result from scalar did not maintain categories
429+
# and ordering of the passed dtype
430+
cats = ['a', 'b', 'c']
431+
cat_type = CategoricalDtype(categories=cats, ordered=False)
432+
expected = pd.Categorical(['a', 'a'], categories=cats)
433+
result = construct_1d_arraylike_from_scalar('a', len(expected),
434+
cat_type)
435+
tm.assert_categorical_equal(result, expected,
436+
check_category_order=True,
437+
check_dtype=True)

pandas/tests/extension/base/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ class TestMyDtype(BaseDtypeTests):
3131
Your class ``TestDtype`` will inherit all the tests defined on
3232
``BaseDtypeTests``. pytest's fixture discover will supply your ``dtype``
3333
wherever the test requires it. You're free to implement additional tests.
34+
35+
All the tests in these modules use ``self.assert_frame_equal`` or
36+
``self.assert_series_equal`` for dataframe or series comparisons. By default,
37+
they use the usual ``pandas.testing.assert_frame_equal`` and
38+
``pandas.testing.assert_series_equal``. You can override the checks used
39+
by defining the staticmethods ``assert_frame_equal`` and
40+
``assert_series_equal`` on your base test class.
41+
3442
"""
3543
from .casting import BaseCastingTests # noqa
3644
from .constructors import BaseConstructorsTests # noqa

pandas/tests/extension/base/base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import pandas.util.testing as tm
2+
3+
4+
class BaseExtensionTests(object):
5+
assert_series_equal = staticmethod(tm.assert_series_equal)
6+
assert_frame_equal = staticmethod(tm.assert_frame_equal)

pandas/tests/extension/base/casting.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import pandas as pd
22
from pandas.core.internals import ObjectBlock
33

4+
from .base import BaseExtensionTests
45

5-
class BaseCastingTests(object):
6+
7+
class BaseCastingTests(BaseExtensionTests):
68
"""Casting to and from ExtensionDtypes"""
79

810
def test_astype_object_series(self, all_data):

pandas/tests/extension/base/constructors.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
import pandas.util.testing as tm
55
from pandas.core.internals import ExtensionBlock
66

7+
from .base import BaseExtensionTests
78

8-
class BaseConstructorsTests(object):
9+
10+
class BaseConstructorsTests(BaseExtensionTests):
911

1012
def test_series_constructor(self, data):
1113
result = pd.Series(data)

pandas/tests/extension/base/dtype.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import numpy as np
22
import pandas as pd
33

4+
from .base import BaseExtensionTests
45

5-
class BaseDtypeTests(object):
6+
7+
class BaseDtypeTests(BaseExtensionTests):
68
"""Base class for ExtensionDtype classes"""
79

810
def test_name(self, dtype):

pandas/tests/extension/base/getitem.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,74 @@
11
import numpy as np
22

33
import pandas as pd
4-
import pandas.util.testing as tm
54

5+
from .base import BaseExtensionTests
66

7-
class BaseGetitemTests(object):
7+
8+
class BaseGetitemTests(BaseExtensionTests):
89
"""Tests for ExtensionArray.__getitem__."""
910

1011
def test_iloc_series(self, data):
1112
ser = pd.Series(data)
1213
result = ser.iloc[:4]
1314
expected = pd.Series(data[:4])
14-
tm.assert_series_equal(result, expected)
15+
self.assert_series_equal(result, expected)
1516

1617
result = ser.iloc[[0, 1, 2, 3]]
17-
tm.assert_series_equal(result, expected)
18+
self.assert_series_equal(result, expected)
1819

1920
def test_iloc_frame(self, data):
2021
df = pd.DataFrame({"A": data, 'B': np.arange(len(data))})
2122
expected = pd.DataFrame({"A": data[:4]})
2223

2324
# slice -> frame
2425
result = df.iloc[:4, [0]]
25-
tm.assert_frame_equal(result, expected)
26+
self.assert_frame_equal(result, expected)
2627

2728
# sequence -> frame
2829
result = df.iloc[[0, 1, 2, 3], [0]]
29-
tm.assert_frame_equal(result, expected)
30+
self.assert_frame_equal(result, expected)
3031

3132
expected = pd.Series(data[:4], name='A')
3233

3334
# slice -> series
3435
result = df.iloc[:4, 0]
35-
tm.assert_series_equal(result, expected)
36+
self.assert_series_equal(result, expected)
3637

3738
# sequence -> series
3839
result = df.iloc[:4, 0]
39-
tm.assert_series_equal(result, expected)
40+
self.assert_series_equal(result, expected)
4041

4142
def test_loc_series(self, data):
4243
ser = pd.Series(data)
4344
result = ser.loc[:3]
4445
expected = pd.Series(data[:4])
45-
tm.assert_series_equal(result, expected)
46+
self.assert_series_equal(result, expected)
4647

4748
result = ser.loc[[0, 1, 2, 3]]
48-
tm.assert_series_equal(result, expected)
49+
self.assert_series_equal(result, expected)
4950

5051
def test_loc_frame(self, data):
5152
df = pd.DataFrame({"A": data, 'B': np.arange(len(data))})
5253
expected = pd.DataFrame({"A": data[:4]})
5354

5455
# slice -> frame
5556
result = df.loc[:3, ['A']]
56-
tm.assert_frame_equal(result, expected)
57+
self.assert_frame_equal(result, expected)
5758

5859
# sequence -> frame
5960
result = df.loc[[0, 1, 2, 3], ['A']]
60-
tm.assert_frame_equal(result, expected)
61+
self.assert_frame_equal(result, expected)
6162

6263
expected = pd.Series(data[:4], name='A')
6364

6465
# slice -> series
6566
result = df.loc[:3, 'A']
66-
tm.assert_series_equal(result, expected)
67+
self.assert_series_equal(result, expected)
6768

6869
# sequence -> series
6970
result = df.loc[:3, 'A']
70-
tm.assert_series_equal(result, expected)
71+
self.assert_series_equal(result, expected)
7172

7273
def test_getitem_scalar(self, data):
7374
result = data[0]

pandas/tests/extension/base/interface.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
from pandas.core.dtypes.common import is_extension_array_dtype
66
from pandas.core.dtypes.dtypes import ExtensionDtype
77

8+
from .base import BaseExtensionTests
89

9-
class BaseInterfaceTests(object):
10+
11+
class BaseInterfaceTests(BaseExtensionTests):
1012
"""Tests that the basic interface is satisfied."""
1113
# ------------------------------------------------------------------------
1214
# Interface

pandas/tests/extension/base/methods.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
import numpy as np
33

44
import pandas as pd
5-
import pandas.util.testing as tm
65

6+
from .base import BaseExtensionTests
77

8-
class BaseMethodsTests(object):
8+
9+
class BaseMethodsTests(BaseExtensionTests):
910
"""Various Series and DataFrame methods."""
1011

1112
@pytest.mark.parametrize('dropna', [True, False])
@@ -19,13 +20,13 @@ def test_value_counts(self, all_data, dropna):
1920
result = pd.Series(all_data).value_counts(dropna=dropna).sort_index()
2021
expected = pd.Series(other).value_counts(dropna=dropna).sort_index()
2122

22-
tm.assert_series_equal(result, expected)
23+
self.assert_series_equal(result, expected)
2324

2425
def test_count(self, data_missing):
2526
df = pd.DataFrame({"A": data_missing})
2627
result = df.count(axis='columns')
2728
expected = pd.Series([0, 1])
28-
tm.assert_series_equal(result, expected)
29+
self.assert_series_equal(result, expected)
2930

3031
def test_apply_simple_series(self, data):
3132
result = pd.Series(data).apply(id)

pandas/tests/extension/base/missing.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import pandas as pd
44
import pandas.util.testing as tm
55

6+
from .base import BaseExtensionTests
67

7-
class BaseMissingTests(object):
8+
9+
class BaseMissingTests(BaseExtensionTests):
810
def test_isna(self, data_missing):
911
if data_missing._can_hold_na:
1012
expected = np.array([True, False])
@@ -16,30 +18,30 @@ def test_isna(self, data_missing):
1618

1719
result = pd.Series(data_missing).isna()
1820
expected = pd.Series(expected)
19-
tm.assert_series_equal(result, expected)
21+
self.assert_series_equal(result, expected)
2022

2123
def test_dropna_series(self, data_missing):
2224
ser = pd.Series(data_missing)
2325
result = ser.dropna()
2426
expected = ser.iloc[[1]]
25-
tm.assert_series_equal(result, expected)
27+
self.assert_series_equal(result, expected)
2628

2729
def test_dropna_frame(self, data_missing):
2830
df = pd.DataFrame({"A": data_missing})
2931

3032
# defaults
3133
result = df.dropna()
3234
expected = df.iloc[[1]]
33-
tm.assert_frame_equal(result, expected)
35+
self.assert_frame_equal(result, expected)
3436

3537
# axis = 1
3638
result = df.dropna(axis='columns')
3739
expected = pd.DataFrame(index=[0, 1])
38-
tm.assert_frame_equal(result, expected)
40+
self.assert_frame_equal(result, expected)
3941

4042
# multiple
4143
df = pd.DataFrame({"A": data_missing,
4244
"B": [1, np.nan]})
4345
result = df.dropna()
4446
expected = df.iloc[:0]
45-
tm.assert_frame_equal(result, expected)
47+
self.assert_frame_equal(result, expected)

0 commit comments

Comments
 (0)