Skip to content

Commit 3ecfba1

Browse files
committed
Merge branch 'master' of git://github.com/pandas-dev/pandas into clip
2 parents 9eb5c5c + 8a98f5e commit 3ecfba1

File tree

6 files changed

+48
-31
lines changed

6 files changed

+48
-31
lines changed

doc/source/whatsnew/v0.20.3.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ Conversion
5050
Indexing
5151
^^^^^^^^
5252

53-
- Bug in ``Float64Index`` causing an empty array instead of None to be returned from ``.get(np.nan)`` on a Series whose index did not contain any NaNs (:issue:`8569`)
53+
- Bug in ``Float64Index`` causing an empty array instead of ``None`` to be returned from ``.get(np.nan)`` on a Series whose index did not contain any ``NaN`` s (:issue:`8569`)
5454

5555
I/O
5656
^^^
5757

58-
-- Bug in ``pd.read_csv()`` in which files weren't opened as binary files by the C engine on Windows, causing EOF characters mid-field, which would fail (:issue:`16039`, :issue:`16559`, :issue`16675`)
59-
-- Bug in ``pd.read_hdf()`` in which reading a ``Series`` saved to an HDF file in 'fixed' format fails when an explicit ``mode='r'`` argument is supplied (:issue:`16583`)
58+
- Bug in :func:`read_csv`` in which files weren't opened as binary files by the C engine on Windows, causing EOF characters mid-field, which would fail (:issue:`16039`, :issue:`16559`, :issue:`16675`)
59+
- Bug in :func:`read_hdf`` in which reading a ``Series`` saved to an HDF file in 'fixed' format fails when an explicit ``mode='r'`` argument is supplied (:issue:`16583`)
6060

6161
Plotting
6262
^^^^^^^^

doc/source/whatsnew/v0.21.0.txt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ New features
2222

2323
- Support for `PEP 519 -- Adding a file system path protocol
2424
<https://www.python.org/dev/peps/pep-0519/>`_ on most readers and writers (:issue:`13823`)
25-
- Added `__fspath__` method to :class`:pandas.HDFStore`, :class:`pandas.ExcelFile`,
26-
and :class:`pandas.ExcelWriter` to work properly with the file system path protocol (:issue:`13823`)
25+
- Added ``__fspath__`` method to :class:`~pandas.HDFStore`, :class:`~pandas.ExcelFile`,
26+
and :class:`~pandas.ExcelWriter` to work properly with the file system path protocol (:issue:`13823`)
2727

2828
.. _whatsnew_0210.enhancements.other:
2929

@@ -33,12 +33,12 @@ Other Enhancements
3333
- The ``validate`` argument for :func:`merge` function now checks whether a merge is one-to-one, one-to-many, many-to-one, or many-to-many. If a merge is found to not be an example of specified merge type, an exception of type ``MergeError`` will be raised. For more, see :ref:`here <merging.validation>` (:issue:`16270`)
3434
- ``Series.to_dict()`` and ``DataFrame.to_dict()`` now support an ``into`` keyword which allows you to specify the ``collections.Mapping`` subclass that you would like returned. The default is ``dict``, which is backwards compatible. (:issue:`16122`)
3535
- ``RangeIndex.append`` now returns a ``RangeIndex`` object when possible (:issue:`16212`)
36-
- ``Series.rename_axis()`` and ``DataFrame.rename_axis()`` with ``inplace=True`` now return None while renaming the axis inplace. (:issue:`15704`)
37-
- :func:`to_pickle` has gained a protocol parameter (:issue:`16252`). By default, this parameter is set to `HIGHEST_PROTOCOL <https://docs.python.org/3/library/pickle.html#data-stream-format>`__
38-
- :func:`api.types.infer_dtype` now infers decimals. (:issue: `15690`)
36+
- ``Series.rename_axis()`` and ``DataFrame.rename_axis()`` with ``inplace=True`` now return ``None`` while renaming the axis inplace. (:issue:`15704`)
37+
- :func:`to_pickle` has gained a ``protocol`` parameter (:issue:`16252`). By default, this parameter is set to `HIGHEST_PROTOCOL <https://docs.python.org/3/library/pickle.html#data-stream-format>`__
38+
- :func:`api.types.infer_dtype` now infers decimals. (:issue:`15690`)
3939
- :func:`read_feather` has gained the ``nthreads`` parameter for multi-threaded operations (:issue:`16359`)
40-
- :func:`DataFrame.clip()` and :func: `Series.cip()` have gained an inplace argument. (:issue: `15388`)
41-
- :func:`crosstab` has gained a ``margins_name`` parameter to define the name of the row / column that will contain the totals when margins=True. (:issue:`15972`)
40+
- :func:`DataFrame.clip()` and :func: `Series.clip()` have gained an inplace argument. (:issue:`15388`)
41+
- :func:`crosstab` has gained a ``margins_name`` parameter to define the name of the row / column that will contain the totals when ``margins=True``. (:issue:`15972`)
4242

4343
.. _whatsnew_0210.api_breaking:
4444

@@ -98,13 +98,14 @@ Conversion
9898
Indexing
9999
^^^^^^^^
100100

101-
- When called with a null slice (e.g. ``df.iloc[:]``), the``iloc`` and ``loc`` indexers return a shallow copy of the original object. Previously they returned the original object. (:issue:`13873`).
101+
- When called with a null slice (e.g. ``df.iloc[:]``), the ``.iloc`` and ``.loc`` indexers return a shallow copy of the original object. Previously they returned the original object. (:issue:`13873`).
102+
- When called on an unsorted ``MultiIndex``, the ``loc`` indexer now will raise ``UnsortedIndexError`` only if proper slicing is used on non-sorted levels (:issue:`16734`).
102103

103104

104105
I/O
105106
^^^
106107

107-
- Bug in ``pd.read_csv()`` in which non integer values for the header argument generated an unhelpful / unrelated error message (:issue:`16338`)
108+
- Bug in :func:`read_csv` in which non integer values for the header argument generated an unhelpful / unrelated error message (:issue:`16338`)
108109

109110

110111
Plotting
@@ -114,7 +115,7 @@ Plotting
114115

115116
Groupby/Resample/Rolling
116117
^^^^^^^^^^^^^^^^^^^^^^^^
117-
- Bug in ``DataFrame.resample().size()`` where an empty DataFrame did not return a Series (:issue:`14962`)
118+
- Bug in ``DataFrame.resample().size()`` where an empty ``DataFrame`` did not return a ``Series`` (:issue:`14962`)
118119

119120

120121

pandas/core/common.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,13 @@ def is_null_slice(obj):
411411
obj.stop is None and obj.step is None)
412412

413413

414+
def is_true_slices(l):
415+
"""
416+
Find non-trivial slices in "l": return a list of booleans with same length.
417+
"""
418+
return [isinstance(k, slice) and not is_null_slice(k) for k in l]
419+
420+
414421
def is_full_slice(obj, l):
415422
""" we have a full length slice """
416423
return (isinstance(obj, slice) and obj.start == 0 and obj.stop == l and

pandas/core/indexes/multi.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
from pandas.errors import PerformanceWarning, UnsortedIndexError
2424
from pandas.core.common import (_values_from_object,
2525
is_bool_indexer,
26-
is_null_slice)
26+
is_null_slice,
27+
is_true_slices)
2728

2829
import pandas.core.base as base
2930
from pandas.util._decorators import (Appender, cache_readonly,
@@ -1035,12 +1036,6 @@ def is_lexsorted(self):
10351036
"""
10361037
return self.lexsort_depth == self.nlevels
10371038

1038-
def is_lexsorted_for_tuple(self, tup):
1039-
"""
1040-
Return True if we are correctly lexsorted given the passed tuple
1041-
"""
1042-
return len(tup) <= self.lexsort_depth
1043-
10441039
@cache_readonly
10451040
def lexsort_depth(self):
10461041
if self.sortorder is not None:
@@ -2262,12 +2257,12 @@ def get_locs(self, tup):
22622257
"""
22632258

22642259
# must be lexsorted to at least as many levels
2265-
if not self.is_lexsorted_for_tuple(tup):
2266-
raise UnsortedIndexError('MultiIndex Slicing requires the index '
2267-
'to be fully lexsorted tuple len ({0}), '
2268-
'lexsort depth ({1})'
2269-
.format(len(tup), self.lexsort_depth))
2270-
2260+
true_slices = [i for (i, s) in enumerate(is_true_slices(tup)) if s]
2261+
if true_slices and true_slices[-1] >= self.lexsort_depth:
2262+
raise UnsortedIndexError('MultiIndex slicing requires the index '
2263+
'to be lexsorted: slicing on levels {0}, '
2264+
'lexsort depth {1}'
2265+
.format(true_slices, self.lexsort_depth))
22712266
# indexer
22722267
# this is the list of all values that we want to select
22732268
n = len(self)

pandas/tests/indexes/test_multi.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2826,8 +2826,13 @@ def test_unsortedindex(self):
28262826
df = pd.DataFrame([[i, 10 * i] for i in lrange(6)], index=mi,
28272827
columns=['one', 'two'])
28282828

2829+
# GH 16734: not sorted, but no real slicing
2830+
result = df.loc(axis=0)['z', 'a']
2831+
expected = df.iloc[0]
2832+
tm.assert_series_equal(result, expected)
2833+
28292834
with pytest.raises(UnsortedIndexError):
2830-
df.loc(axis=0)['z', :]
2835+
df.loc(axis=0)['z', slice('a')]
28312836
df.sort_index(inplace=True)
28322837
assert len(df.loc(axis=0)['z', :]) == 2
28332838

pandas/tests/indexing/test_multiindex.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -817,9 +817,13 @@ def f():
817817
assert df.index.lexsort_depth == 0
818818
with tm.assert_raises_regex(
819819
UnsortedIndexError,
820-
'MultiIndex Slicing requires the index to be fully '
821-
r'lexsorted tuple len \(2\), lexsort depth \(0\)'):
822-
df.loc[(slice(None), df.loc[:, ('a', 'bar')] > 5), :]
820+
'MultiIndex slicing requires the index to be '
821+
r'lexsorted: slicing on levels \[1\], lexsort depth 0'):
822+
df.loc[(slice(None), slice('bar')), :]
823+
824+
# GH 16734: not sorted, but no real slicing
825+
result = df.loc[(slice(None), df.loc[:, ('a', 'bar')] > 5), :]
826+
tm.assert_frame_equal(result, df.iloc[[1, 3], :])
823827

824828
def test_multiindex_slicers_non_unique(self):
825829

@@ -1001,9 +1005,14 @@ def test_per_axis_per_level_doc_examples(self):
10011005

10021006
# not sorted
10031007
def f():
1004-
df.loc['A1', (slice(None), 'foo')]
1008+
df.loc['A1', ('a', slice('foo'))]
10051009

10061010
pytest.raises(UnsortedIndexError, f)
1011+
1012+
# GH 16734: not sorted, but no real slicing
1013+
tm.assert_frame_equal(df.loc['A1', (slice(None), 'foo')],
1014+
df.loc['A1'].iloc[:, [0, 2]])
1015+
10071016
df = df.sort_index(axis=1)
10081017

10091018
# slicing

0 commit comments

Comments
 (0)