Skip to content

API: DatetimeIndex and PeriodIndex have same representation #7602

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 29, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/v0.14.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Enhancements
- Add ``NotImplementedError`` for simultaneous use of ``chunksize`` and ``nrows``
for read_csv() (:issue:`6774`).


- ``PeriodIndex`` is represented as the same format as ``DatetimeIndex`` (:issue:`7601`)



Expand Down
32 changes: 32 additions & 0 deletions pandas/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,36 @@ def max(self, axis=None):
max_stamp = masked.asi8.max()
return self._box_func(max_stamp)

@property
def _formatter_func(self):
"""
Format function to convert value to representation
"""
return str

def _format_footer(self):
tagline = 'Length: %d, Freq: %s, Timezone: %s'
return tagline % (len(self), self.freqstr, self.tz)

def __unicode__(self):
formatter = self._formatter_func
summary = str(self.__class__) + '\n'

n = len(self)
if n == 0:
pass
elif n == 1:
first = formatter(self[0])
summary += '[%s]\n' % first
elif n == 2:
first = formatter(self[0])
last = formatter(self[-1])
summary += '[%s, %s]\n' % (first, last)
else:
first = formatter(self[0])
last = formatter(self[-1])
summary += '[%s, ..., %s]\n' % (first, last)

summary += self._format_footer()
return summary

80 changes: 80 additions & 0 deletions pandas/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,40 @@ def test_minmax(self):
obj = DatetimeIndex([pd.NaT, pd.NaT, pd.NaT])
self.assertTrue(pd.isnull(getattr(obj, op)()))

def test_representation(self):
idx1 = DatetimeIndex([], freq='D')
idx2 = DatetimeIndex(['2011-01-01'], freq='D')
idx3 = DatetimeIndex(['2011-01-01', '2011-01-02'], freq='D')
idx4 = DatetimeIndex(['2011-01-01', '2011-01-02', '2011-01-03'], freq='D')
idx5 = DatetimeIndex(['2011-01-01 09:00', '2011-01-01 10:00', '2011-01-01 11:00'],
freq='H', tz='Asia/Tokyo')
idx6 = DatetimeIndex(['2011-01-01 09:00', '2011-01-01 10:00', pd.NaT],
tz='US/Eastern')

exp1 = """<class 'pandas.tseries.index.DatetimeIndex'>
Length: 0, Freq: D, Timezone: None"""
exp2 = """<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-01]
Length: 1, Freq: D, Timezone: None"""
exp3 = """<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-01, 2011-01-02]
Length: 2, Freq: D, Timezone: None"""
exp4 = """<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-01, ..., 2011-01-03]
Length: 3, Freq: D, Timezone: None"""
exp5 = """<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-01 09:00:00+09:00, ..., 2011-01-01 11:00:00+09:00]
Length: 3, Freq: H, Timezone: Asia/Tokyo"""
exp6 = """<class 'pandas.tseries.index.DatetimeIndex'>
[2011-01-01 09:00:00-05:00, ..., NaT]
Length: 3, Freq: None, Timezone: US/Eastern"""

for idx, expected in zip([idx1, idx2, idx3, idx4, idx5, idx6],
[exp1, exp2, exp3, exp4, exp5, exp6]):
for func in ['__repr__', '__unicode__', '__str__']:
result = getattr(idx, func)()
self.assertEqual(result, expected)


class TestPeriodIndexOps(Ops):
_allowed = '_allow_period_index_ops'
Expand Down Expand Up @@ -650,6 +684,52 @@ def test_minmax(self):
self.assertEqual(result.ordinal, tslib.iNaT)
self.assertEqual(result.freq, 'M')

def test_representation(self):
# GH 7601
idx1 = PeriodIndex([], freq='D')
idx2 = PeriodIndex(['2011-01-01'], freq='D')
idx3 = PeriodIndex(['2011-01-01', '2011-01-02'], freq='D')
idx4 = PeriodIndex(['2011-01-01', '2011-01-02', '2011-01-03'], freq='D')
idx5 = PeriodIndex(['2011', '2012', '2013'], freq='A')
idx6 = PeriodIndex(['2011-01-01 09:00', '2012-02-01 10:00', 'NaT'], freq='H')

idx7 = pd.period_range('2013Q1', periods=1, freq="Q")
idx8 = pd.period_range('2013Q1', periods=2, freq="Q")
idx9 = pd.period_range('2013Q1', periods=3, freq="Q")

exp1 = """<class 'pandas.tseries.period.PeriodIndex'>
Length: 0, Freq: D"""
exp2 = """<class 'pandas.tseries.period.PeriodIndex'>
[2011-01-01]
Length: 1, Freq: D"""
exp3 = """<class 'pandas.tseries.period.PeriodIndex'>
[2011-01-01, 2011-01-02]
Length: 2, Freq: D"""
exp4 = """<class 'pandas.tseries.period.PeriodIndex'>
[2011-01-01, ..., 2011-01-03]
Length: 3, Freq: D"""
exp5 = """<class 'pandas.tseries.period.PeriodIndex'>
[2011, ..., 2013]
Length: 3, Freq: A-DEC"""
exp6 = """<class 'pandas.tseries.period.PeriodIndex'>
[2011-01-01 09:00, ..., NaT]
Length: 3, Freq: H"""
exp7 = """<class 'pandas.tseries.period.PeriodIndex'>
[2013Q1]
Length: 1, Freq: Q-DEC"""
exp8 = """<class 'pandas.tseries.period.PeriodIndex'>
[2013Q1, 2013Q2]
Length: 2, Freq: Q-DEC"""
exp9 = """<class 'pandas.tseries.period.PeriodIndex'>
[2013Q1, ..., 2013Q3]
Length: 3, Freq: Q-DEC"""

for idx, expected in zip([idx1, idx2, idx3, idx4, idx5, idx6, idx7, idx8, idx9],
[exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8, exp9]):
for func in ['__repr__', '__unicode__', '__str__']:
result = getattr(idx, func)()
self.assertEqual(result, expected)


if __name__ == '__main__':
import nose
Expand Down
26 changes: 3 additions & 23 deletions pandas/tseries/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,31 +565,11 @@ def _is_dates_only(self):
from pandas.core.format import _is_dates_only
return _is_dates_only(self.values)

def __unicode__(self):
@property
def _formatter_func(self):
from pandas.core.format import _get_format_datetime64

formatter = _get_format_datetime64(is_dates_only=self._is_dates_only)

values = self.values

freq = self.freqstr
summary = str(self.__class__)
if len(self) == 1:
first = formatter(values[0], tz=self.tz)
summary += '\n[%s]' % first
elif len(self) == 2:
first = formatter(values[0], tz=self.tz)
last = formatter(values[-1], tz=self.tz)
summary += '\n[%s, %s]' % (first, last)
elif len(self) > 2:
first = formatter(values[0], tz=self.tz)
last = formatter(values[-1], tz=self.tz)
summary += '\n[%s, ..., %s]' % (first, last)

tagline = '\nLength: %d, Freq: %s, Timezone: %s'
summary += tagline % (len(self), freq, self.tz)

return summary
return lambda x: formatter(x, tz=self.tz)

def __reduce__(self):
"""Necessary for making this object picklable"""
Expand Down
34 changes: 3 additions & 31 deletions pandas/tseries/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,37 +1129,9 @@ def __array_finalize__(self, obj):
self.name = getattr(obj, 'name', None)
self._reset_identity()

def __repr__(self):
output = com.pprint_thing(self.__class__) + '\n'
output += 'freq: %s\n' % self.freq
n = len(self)
if n == 1:
output += '[%s]\n' % (self[0])
elif n == 2:
output += '[%s, %s]\n' % (self[0], self[-1])
elif n:
output += '[%s, ..., %s]\n' % (self[0], self[-1])
output += 'length: %d' % n
return output

def __unicode__(self):
output = self.__class__.__name__
output += u('(')
prefix = '' if compat.PY3 else 'u'
mapper = "{0}'{{0}}'".format(prefix)
output += '[{0}]'.format(', '.join(map(mapper.format, self)))
output += ", freq='{0}'".format(self.freq)
output += ')'
return output

def __bytes__(self):
encoding = com.get_option('display.encoding')
return self.__unicode__().encode(encoding, 'replace')

def __str__(self):
if compat.PY3:
return self.__unicode__()
return self.__bytes__()
def _format_footer(self):
tagline = 'Length: %d, Freq: %s'
return tagline % (len(self), self.freqstr)

def take(self, indices, axis=None):
"""
Expand Down
31 changes: 1 addition & 30 deletions pandas/tseries/tests/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -1798,65 +1798,39 @@ def test_asfreq_nat(self):
expected = PeriodIndex(['2011Q1', '2011Q1', 'NaT', '2011Q2'], freq='Q')
self.assertTrue(result.equals(expected))

def test_ts_repr(self):
index = PeriodIndex(freq='A', start='1/1/2001', end='12/31/2010')
ts = Series(np.random.randn(len(index)), index=index)
repr(ts) # ??

val = period_range('2013Q1', periods=1, freq="Q")
expected = "<class 'pandas.tseries.period.PeriodIndex'>\nfreq: Q-DEC\n[2013Q1]\nlength: 1"
assert_equal(repr(val), expected)

val = period_range('2013Q1', periods=2, freq="Q")
expected = "<class 'pandas.tseries.period.PeriodIndex'>\nfreq: Q-DEC\n[2013Q1, 2013Q2]\nlength: 2"
assert_equal(repr(val), expected)

val = period_range('2013Q1', periods=3, freq="Q")
expected = "<class 'pandas.tseries.period.PeriodIndex'>\nfreq: Q-DEC\n[2013Q1, ..., 2013Q3]\nlength: 3"
assert_equal(repr(val), expected)

def test_period_index_unicode(self):
def test_period_index_length(self):
pi = PeriodIndex(freq='A', start='1/1/2001', end='12/1/2009')
assert_equal(len(pi), 9)
assert_equal(pi, eval(compat.text_type(pi)))

pi = PeriodIndex(freq='Q', start='1/1/2001', end='12/1/2009')
assert_equal(len(pi), 4 * 9)
assert_equal(pi, eval(compat.text_type(pi)))

pi = PeriodIndex(freq='M', start='1/1/2001', end='12/1/2009')
assert_equal(len(pi), 12 * 9)
assert_equal(pi, eval(compat.text_type(pi)))

start = Period('02-Apr-2005', 'B')
i1 = PeriodIndex(start=start, periods=20)
assert_equal(len(i1), 20)
assert_equal(i1.freq, start.freq)
assert_equal(i1[0], start)
assert_equal(i1, eval(compat.text_type(i1)))

end_intv = Period('2006-12-31', 'W')
i1 = PeriodIndex(end=end_intv, periods=10)
assert_equal(len(i1), 10)
assert_equal(i1.freq, end_intv.freq)
assert_equal(i1[-1], end_intv)
assert_equal(i1, eval(compat.text_type(i1)))

end_intv = Period('2006-12-31', '1w')
i2 = PeriodIndex(end=end_intv, periods=10)
assert_equal(len(i1), len(i2))
self.assertTrue((i1 == i2).all())
assert_equal(i1.freq, i2.freq)
assert_equal(i1, eval(compat.text_type(i1)))
assert_equal(i2, eval(compat.text_type(i2)))

end_intv = Period('2006-12-31', ('w', 1))
i2 = PeriodIndex(end=end_intv, periods=10)
assert_equal(len(i1), len(i2))
self.assertTrue((i1 == i2).all())
assert_equal(i1.freq, i2.freq)
assert_equal(i1, eval(compat.text_type(i1)))
assert_equal(i2, eval(compat.text_type(i2)))

try:
PeriodIndex(start=start, end=end_intv)
Expand All @@ -1866,7 +1840,6 @@ def test_period_index_unicode(self):

end_intv = Period('2005-05-01', 'B')
i1 = PeriodIndex(start=start, end=end_intv)
assert_equal(i1, eval(compat.text_type(i1)))

try:
PeriodIndex(start=start)
Expand All @@ -1879,12 +1852,10 @@ def test_period_index_unicode(self):
i2 = PeriodIndex([end_intv, Period('2005-05-05', 'B')])
assert_equal(len(i2), 2)
assert_equal(i2[0], end_intv)
assert_equal(i2, eval(compat.text_type(i2)))

i2 = PeriodIndex(np.array([end_intv, Period('2005-05-05', 'B')]))
assert_equal(len(i2), 2)
assert_equal(i2[0], end_intv)
assert_equal(i2, eval(compat.text_type(i2)))

# Mixed freq should fail
vals = [end_intv, Period('2006-12-31', 'w')]
Expand Down