Skip to content

Commit 39a46ff

Browse files
committed
COMPAT: 3.6.1 compat for change in PySlice_GetIndices_Ex
This doesn't actually matter to any tests except for some internal consistency ones. Bonus is that it eliminates a warning :< note that we aren't actually testing this (yet) on Travis as our 3.6 build uses conda-forge and 3.6.1 is not there as of yet. Its in defaults though (and shows up on appveyor build). Author: Jeff Reback <[email protected]> Closes pandas-dev#15790 from jreback/py361 and squashes the following commits: 42ddddc [Jeff Reback] change to version < 3 d36902c [Jeff Reback] COMPAT: 3.6.1 compat for change in PySlice_GetIndices_Ex
1 parent 56ccad8 commit 39a46ff

File tree

4 files changed

+73
-22
lines changed

4 files changed

+73
-22
lines changed

pandas/_libs/lib.pyx

+10-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ cimport numpy as np
33
cimport cython
44
import numpy as np
55
import sys
6+
67
cdef bint PY3 = (sys.version_info[0] >= 3)
78

89
from numpy cimport *
@@ -26,7 +27,8 @@ from cpython cimport (PyDict_New, PyDict_GetItem, PyDict_SetItem,
2627
PyObject_SetAttrString,
2728
PyObject_RichCompareBool,
2829
PyBytes_GET_SIZE,
29-
PyUnicode_GET_SIZE)
30+
PyUnicode_GET_SIZE,
31+
PyObject)
3032

3133
try:
3234
from cpython cimport PyString_GET_SIZE
@@ -36,11 +38,10 @@ except ImportError:
3638
cdef extern from "Python.h":
3739
Py_ssize_t PY_SSIZE_T_MAX
3840

39-
ctypedef struct PySliceObject:
40-
pass
41+
cdef extern from "compat_helper.h":
4142

42-
cdef int PySlice_GetIndicesEx(
43-
PySliceObject* s, Py_ssize_t length,
43+
cdef int slice_get_indices(
44+
PyObject* s, Py_ssize_t length,
4445
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step,
4546
Py_ssize_t *slicelength) except -1
4647

@@ -1658,8 +1659,8 @@ cpdef slice_get_indices_ex(slice slc, Py_ssize_t objlen=PY_SSIZE_T_MAX):
16581659
if slc is None:
16591660
raise TypeError("slc should be a slice")
16601661

1661-
PySlice_GetIndicesEx(<PySliceObject *>slc, objlen,
1662-
&start, &stop, &step, &length)
1662+
slice_get_indices(<PyObject *>slc, objlen,
1663+
&start, &stop, &step, &length)
16631664

16641665
return start, stop, step, length
16651666

@@ -1683,8 +1684,8 @@ cpdef Py_ssize_t slice_len(
16831684
if slc is None:
16841685
raise TypeError("slc must be slice")
16851686

1686-
PySlice_GetIndicesEx(<PySliceObject *>slc, objlen,
1687-
&start, &stop, &step, &length)
1687+
slice_get_indices(<PyObject *>slc, objlen,
1688+
&start, &stop, &step, &length)
16881689

16891690
return length
16901691

pandas/_libs/src/compat_helper.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright (c) 2016, PyData Development Team
3+
All rights reserved.
4+
5+
Distributed under the terms of the BSD Simplified License.
6+
7+
The full license is in the LICENSE file, distributed with this software.
8+
*/
9+
10+
#ifndef PANDAS__LIBS_SRC_COMPAT_HELPER_H_
11+
#define PANDAS__LIBS_SRC_COMPAT_HELPER_H_
12+
13+
#include "Python.h"
14+
#include "numpy_helper.h"
15+
16+
/*
17+
PySlice_GetIndicesEx changes signature in PY3
18+
but 3.6.1 in particular changes the behavior of this function slightly
19+
https://bugs.python.org/issue27867
20+
*/
21+
22+
PANDAS_INLINE int slice_get_indices(PyObject *s,
23+
Py_ssize_t length,
24+
Py_ssize_t *start,
25+
Py_ssize_t *stop,
26+
Py_ssize_t *step,
27+
Py_ssize_t *slicelength) {
28+
#if PY_VERSION_HEX >= 0x03000000
29+
return PySlice_GetIndicesEx(s, length, start, stop,
30+
step, slicelength);
31+
#else
32+
return PySlice_GetIndicesEx((PySliceObject *)s, length, start,
33+
stop, step, slicelength);
34+
#endif
35+
}
36+
37+
#endif // PANDAS__LIBS_SRC_COMPAT_HELPER_H_

pandas/tests/test_internals.py

+24-12
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
# pylint: disable=W0102
33

44
from datetime import datetime, date
5-
5+
import sys
66
import pytest
77
import numpy as np
88

99
import re
10+
from distutils.version import LooseVersion
1011
import itertools
1112
from pandas import (Index, MultiIndex, DataFrame, DatetimeIndex,
1213
Series, Categorical)
@@ -22,6 +23,9 @@
2223
randn, assert_series_equal)
2324
from pandas.compat import zip, u
2425

26+
# in 3.6.1 a c-api slicing function changed, see src/compat_helper.h
27+
PY361 = sys.version >= LooseVersion('3.6.1')
28+
2529

2630
@pytest.fixture
2731
def mgr():
@@ -1128,8 +1132,10 @@ def assert_as_slice_equals(arr, slc):
11281132
assert_as_slice_equals([0, 100], slice(0, 200, 100))
11291133

11301134
assert_as_slice_equals([2, 1], slice(2, 0, -1))
1131-
assert_as_slice_equals([2, 1, 0], slice(2, None, -1))
1132-
assert_as_slice_equals([100, 0], slice(100, None, -100))
1135+
1136+
if not PY361:
1137+
assert_as_slice_equals([2, 1, 0], slice(2, None, -1))
1138+
assert_as_slice_equals([100, 0], slice(100, None, -100))
11331139

11341140
def test_not_slice_like_arrays(self):
11351141
def assert_not_slice_like(arr):
@@ -1150,8 +1156,9 @@ def test_slice_iter(self):
11501156
assert list(BlockPlacement(slice(0, 0))) == []
11511157
assert list(BlockPlacement(slice(3, 0))) == []
11521158

1153-
assert list(BlockPlacement(slice(3, 0, -1))) == [3, 2, 1]
1154-
assert list(BlockPlacement(slice(3, None, -1))) == [3, 2, 1, 0]
1159+
if not PY361:
1160+
assert list(BlockPlacement(slice(3, 0, -1))) == [3, 2, 1]
1161+
assert list(BlockPlacement(slice(3, None, -1))) == [3, 2, 1, 0]
11551162

11561163
def test_slice_to_array_conversion(self):
11571164
def assert_as_array_equals(slc, asarray):
@@ -1164,8 +1171,10 @@ def assert_as_array_equals(slc, asarray):
11641171
assert_as_array_equals(slice(3, 0), [])
11651172

11661173
assert_as_array_equals(slice(3, 0, -1), [3, 2, 1])
1167-
assert_as_array_equals(slice(3, None, -1), [3, 2, 1, 0])
1168-
assert_as_array_equals(slice(31, None, -10), [31, 21, 11, 1])
1174+
1175+
if not PY361:
1176+
assert_as_array_equals(slice(3, None, -1), [3, 2, 1, 0])
1177+
assert_as_array_equals(slice(31, None, -10), [31, 21, 11, 1])
11691178

11701179
def test_blockplacement_add(self):
11711180
bpl = BlockPlacement(slice(0, 5))
@@ -1180,23 +1189,26 @@ def assert_add_equals(val, inc, result):
11801189
assert_add_equals(slice(0, 0), 0, [])
11811190
assert_add_equals(slice(1, 4), 0, [1, 2, 3])
11821191
assert_add_equals(slice(3, 0, -1), 0, [3, 2, 1])
1183-
assert_add_equals(slice(2, None, -1), 0, [2, 1, 0])
11841192
assert_add_equals([1, 2, 4], 0, [1, 2, 4])
11851193

11861194
assert_add_equals(slice(0, 0), 10, [])
11871195
assert_add_equals(slice(1, 4), 10, [11, 12, 13])
11881196
assert_add_equals(slice(3, 0, -1), 10, [13, 12, 11])
1189-
assert_add_equals(slice(2, None, -1), 10, [12, 11, 10])
11901197
assert_add_equals([1, 2, 4], 10, [11, 12, 14])
11911198

11921199
assert_add_equals(slice(0, 0), -1, [])
11931200
assert_add_equals(slice(1, 4), -1, [0, 1, 2])
1194-
assert_add_equals(slice(3, 0, -1), -1, [2, 1, 0])
11951201
assert_add_equals([1, 2, 4], -1, [0, 1, 3])
11961202

11971203
with pytest.raises(ValueError):
11981204
BlockPlacement(slice(1, 4)).add(-10)
11991205
with pytest.raises(ValueError):
12001206
BlockPlacement([1, 2, 4]).add(-10)
1201-
with pytest.raises(ValueError):
1202-
BlockPlacement(slice(2, None, -1)).add(-1)
1207+
1208+
if not PY361:
1209+
assert_add_equals(slice(3, 0, -1), -1, [2, 1, 0])
1210+
assert_add_equals(slice(2, None, -1), 0, [2, 1, 0])
1211+
assert_add_equals(slice(2, None, -1), 10, [12, 11, 10])
1212+
1213+
with pytest.raises(ValueError):
1214+
BlockPlacement(slice(2, None, -1)).add(-1)

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@ def pxd(name):
460460
extra_compile_args=['-Wno-unused-function']
461461

462462
lib_depends = lib_depends + ['pandas/_libs/src/numpy_helper.h',
463-
'pandas/_libs/src/parse_helper.h']
463+
'pandas/_libs/src/parse_helper.h',
464+
'pandas/_libs/src/compat_helper.h']
464465

465466

466467
tseries_depends = ['pandas/_libs/src/datetime/np_datetime.h',

0 commit comments

Comments
 (0)