Skip to content

Commit 0cfd41c

Browse files
committed
BUG: Fix range dtype in constructor on windows
1 parent a0a0f5a commit 0cfd41c

File tree

11 files changed

+84
-27
lines changed

11 files changed

+84
-27
lines changed

doc/source/whatsnew/v0.21.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ Conversion
918918
- Bug in ``Timedelta`` construction and arithmetic that would not propagate the ``Overflow`` exception (:issue:`17367`)
919919
- Bug in :meth:`~DataFrame.astype` converting to object dtype when passed extension type classes (`DatetimeTZDtype``, ``CategoricalDtype``) rather than instances. Now a ``TypeError`` is raised when a class is passed (:issue:`17780`).
920920
- Bug in :meth:`to_numeric` in which elements were not always being coerced to numeric when ``errors='coerce'`` (:issue:`17007`, :issue:`17125`)
921+
- Bug in ``DataFrame`` and ``Series`` constructors where ``range`` objects are converted ``int32`` dtype on Windows instead of ``int64`` (:issue:`16804`)
921922

922923
Indexing
923924
^^^^^^^^

pandas/core/common.py

+24
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,30 @@ class Sentinel(object):
552552
return Sentinel()
553553

554554

555+
def _get_range_parameters(data):
556+
"""Gets the start, stop, and step parameters from a range object"""
557+
if compat.PY3:
558+
step = data.step
559+
stop = data.stop
560+
start = data.start
561+
else:
562+
# seems we only have indexing ops to infer
563+
# rather than direct accessors
564+
if len(data) > 1:
565+
step = data[1] - data[0]
566+
stop = data[-1] + step
567+
start = data[0]
568+
elif len(data):
569+
start = data[0]
570+
stop = data[0] + 1
571+
step = 1
572+
else:
573+
start = stop = 0
574+
step = 1
575+
576+
return start, stop, step
577+
578+
555579
# ----------------------------------------------------------------------
556580
# Detect our environment
557581

pandas/core/indexes/range.py

+2-19
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pandas import compat
1313
from pandas.compat import lrange, range
1414
from pandas.compat.numpy import function as nv
15-
from pandas.core.common import _all_none
15+
from pandas.core.common import _all_none, _get_range_parameters
1616
from pandas.core.indexes.base import Index, _index_shared_docs
1717
from pandas.util._decorators import Appender, cache_readonly
1818
import pandas.core.dtypes.concat as _concat
@@ -113,24 +113,7 @@ def from_range(cls, data, name=None, dtype=None, **kwargs):
113113
'{0}(...) must be called with object coercible to a '
114114
'range, {1} was passed'.format(cls.__name__, repr(data)))
115115

116-
if compat.PY3:
117-
step = data.step
118-
stop = data.stop
119-
start = data.start
120-
else:
121-
# seems we only have indexing ops to infer
122-
# rather than direct accessors
123-
if len(data) > 1:
124-
step = data[1] - data[0]
125-
stop = data[-1] + step
126-
start = data[0]
127-
elif len(data):
128-
start = data[0]
129-
stop = data[0] + 1
130-
step = 1
131-
else:
132-
start = stop = 0
133-
step = 1
116+
start, stop, step = _get_range_parameters(data)
134117
return RangeIndex(start, stop, step, dtype=dtype, name=name, **kwargs)
135118

136119
@classmethod

pandas/core/series.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
_maybe_box_datetimelike,
4747
_dict_compat,
4848
standardize_mapping,
49-
_any_none)
49+
_any_none,
50+
_get_range_parameters)
5051
from pandas.core.index import (Index, MultiIndex, InvalidIndexError,
5152
Float64Index, _ensure_index)
5253
from pandas.core.indexing import check_bool_indexer, maybe_convert_indices
@@ -3177,6 +3178,15 @@ def _try_cast(arr, take_fast_path):
31773178

31783179
subarr = maybe_cast_to_datetime(subarr, dtype)
31793180

3181+
elif isinstance(data, range):
3182+
# GH 16804
3183+
start, stop, step = _get_range_parameters(data)
3184+
if is_extension_type(dtype):
3185+
arr = np.arange(start, stop, step, dtype='int64')
3186+
subarr = _try_cast(arr, False)
3187+
else:
3188+
subarr = np.arange(start, stop, step, dtype=dtype or 'int64')
3189+
31803190
else:
31813191
subarr = _try_cast(data, False)
31823192

pandas/tests/frame/test_constructors.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ def test_constructor_list_of_lists(self):
829829

830830
# GH 4851
831831
# list of 0-dim ndarrays
832-
expected = DataFrame({0: range(10)})
832+
expected = DataFrame({0: np.arange(10)})
833833
data = [np.array(x) for x in range(10)]
834834
result = DataFrame(data)
835835
tm.assert_frame_equal(result, expected)
@@ -1927,6 +1927,17 @@ def test_to_frame_with_falsey_names(self):
19271927
result = DataFrame(Series(name=0)).dtypes
19281928
tm.assert_series_equal(result, expected)
19291929

1930+
def test_constructor_range_dtype(self):
1931+
# GH 16804
1932+
expected = DataFrame({'A': [0, 1, 2, 3, 4]}, dtype='int64')
1933+
result = DataFrame({'A': range(5)})
1934+
tm.assert_frame_equal(result, expected)
1935+
1936+
# override default dtype
1937+
expected = DataFrame({'A': [0, 1, 2, 3, 4]}, dtype='uint8')
1938+
result = DataFrame({'A': range(5)}, dtype='uint8')
1939+
tm.assert_frame_equal(result, expected)
1940+
19301941

19311942
class TestDataFrameConstructorWithDatetimeTZ(TestData):
19321943

pandas/tests/indexing/test_partial.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ def f():
532532

533533
def f():
534534
df = DataFrame()
535-
df['foo'] = Series(range(len(df)))
535+
df['foo'] = Series(np.arange(len(df)), dtype='float64')
536536
return df
537537

538538
tm.assert_frame_equal(f(), expected)

pandas/tests/series/test_alter_axes.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ def test_reorder_levels(self):
219219
labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
220220
[0, 0, 0, 0, 0, 0]],
221221
names=['L0', 'L0', 'L0'])
222-
expected = Series(range(6), index=e_idx)
222+
expected = Series(np.arange(6), index=e_idx)
223223
assert_series_equal(result, expected)
224224

225225
result = s.reorder_levels(['L0', 'L0', 'L0'])

pandas/tests/series/test_constructors.py

+11
Original file line numberDiff line numberDiff line change
@@ -846,3 +846,14 @@ def test_constructor_generic_timestamp_deprecated(self):
846846
msg = "cannot convert datetimelike"
847847
with tm.assert_raises_regex(TypeError, msg):
848848
Series([], dtype='M8[ps]')
849+
850+
def test_constructor_range_dtype(self):
851+
# GH 16804
852+
expected = Series([0, 1, 2, 3, 4], dtype='int64')
853+
result = Series(range(5))
854+
tm.assert_series_equal(result, expected)
855+
856+
# override default dtype
857+
expected = Series([0, 1, 2, 3, 4], dtype='uint8')
858+
result = Series(range(5), dtype='uint8')
859+
tm.assert_series_equal(result, expected)

pandas/tests/test_common.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import numpy as np
88

99
from pandas import Series, Timestamp
10-
from pandas.compat import range, lmap
10+
from pandas.compat import range, lmap, PY2
1111
import pandas.core.common as com
1212
import pandas.util.testing as tm
1313

@@ -221,3 +221,20 @@ def test_standardize_mapping():
221221

222222
dd = collections.defaultdict(list)
223223
assert isinstance(com.standardize_mapping(dd), partial)
224+
225+
226+
@pytest.mark.parametrize(
227+
'start,stop,step', [(0, 10, 2), (11, -2, -1), (0, -5, 1), (2, 4, 8)])
228+
def test_get_range_parameters(start, stop, step):
229+
rng = range(start, stop, step)
230+
if PY2 and len(rng) == 0:
231+
start_expected, stop_expected, step_expected = 0, 0, 1
232+
elif PY2 and len(rng) == 1:
233+
start_expected, stop_expected, step_expected = start, start + 1, 1
234+
else:
235+
start_expected, stop_expected, step_expected = start, stop, step
236+
237+
start_result, stop_result, step_result = com._get_range_parameters(rng)
238+
assert start_result == start_expected
239+
assert stop_result == stop_expected
240+
assert step_result == step_expected

pandas/tests/test_resample.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3030,7 +3030,7 @@ def test_nearest(self):
30303030
# GH 17496
30313031
# Resample nearest
30323032
index = pd.date_range('1/1/2000', periods=3, freq='T')
3033-
result = pd.Series(range(3), index=index).resample('20s').nearest()
3033+
result = pd.Series(np.arange(3), index=index).resample('20s').nearest()
30343034

30353035
expected = pd.Series(
30363036
np.array([0, 0, 1, 1, 1, 2, 2]),

pandas/tests/test_window.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -698,8 +698,8 @@ def get_expects(self):
698698
return expects
699699

700700
def _create_dtype_data(self, dtype):
701-
sr1 = Series(range(5), dtype=dtype)
702-
sr2 = Series(range(10, 0, -2), dtype=dtype)
701+
sr1 = Series(np.arange(5), dtype=dtype)
702+
sr2 = Series(np.arange(10, 0, -2), dtype=dtype)
703703
df = DataFrame(np.arange(10).reshape((5, 2)), dtype=dtype)
704704

705705
data = {

0 commit comments

Comments
 (0)