Skip to content

Commit 3722487

Browse files
committed
Merge pull request pandas-dev#5101 from cpcloud/fix-period-datetime-join-stack-overflow
BUG: fix PeriodIndex join with DatetimeIndex stack overflow
2 parents 772ff01 + cc4b130 commit 3722487

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

doc/source/release.rst

+2
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,8 @@ Bug Fixes
553553
passed ``index_col=0`` (:issue:`5066`).
554554
- Fixed a bug where :func:`~pandas.read_html` was incorrectly infering the
555555
type of headers (:issue:`5048`).
556+
- Fixed a bug where ``DatetimeIndex`` joins with ``PeriodIndex`` caused a
557+
stack overflow (:issue:`3899`).
556558

557559

558560
pandas 0.12.0

pandas/tseries/period.py

+5-8
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
import pandas.tseries.frequencies as _freq_mod
1313

1414
import pandas.core.common as com
15-
from pandas.core.common import (isnull, _NS_DTYPE, _INT64_DTYPE,
16-
_maybe_box, _values_from_object)
15+
from pandas.core.common import (isnull, _INT64_DTYPE, _maybe_box,
16+
_values_from_object)
1717
from pandas import compat
1818
from pandas.lib import Timestamp
1919
import pandas.lib as lib
@@ -712,13 +712,10 @@ def _array_values(self):
712712
def astype(self, dtype):
713713
dtype = np.dtype(dtype)
714714
if dtype == np.object_:
715-
result = np.empty(len(self), dtype=dtype)
716-
result[:] = [x for x in self]
717-
return result
715+
return Index(np.array(list(self), dtype), dtype)
718716
elif dtype == _INT64_DTYPE:
719-
return self.values.copy()
720-
else: # pragma: no cover
721-
raise ValueError('Cannot cast PeriodIndex to dtype %s' % dtype)
717+
return Index(self.values, dtype)
718+
raise ValueError('Cannot cast PeriodIndex to dtype %s' % dtype)
722719

723720
def __iter__(self):
724721
for val in self.values:

pandas/tseries/tests/test_period.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
import pandas.core.datetools as datetools
2323
import pandas as pd
2424
import numpy as np
25-
from pandas.compat import range, lrange, lmap, map, zip
26-
randn = np.random.randn
25+
from numpy.random import randn
26+
from pandas.compat import range, lrange, lmap, zip
2727

2828
from pandas import Series, TimeSeries, DataFrame
2929
from pandas.util.testing import(assert_series_equal, assert_almost_equal,
@@ -1207,7 +1207,6 @@ def test_is_(self):
12071207
self.assertFalse(index.is_(index - 2))
12081208
self.assertFalse(index.is_(index - 0))
12091209

1210-
12111210
def test_comp_period(self):
12121211
idx = period_range('2007-01', periods=20, freq='M')
12131212

@@ -1913,6 +1912,17 @@ def test_join_self(self):
19131912
res = index.join(index, how=kind)
19141913
self.assert_(index is res)
19151914

1915+
def test_join_does_not_recur(self):
1916+
df = tm.makeCustomDataframe(3, 2, data_gen_f=lambda *args:
1917+
np.random.randint(2), c_idx_type='p',
1918+
r_idx_type='dt')
1919+
s = df.iloc[:2, 0]
1920+
1921+
res = s.index.join(df.columns, how='outer')
1922+
expected = Index([s.index[0], s.index[1],
1923+
df.columns[0], df.columns[1]], object)
1924+
tm.assert_index_equal(res, expected)
1925+
19161926
def test_align_series(self):
19171927
rng = period_range('1/1/2000', '1/1/2010', freq='A')
19181928
ts = Series(np.random.randn(len(rng)), index=rng)
@@ -2185,15 +2195,15 @@ def test_minutely(self):
21852195

21862196
def test_secondly(self):
21872197
self._check_freq('S', '1970-01-01')
2188-
2198+
21892199
def test_millisecondly(self):
21902200
self._check_freq('L', '1970-01-01')
21912201

21922202
def test_microsecondly(self):
21932203
self._check_freq('U', '1970-01-01')
2194-
2204+
21952205
def test_nanosecondly(self):
2196-
self._check_freq('N', '1970-01-01')
2206+
self._check_freq('N', '1970-01-01')
21972207

21982208
def _check_freq(self, freq, base_date):
21992209
rng = PeriodIndex(start=base_date, periods=10, freq=freq)

pandas/tseries/tests/test_timeseries.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,12 @@
3131

3232
import pandas.index as _index
3333

34-
from pandas.compat import(
35-
range, long, StringIO, lrange, lmap, map, zip, cPickle as pickle, product
36-
)
37-
from pandas import read_pickle
34+
from pandas.compat import range, long, StringIO, lrange, lmap, zip, product
3835
import pandas.core.datetools as dt
3936
from numpy.random import rand
4037
from numpy.testing import assert_array_equal
4138
from pandas.util.testing import assert_frame_equal
4239
import pandas.compat as compat
43-
from pandas.core.datetools import BDay
4440
import pandas.core.common as com
4541
from pandas import concat
4642
from pandas import _np_version_under1p7
@@ -2064,6 +2060,18 @@ def test_ns_index(self):
20642060
new_index = pd.DatetimeIndex(start=index[0], end=index[-1], freq=index.freq)
20652061
self.assert_index_parameters(new_index)
20662062

2063+
def test_join_with_period_index(self):
2064+
df = tm.makeCustomDataframe(10, 10, data_gen_f=lambda *args:
2065+
np.random.randint(2), c_idx_type='p',
2066+
r_idx_type='dt')
2067+
s = df.iloc[:5, 0]
2068+
joins = 'left', 'right', 'inner', 'outer'
2069+
2070+
for join in joins:
2071+
with tm.assertRaisesRegexp(ValueError, 'can only call with other '
2072+
'PeriodIndex-ed objects'):
2073+
df.columns.join(s.index, how=join)
2074+
20672075

20682076
class TestDatetime64(unittest.TestCase):
20692077
"""

0 commit comments

Comments
 (0)