From 0ec35317a2b924e8db5cf24b12f989c22ac59600 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Wed, 6 Jun 2018 19:22:37 -0400 Subject: [PATCH 01/22] Use of Enums in MultiIndex now supported Due to an unnecessary "orderedness" check in `arrays/categorical.py`'s method `_factorize_from_iterable`, MultiIndex's constructor inappropriately threw a `TypeError` when passed an Enum as one of its iterables. This has been fixed. --- pandas/core/arrays/categorical.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 30f9c56d24f02..8a7fab00179a9 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2523,7 +2523,7 @@ def _factorize_from_iterable(values): ordered=values.ordered) codes = values.codes else: - cat = Categorical(values, ordered=True) + cat = Categorical(values, ordered=False) categories = cat.categories codes = cat.codes return codes, categories From ca40575aa9ff44d7bddceee1c2c0a491fa5f5c03 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Wed, 6 Jun 2018 20:14:50 -0400 Subject: [PATCH 02/22] added a test for `MultiIndex` with `Enum` --- pandas/tests/indexes/test_multi.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index 0ab3447909d9b..d40857903ac79 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -3307,3 +3307,33 @@ def test_duplicate_multiindex_labels(self): with pytest.raises(ValueError): ind.set_levels([['A', 'B', 'A', 'A', 'B'], [2, 1, 3, -2, 5]], inplace=True) + + def test_use_enum(): + # GH 21298 + # Allow use of Enums as one of the factors in a MultiIndex. + + # See https://github.com/pandas-dev/pandas/blob/0c65c57a279e755ab7093db925d1e580f9878dae + # /pandas/util/testing.py#L793-L799. We cannot simply use tm.assert_index_equal, as the + # "expected" index cannot actually be built yet. + from pandas.core.algorithms import take_1d + def _get_ilevel_values(index, level): + # accept level number only + unique = index.levels[level] + labels = index.labels[level] + filled = take_1d(unique.values, labels, fill_value=unique._na_value) + values = unique._shallow_copy(filled, name=index.names[level]) + return values + + from enum import Enum + MyEnum = Enum("MyEnum", "A B") + df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[MyEnum, [1, 2]])) + exp_index_0 = pd.Index([MyEnum.A, MyEnum.A, MyEnum.B, MyEnum.B], dtype='object') + tm.assert_index_equal(_get_ilevel_values(df.columns, 0), exp_index_0) + + expected = df.copy() + df = df.append({(MyEnum.A, 1): "abc", (MyEnum.B, 2): "xyz"}, ignore_index=True) + expected.loc[0, [(MyEnum.A, 1), (MyEnum.B, 2)]] = 'abc', 'xyz' + tm.assert_frame_equal(df, expected) + + + From 38572290ffd1504bfc432451321f036de9548a0d Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Wed, 6 Jun 2018 20:15:46 -0400 Subject: [PATCH 03/22] Update test_multi.py --- pandas/tests/indexes/test_multi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index d40857903ac79..6c03c5ecc23ac 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -3308,7 +3308,7 @@ def test_duplicate_multiindex_labels(self): ind.set_levels([['A', 'B', 'A', 'A', 'B'], [2, 1, 3, -2, 5]], inplace=True) - def test_use_enum(): + def test_use_enum_in_multiindex(self): # GH 21298 # Allow use of Enums as one of the factors in a MultiIndex. From 9aee04ab3b85554e07fa612644ae3e4e1d80379d Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Wed, 6 Jun 2018 20:28:23 -0400 Subject: [PATCH 04/22] PEP8 --- pandas/tests/indexes/test_multi.py | 35 ++++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index 6c03c5ecc23ac..fbcd9ed9a3fd3 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -3307,33 +3307,40 @@ def test_duplicate_multiindex_labels(self): with pytest.raises(ValueError): ind.set_levels([['A', 'B', 'A', 'A', 'B'], [2, 1, 3, -2, 5]], inplace=True) - + def test_use_enum_in_multiindex(self): # GH 21298 # Allow use of Enums as one of the factors in a MultiIndex. - - # See https://github.com/pandas-dev/pandas/blob/0c65c57a279e755ab7093db925d1e580f9878dae - # /pandas/util/testing.py#L793-L799. We cannot simply use tm.assert_index_equal, as the - # "expected" index cannot actually be built yet. + + # See https://github.com/pandas-dev/pandas/blob/ + # 0c65c57a279e755ab7093db925d1e580f9878dae/pandas/util/testing.py#L793-L799. + # We cannot simply use tm.assert_index_equal, as the "expected" index + # cannot actually be built yet. from pandas.core.algorithms import take_1d + def _get_ilevel_values(index, level): # accept level number only unique = index.levels[level] labels = index.labels[level] - filled = take_1d(unique.values, labels, fill_value=unique._na_value) + filled = take_1d( + unique.values, + labels, fill_value=unique._na_value + ) values = unique._shallow_copy(filled, name=index.names[level]) return values - + from enum import Enum MyEnum = Enum("MyEnum", "A B") - df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[MyEnum, [1, 2]])) - exp_index_0 = pd.Index([MyEnum.A, MyEnum.A, MyEnum.B, MyEnum.B], dtype='object') + df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[ + MyEnum, + [1, 2] + ])) + exp_index_0 = pd.Index([MyEnum.A, MyEnum.A, MyEnum.B, MyEnum.B], + dtype='object') tm.assert_index_equal(_get_ilevel_values(df.columns, 0), exp_index_0) - + expected = df.copy() - df = df.append({(MyEnum.A, 1): "abc", (MyEnum.B, 2): "xyz"}, ignore_index=True) + df = df.append({(MyEnum.A, 1): "abc", (MyEnum.B, 2): "xyz"}, + ignore_index=True) expected.loc[0, [(MyEnum.A, 1), (MyEnum.B, 2)]] = 'abc', 'xyz' tm.assert_frame_equal(df, expected) - - - From 60c8f2a741386f77e06aa49b6a515fe2bc2e7811 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 09:11:46 -0400 Subject: [PATCH 05/22] Put imports on top --- pandas/tests/indexes/test_multi.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index fbcd9ed9a3fd3..ee2aac30ae748 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -3311,13 +3311,13 @@ def test_duplicate_multiindex_labels(self): def test_use_enum_in_multiindex(self): # GH 21298 # Allow use of Enums as one of the factors in a MultiIndex. + from enum import Enum + from pandas.core.algorithms import take_1d # See https://github.com/pandas-dev/pandas/blob/ # 0c65c57a279e755ab7093db925d1e580f9878dae/pandas/util/testing.py#L793-L799. # We cannot simply use tm.assert_index_equal, as the "expected" index # cannot actually be built yet. - from pandas.core.algorithms import take_1d - def _get_ilevel_values(index, level): # accept level number only unique = index.levels[level] @@ -3329,7 +3329,6 @@ def _get_ilevel_values(index, level): values = unique._shallow_copy(filled, name=index.names[level]) return values - from enum import Enum MyEnum = Enum("MyEnum", "A B") df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[ MyEnum, From 13d67ca6af29792016f1fdca9fa6f0ab903b0faa Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 09:49:54 -0400 Subject: [PATCH 06/22] Update appveyor-27.yaml --- ci/appveyor-27.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/appveyor-27.yaml b/ci/appveyor-27.yaml index cfc6a796bd77e..74527dfa34fed 100644 --- a/ci/appveyor-27.yaml +++ b/ci/appveyor-27.yaml @@ -27,3 +27,4 @@ dependencies: - pytest - pytest-xdist - moto + - enum34 From e6e66275ea028027c0f043ecbb6c9d7327db2cc4 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 09:50:45 -0400 Subject: [PATCH 07/22] Update circle-27-compat.yaml --- ci/circle-27-compat.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index 81a48d4edf11c..a5c86a0ed2d2a 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -22,6 +22,7 @@ dependencies: # universal - pytest - pytest-xdist + - enum34 - pip: - html5lib==1.0b2 - beautifulsoup4==4.2.1 From d0607f448377ab49e926f899374ca10d16fdceaf Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 09:51:21 -0400 Subject: [PATCH 08/22] Update travis-27-locale.yaml --- ci/travis-27-locale.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/travis-27-locale.yaml b/ci/travis-27-locale.yaml index 1312c1296d46a..9acc0bfd5353d 100644 --- a/ci/travis-27-locale.yaml +++ b/ci/travis-27-locale.yaml @@ -22,6 +22,7 @@ dependencies: # universal - pytest - pytest-xdist + - enum34 - pip: - html5lib==1.0b2 - beautifulsoup4==4.2.1 From ec5900a67dfe74ebfb2697fdf4c707a00ea959ea Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 09:51:53 -0400 Subject: [PATCH 09/22] Update travis-27.yaml --- ci/travis-27.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/travis-27.yaml b/ci/travis-27.yaml index 22b993a2da886..eb16607dedf83 100644 --- a/ci/travis-27.yaml +++ b/ci/travis-27.yaml @@ -42,6 +42,7 @@ dependencies: - pytest - pytest-xdist - moto + - enum34 - pip: - backports.lzma - cpplint From 1c84176fb65335dbe09447fb9018212e1d676229 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 16:40:22 -0400 Subject: [PATCH 10/22] add whatsnew --- doc/source/whatsnew/v0.23.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 9c29c34adb7dd..ed75007a27aa2 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -88,7 +88,7 @@ Indexing - Bug in :meth:`MultiIndex.set_names` where error raised for a ``MultiIndex`` with ``nlevels == 1`` (:issue:`21149`) - Bug in :class:`IntervalIndex` constructors where creating an ``IntervalIndex`` from categorical data was not fully supported (:issue:`21243`, issue:`21253`) - Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`) -- +- Bug in :func:`pandas.core.arrays.categorical._factorize_from_iterable` inappropriately caused ``TypeError`` to be raised when an ``Enum`` was used as a factor in a ``MultiIndex`` (:issue:`21298`) I/O ^^^ From e914b2040195c8995f3312c665401866fe478f52 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 16:44:28 -0400 Subject: [PATCH 11/22] sync whatsnew with master --- doc/source/whatsnew/v0.23.1.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index ed75007a27aa2..490f5c4d77e69 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -88,6 +88,7 @@ Indexing - Bug in :meth:`MultiIndex.set_names` where error raised for a ``MultiIndex`` with ``nlevels == 1`` (:issue:`21149`) - Bug in :class:`IntervalIndex` constructors where creating an ``IntervalIndex`` from categorical data was not fully supported (:issue:`21243`, issue:`21253`) - Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`) +- Bug in :attr:`DatetimeIndex.time` where given a tz-aware Timestamp, a tz-aware Time is returned instead of tz-naive (:issue:`21267`) - Bug in :func:`pandas.core.arrays.categorical._factorize_from_iterable` inappropriately caused ``TypeError`` to be raised when an ``Enum`` was used as a factor in a ``MultiIndex`` (:issue:`21298`) I/O From 5a55feee927356b924c6126f2798faac26e941c1 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 16:45:35 -0400 Subject: [PATCH 12/22] sync whatsnew with master --- doc/source/whatsnew/v0.23.1.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 490f5c4d77e69..1a401a476074c 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -90,6 +90,7 @@ Indexing - Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`) - Bug in :attr:`DatetimeIndex.time` where given a tz-aware Timestamp, a tz-aware Time is returned instead of tz-naive (:issue:`21267`) - Bug in :func:`pandas.core.arrays.categorical._factorize_from_iterable` inappropriately caused ``TypeError`` to be raised when an ``Enum`` was used as a factor in a ``MultiIndex`` (:issue:`21298`) +- I/O ^^^ From 191fe58efbd50899c1e278b02c042d1d564cf733 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 17:20:23 -0400 Subject: [PATCH 13/22] attempting to resolve conflict --- doc/source/whatsnew/v0.23.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 1a401a476074c..9d5008da9f38d 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -79,13 +79,13 @@ Conversion - - - Indexing ^^^^^^^^ - Bug in :meth:`Series.reset_index` where appropriate error was not raised with an invalid level name (:issue:`20925`) - Bug in :func:`interval_range` when ``start``/``periods`` or ``end``/``periods`` are specified with float ``start`` or ``end`` (:issue:`21161`) - Bug in :meth:`MultiIndex.set_names` where error raised for a ``MultiIndex`` with ``nlevels == 1`` (:issue:`21149`) +- Bug in :attr:`DatetimeIndex.date` where an incorrect date is returned when the input date has a non-UTC timezone (:issue:`21230`) - Bug in :class:`IntervalIndex` constructors where creating an ``IntervalIndex`` from categorical data was not fully supported (:issue:`21243`, issue:`21253`) - Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`) - Bug in :attr:`DatetimeIndex.time` where given a tz-aware Timestamp, a tz-aware Time is returned instead of tz-naive (:issue:`21267`) From bac47e2c6ca37199ff3ac4628b24f1d414b14e3d Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Thu, 7 Jun 2018 17:27:58 -0400 Subject: [PATCH 14/22] attempting to resolve conflicts in `whatsnew` --- doc/source/whatsnew/v0.23.1.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index 9d5008da9f38d..d2a7dc633e6ec 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -79,16 +79,15 @@ Conversion - - + Indexing ^^^^^^^^ - Bug in :meth:`Series.reset_index` where appropriate error was not raised with an invalid level name (:issue:`20925`) - Bug in :func:`interval_range` when ``start``/``periods`` or ``end``/``periods`` are specified with float ``start`` or ``end`` (:issue:`21161`) - Bug in :meth:`MultiIndex.set_names` where error raised for a ``MultiIndex`` with ``nlevels == 1`` (:issue:`21149`) -- Bug in :attr:`DatetimeIndex.date` where an incorrect date is returned when the input date has a non-UTC timezone (:issue:`21230`) - Bug in :class:`IntervalIndex` constructors where creating an ``IntervalIndex`` from categorical data was not fully supported (:issue:`21243`, issue:`21253`) - Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`) -- Bug in :attr:`DatetimeIndex.time` where given a tz-aware Timestamp, a tz-aware Time is returned instead of tz-naive (:issue:`21267`) - Bug in :func:`pandas.core.arrays.categorical._factorize_from_iterable` inappropriately caused ``TypeError`` to be raised when an ``Enum`` was used as a factor in a ``MultiIndex`` (:issue:`21298`) - From f76d522392d7743e185dc3bb3c02f4d4c4920792 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Fri, 8 Jun 2018 08:35:58 -0400 Subject: [PATCH 15/22] remove whatsnew --- doc/source/whatsnew/v0.23.1.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.1.txt b/doc/source/whatsnew/v0.23.1.txt index d2a7dc633e6ec..9c29c34adb7dd 100644 --- a/doc/source/whatsnew/v0.23.1.txt +++ b/doc/source/whatsnew/v0.23.1.txt @@ -88,7 +88,6 @@ Indexing - Bug in :meth:`MultiIndex.set_names` where error raised for a ``MultiIndex`` with ``nlevels == 1`` (:issue:`21149`) - Bug in :class:`IntervalIndex` constructors where creating an ``IntervalIndex`` from categorical data was not fully supported (:issue:`21243`, issue:`21253`) - Bug in :meth:`MultiIndex.sort_index` which was not guaranteed to sort correctly with ``level=1``; this was also causing data misalignment in particular :meth:`DataFrame.stack` operations (:issue:`20994`, :issue:`20945`, :issue:`21052`) -- Bug in :func:`pandas.core.arrays.categorical._factorize_from_iterable` inappropriately caused ``TypeError`` to be raised when an ``Enum`` was used as a factor in a ``MultiIndex`` (:issue:`21298`) - I/O From 761a9d17a6e3d8f6562c503986b3087bdf07da28 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Fri, 8 Jun 2018 13:30:47 -0400 Subject: [PATCH 16/22] add to whatsnew 0.24 --- doc/source/whatsnew/v0.24.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index c69de149a0f35..e09d162b7b00b 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -132,7 +132,7 @@ Strings Indexing ^^^^^^^^ -- +- Bug in :func:`pandas.core.arrays.categorical._factorize_from_iterable` inappropriately caused ``TypeError`` to be raised when an ``Enum`` was used as a factor in a ``MultiIndex`` (:issue:`21298`) - - From 2e7921b3bab473bea1ca361d3cd22b1747eeeec9 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Fri, 8 Jun 2018 13:58:37 -0400 Subject: [PATCH 17/22] remove nested function from test This nested function had been drawn directly from _within_ `pands.util.testing.assert_index_equal`. As there is no way to construct the target dataframe's (multi) index directly (hence this PR), I simply compare this index's _0th level_ to a manually constructed (simple) index. This comparison is given by a subroutine of `assert_index_equal` (which applies the subroutine to _each_ level). --- pandas/tests/indexes/test_multi.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index ee2aac30ae748..f004cbb9c51f0 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -3314,29 +3314,21 @@ def test_use_enum_in_multiindex(self): from enum import Enum from pandas.core.algorithms import take_1d - # See https://github.com/pandas-dev/pandas/blob/ - # 0c65c57a279e755ab7093db925d1e580f9878dae/pandas/util/testing.py#L793-L799. - # We cannot simply use tm.assert_index_equal, as the "expected" index - # cannot actually be built yet. - def _get_ilevel_values(index, level): - # accept level number only - unique = index.levels[level] - labels = index.labels[level] - filled = take_1d( - unique.values, - labels, fill_value=unique._na_value - ) - values = unique._shallow_copy(filled, name=index.names[level]) - return values - MyEnum = Enum("MyEnum", "A B") df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[ MyEnum, [1, 2] ])) + + # cf. https://github.com/pandas-dev/pandas/blob/ + # 0c65c57a279e755ab7093db925d1e580f9878dae/pandas/util/testing.py#L793-L799 + unique = df.columns.levels[0] + labels = df.columns.labels[0] + filled = take_1d(unique.values, labels, fill_value=unique._na_value) + df_index_0 = unique._shallow_copy(filled, name=df.columns.names[0]) exp_index_0 = pd.Index([MyEnum.A, MyEnum.A, MyEnum.B, MyEnum.B], dtype='object') - tm.assert_index_equal(_get_ilevel_values(df.columns, 0), exp_index_0) + tm.assert_index_equal(df_index_0, exp_index_0) expected = df.copy() df = df.append({(MyEnum.A, 1): "abc", (MyEnum.B, 2): "xyz"}, From 21014c61ec6389ac84b67c6235fafb5184004d8c Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Fri, 8 Jun 2018 14:00:30 -0400 Subject: [PATCH 18/22] move imports to top --- pandas/tests/indexes/test_multi.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index f004cbb9c51f0..401afe2c211a9 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -5,7 +5,7 @@ from datetime import timedelta from itertools import product - +from enum import Enum import pytest import numpy as np @@ -20,6 +20,7 @@ from pandas.core.indexes.base import InvalidIndexError from pandas.core.dtypes.cast import construct_1d_object_array_from_listlike from pandas._libs.tslib import Timestamp +from pandas.core.algorithms import take_1d import pandas.util.testing as tm @@ -3311,9 +3312,6 @@ def test_duplicate_multiindex_labels(self): def test_use_enum_in_multiindex(self): # GH 21298 # Allow use of Enums as one of the factors in a MultiIndex. - from enum import Enum - from pandas.core.algorithms import take_1d - MyEnum = Enum("MyEnum", "A B") df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[ MyEnum, From 4cd2dff96775a828687acd7c65919ec135824cf4 Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Tue, 19 Jun 2018 13:24:05 -0400 Subject: [PATCH 19/22] jreback fixes --- ci/appveyor-27.yaml | 2 +- ci/circle-27-compat.yaml | 1 - ci/travis-27-locale.yaml | 1 - pandas/tests/indexes/test_multi.py | 15 ++++----------- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/ci/appveyor-27.yaml b/ci/appveyor-27.yaml index 74527dfa34fed..cf44bba9a3937 100644 --- a/ci/appveyor-27.yaml +++ b/ci/appveyor-27.yaml @@ -27,4 +27,4 @@ dependencies: - pytest - pytest-xdist - moto - - enum34 + diff --git a/ci/circle-27-compat.yaml b/ci/circle-27-compat.yaml index a5c86a0ed2d2a..81a48d4edf11c 100644 --- a/ci/circle-27-compat.yaml +++ b/ci/circle-27-compat.yaml @@ -22,7 +22,6 @@ dependencies: # universal - pytest - pytest-xdist - - enum34 - pip: - html5lib==1.0b2 - beautifulsoup4==4.2.1 diff --git a/ci/travis-27-locale.yaml b/ci/travis-27-locale.yaml index 9acc0bfd5353d..1312c1296d46a 100644 --- a/ci/travis-27-locale.yaml +++ b/ci/travis-27-locale.yaml @@ -22,7 +22,6 @@ dependencies: # universal - pytest - pytest-xdist - - enum34 - pip: - html5lib==1.0b2 - beautifulsoup4==4.2.1 diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index 401afe2c211a9..f23a24a28b364 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -5,7 +5,6 @@ from datetime import timedelta from itertools import product -from enum import Enum import pytest import numpy as np @@ -20,7 +19,6 @@ from pandas.core.indexes.base import InvalidIndexError from pandas.core.dtypes.cast import construct_1d_object_array_from_listlike from pandas._libs.tslib import Timestamp -from pandas.core.algorithms import take_1d import pandas.util.testing as tm @@ -3309,24 +3307,19 @@ def test_duplicate_multiindex_labels(self): ind.set_levels([['A', 'B', 'A', 'A', 'B'], [2, 1, 3, -2, 5]], inplace=True) + @td.skip_if_no('enum') def test_use_enum_in_multiindex(self): # GH 21298 # Allow use of Enums as one of the factors in a MultiIndex. + from enum import Enum MyEnum = Enum("MyEnum", "A B") df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[ MyEnum, [1, 2] ])) - # cf. https://github.com/pandas-dev/pandas/blob/ - # 0c65c57a279e755ab7093db925d1e580f9878dae/pandas/util/testing.py#L793-L799 - unique = df.columns.levels[0] - labels = df.columns.labels[0] - filled = take_1d(unique.values, labels, fill_value=unique._na_value) - df_index_0 = unique._shallow_copy(filled, name=df.columns.names[0]) - exp_index_0 = pd.Index([MyEnum.A, MyEnum.A, MyEnum.B, MyEnum.B], - dtype='object') - tm.assert_index_equal(df_index_0, exp_index_0) + exp_index_0 = pd.Index([MyEnum.A, MyEnum.B], dtype='object') + tm.assert_index_equal(df.columns.levels[0], exp_index_0) expected = df.copy() df = df.append({(MyEnum.A, 1): "abc", (MyEnum.B, 2): "xyz"}, From 702594b13acf3e89f6540fc77cbcd4364621be8f Mon Sep 17 00:00:00 2001 From: Benjamin Diamond <30356252+benediamond@users.noreply.github.com> Date: Sun, 12 Aug 2018 16:29:27 -0400 Subject: [PATCH 20/22] import pandas.util._test_decorators as td --- pandas/tests/indexes/test_multi.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/indexes/test_multi.py b/pandas/tests/indexes/test_multi.py index f23a24a28b364..ae26c4bec4da0 100644 --- a/pandas/tests/indexes/test_multi.py +++ b/pandas/tests/indexes/test_multi.py @@ -21,6 +21,7 @@ from pandas._libs.tslib import Timestamp import pandas.util.testing as tm +import pandas.util._test_decorators as td from pandas.util.testing import assert_almost_equal, assert_copy From 6e4485f1660924904eda5f65c91c7701fe59d1bf Mon Sep 17 00:00:00 2001 From: benediamond Date: Thu, 22 Nov 2018 00:10:24 -0500 Subject: [PATCH 21/22] added test --- pandas/tests/indexes/multi/test_enum.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 pandas/tests/indexes/multi/test_enum.py diff --git a/pandas/tests/indexes/multi/test_enum.py b/pandas/tests/indexes/multi/test_enum.py new file mode 100644 index 0000000000000..3fec4fa049be2 --- /dev/null +++ b/pandas/tests/indexes/multi/test_enum.py @@ -0,0 +1,25 @@ +import pandas as pd + +import pandas.util.testing as tm +import pandas.util._test_decorators as td + + +@td.skip_if_no('enum') +def test_enum_in_multiindex(self): + # GH 21298 + # Allow use of Enums as one of the factors in a MultiIndex. + from enum import Enum + MyEnum = Enum("MyEnum", "A B") + df = pd.DataFrame(columns=pd.MultiIndex.from_product(iterables=[ + MyEnum, + [1, 2] + ])) + + exp_index_0 = pd.Index([MyEnum.A, MyEnum.B], dtype='object') + tm.assert_index_equal(df.columns.levels[0], exp_index_0) + + expected = df.copy() + df = df.append({(MyEnum.A, 1): "abc", (MyEnum.B, 2): "xyz"}, + ignore_index=True) + expected.loc[0, [(MyEnum.A, 1), (MyEnum.B, 2)]] = 'abc', 'xyz' + tm.assert_frame_equal(df, expected) From 06437cdf0c4f2bc388f165dced8cd9cbcc6d02d2 Mon Sep 17 00:00:00 2001 From: benediamond Date: Thu, 22 Nov 2018 10:46:30 -0500 Subject: [PATCH 22/22] typo: remove 'self' --- pandas/tests/indexes/multi/test_enum.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/indexes/multi/test_enum.py b/pandas/tests/indexes/multi/test_enum.py index 3fec4fa049be2..a13dd465ca813 100644 --- a/pandas/tests/indexes/multi/test_enum.py +++ b/pandas/tests/indexes/multi/test_enum.py @@ -5,7 +5,7 @@ @td.skip_if_no('enum') -def test_enum_in_multiindex(self): +def test_enum_in_multiindex(): # GH 21298 # Allow use of Enums as one of the factors in a MultiIndex. from enum import Enum