Skip to content

Commit 33659fd

Browse files
kawochenjreback
authored andcommitted
BUG: GH12622 where pprint of Timestamp in nested structure fails
closes #12622 I suspect this is a bug in Cython (I don't think `type(A).func` should be an `instancemethod`). Not sure if we should use this workaround as we encounter issues in the wild, or do this for all the functions we can think of. Author: Ka Wo Chen <[email protected]> Closes #12629 from kawochen/BUG-FIX-12622 and squashes the following commits: a6216ae [Ka Wo Chen] BUG: GH12622 where pprint of Timestamp in nested structure fails
1 parent 6531206 commit 33659fd

File tree

3 files changed

+65
-45
lines changed

3 files changed

+65
-45
lines changed

doc/source/whatsnew/v0.18.1.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ Bug Fixes
127127

128128

129129

130-
130+
- Bug in ``Timestamp.__repr__`` that caused ``pprint`` to fail in nested structures (:issue:`12622`)
131131

132132

133133

pandas/tseries/tests/test_tslib.py

+19
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,25 @@ def test_nat_fields(self):
453453
self.assertTrue(np.isnan(ts.daysinmonth))
454454
self.assertTrue(np.isnan(ts.days_in_month))
455455

456+
def test_pprint(self):
457+
# GH12622
458+
import pprint
459+
nested_obj = {'foo': 1,
460+
'bar': [{'w': {'a': Timestamp('2011-01-01')}}] * 10}
461+
result = pprint.pformat(nested_obj, width=50)
462+
expected = r'''{'bar': [{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
463+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
464+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
465+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
466+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
467+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
468+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
469+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
470+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}},
471+
{'w': {'a': Timestamp('2011-01-01 00:00:00')}}],
472+
'foo': 1}'''
473+
self.assertEqual(result, expected)
474+
456475

457476
class TestDatetimeParsingWrappers(tm.TestCase):
458477
def test_does_not_convert_mixed_integer(self):

pandas/tslib.pyx

+45-44
Original file line numberDiff line numberDiff line change
@@ -316,50 +316,6 @@ class Timestamp(_Timestamp):
316316

317317
return ts_base
318318

319-
def __repr__(self):
320-
stamp = self._repr_base
321-
zone = None
322-
323-
try:
324-
stamp += self.strftime('%z')
325-
if self.tzinfo:
326-
zone = _get_zone(self.tzinfo)
327-
except ValueError:
328-
year2000 = self.replace(year=2000)
329-
stamp += year2000.strftime('%z')
330-
if self.tzinfo:
331-
zone = _get_zone(self.tzinfo)
332-
333-
try:
334-
stamp += zone.strftime(' %%Z')
335-
except:
336-
pass
337-
338-
tz = ", tz='{0}'".format(zone) if zone is not None else ""
339-
offset = ", offset='{0}'".format(self.offset.freqstr) if self.offset is not None else ""
340-
341-
return "Timestamp('{stamp}'{tz}{offset})".format(stamp=stamp, tz=tz, offset=offset)
342-
343-
@property
344-
def _date_repr(self):
345-
# Ideal here would be self.strftime("%Y-%m-%d"), but
346-
# the datetime strftime() methods require year >= 1900
347-
return '%d-%.2d-%.2d' % (self.year, self.month, self.day)
348-
349-
@property
350-
def _time_repr(self):
351-
result = '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second)
352-
353-
if self.nanosecond != 0:
354-
result += '.%.9d' % (self.nanosecond + 1000 * self.microsecond)
355-
elif self.microsecond != 0:
356-
result += '.%.6d' % self.microsecond
357-
358-
return result
359-
360-
@property
361-
def _repr_base(self):
362-
return '%s %s' % (self._date_repr, self._time_repr)
363319

364320
def _round(self, freq, rounder):
365321

@@ -977,6 +933,30 @@ cdef class _Timestamp(datetime):
977933
self._assert_tzawareness_compat(other)
978934
return _cmp_scalar(self.value, ots.value, op)
979935

936+
def __repr__(self):
937+
stamp = self._repr_base
938+
zone = None
939+
940+
try:
941+
stamp += self.strftime('%z')
942+
if self.tzinfo:
943+
zone = _get_zone(self.tzinfo)
944+
except ValueError:
945+
year2000 = self.replace(year=2000)
946+
stamp += year2000.strftime('%z')
947+
if self.tzinfo:
948+
zone = _get_zone(self.tzinfo)
949+
950+
try:
951+
stamp += zone.strftime(' %%Z')
952+
except:
953+
pass
954+
955+
tz = ", tz='{0}'".format(zone) if zone is not None else ""
956+
offset = ", offset='{0}'".format(self.offset.freqstr) if self.offset is not None else ""
957+
958+
return "Timestamp('{stamp}'{tz}{offset})".format(stamp=stamp, tz=tz, offset=offset)
959+
980960
cdef bint _compare_outside_nanorange(_Timestamp self, datetime other,
981961
int op) except -1:
982962
cdef datetime dtval = self.to_datetime()
@@ -1098,6 +1078,27 @@ cdef class _Timestamp(datetime):
10981078
out = get_start_end_field(np.array([self.value], dtype=np.int64), field, freqstr, month_kw)
10991079
return out[0]
11001080

1081+
property _repr_base:
1082+
def __get__(self):
1083+
return '%s %s' % (self._date_repr, self._time_repr)
1084+
1085+
property _date_repr:
1086+
def __get__(self):
1087+
# Ideal here would be self.strftime("%Y-%m-%d"), but
1088+
# the datetime strftime() methods require year >= 1900
1089+
return '%d-%.2d-%.2d' % (self.year, self.month, self.day)
1090+
1091+
property _time_repr:
1092+
def __get__(self):
1093+
result = '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second)
1094+
1095+
if self.nanosecond != 0:
1096+
result += '.%.9d' % (self.nanosecond + 1000 * self.microsecond)
1097+
elif self.microsecond != 0:
1098+
result += '.%.6d' % self.microsecond
1099+
1100+
return result
1101+
11011102
property asm8:
11021103
def __get__(self):
11031104
return np.datetime64(self.value, 'ns')

0 commit comments

Comments
 (0)