Repository: pandas-dev/pandas
Pull request: Fix slicer assignment bug
- [x] closes #26939 
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
BUG: cannot set Series with reverse slicer
Minimal example:
```
>>> import pandas as pd
>>> s = pd.Series(index=range(2010, 2020))
>>> s.loc[2015:2010:-1] = [6, 5, 4, 3, 2, 1]
Traceback (most recent call last):
[...]
ValueError: cannot set using a slice indexer with a different length than the value
```

I see no reason why this shouldn't work, as setting with the forward slicer works without problems, and *getting* with the reverse slicer also works without issue:
```
>>> # turn list around because slicer is (not) reversed compared to above
>>> s.loc[2010:2015] = [6, 5, 4, 3, 2, 1][::-1]
>>> s
2010    1.0
2011    2.0
2012    3.0
2013    4.0
2014    5.0
2015    6.0
2016    NaN
2017    NaN
2018    NaN
2019    NaN
dtype: float64
>>> s.loc[2015:2010:-1] == [6, 5, 4, 3, 2, 1]  # comparison, not assignment
2015    True
2014    True
2013    True
2012    True
2011    True
2010    True
dtype: bool
```

PS: For the failure, it does not matter if the RHS is a np.array, etc.

Hints from issue discussion:
can I try it?
Sure, thanks.

On Thu, Aug 15, 2019 at 10:17 PM kmin-jeong <notifications@github.com>
wrote:

> can I try it?
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/pandas-dev/pandas/issues/26939?email_source=notifications&email_token=AAKAOIVUYC6UPJGLYUEX65LQEYL3LA5CNFSM4HZIJBZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4NRRUA#issuecomment-521869520>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAKAOIS7VDSD6W53V2S2X43QEYL3LANCNFSM4HZIJBZA>
> .
>

Commit message: BUG: fixes GH26939

Patch to review:
diff --git a/pandas/core/indexers.py b/pandas/core/indexers.py
index 70c48e969172f..6502d566e88c0 100644
--- a/pandas/core/indexers.py
+++ b/pandas/core/indexers.py
@@ -226,6 +226,9 @@ def length_of_indexer(indexer, target=None) -> int:
         if step is None:
             step = 1
         elif step < 0:
+            t = stop
+            stop = start + 1
+            start = t + 1
             step = -step
         return (stop - start + step - 1) // step
     elif isinstance(indexer, (ABCSeries, ABCIndexClass, np.ndarray, list)):
diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py
index abe0cd86c90d7..383771b87ca75 100644
--- a/pandas/tests/indexing/test_loc.py
+++ b/pandas/tests/indexing/test_loc.py
@@ -1070,6 +1070,16 @@ def test_series_indexing_zerodim_np_array(self):
         result = s.loc[np.array(0)]
         assert result == 1
 
+    def test_loc_reverse_assignment(self):
+        # GH26939
+        data = [1, 2, 3, 4, 5, 6] + [None] * 4
+        expected = Series(index=range(2010, 2020), data=data)
+
+        result = pd.Series(index=range(2010, 2020))
+        result.loc[2015:2010:-1] = [6, 5, 4, 3, 2, 1]
+
+        tm.assert_series_equal(result, expected)
+
 
 def test_series_loc_getitem_label_list_missing_values():
     # gh-11428


Code review comments:
diff_hunk: @@ -226,6 +226,9 @@ def length_of_indexer(indexer, target=None) -> int:
         if step is None:
             step = 1
         elif step < 0:
+            t = stop
+            stop = start + 1
+            start = t + 1
path: pandas/core/indexers.py
text: @user1:
can you eliminate the temporary variable with `start, stop = stop+1, start+1`