bpo-30302 Make timedelta.__repr__ more informative. (#1493)

This commit is contained in:
Utkarsh Upadhyay 2017-07-25 23:51:33 +02:00 committed by Victor Stinner
parent 830080913c
commit cc5a65cd90
6 changed files with 73 additions and 32 deletions

View File

@ -287,11 +287,12 @@ Supported operations:
| | ``[D day[s], ][H]H:MM:SS[.UUUUUU]``, where D | | | ``[D day[s], ][H]H:MM:SS[.UUUUUU]``, where D |
| | is negative for negative ``t``. (5) | | | is negative for negative ``t``. (5) |
+--------------------------------+-----------------------------------------------+ +--------------------------------+-----------------------------------------------+
| ``repr(t)`` | Returns a string in the form | | ``repr(t)`` | Returns a string representation of the |
| | ``datetime.timedelta(D[, S[, U]])``, where D | | | :class:`timedelta` object as a constructor |
| | is negative for negative ``t``. (5) | | | call with canonical attribute values. |
+--------------------------------+-----------------------------------------------+ +--------------------------------+-----------------------------------------------+
Notes: Notes:
(1) (1)

View File

@ -454,20 +454,18 @@ class timedelta:
return self return self
def __repr__(self): def __repr__(self):
if self._microseconds: args = []
return "%s.%s(%d, %d, %d)" % (self.__class__.__module__, if self._days:
self.__class__.__qualname__, args.append("days=%d" % self._days)
self._days,
self._seconds,
self._microseconds)
if self._seconds: if self._seconds:
return "%s.%s(%d, %d)" % (self.__class__.__module__, args.append("seconds=%d" % self._seconds)
self.__class__.__qualname__, if self._microseconds:
self._days, args.append("microseconds=%d" % self._microseconds)
self._seconds) if not args:
return "%s.%s(%d)" % (self.__class__.__module__, args.append('0')
return "%s.%s(%s)" % (self.__class__.__module__,
self.__class__.__qualname__, self.__class__.__qualname__,
self._days) ', '.join(args))
def __str__(self): def __str__(self):
mm, ss = divmod(self._seconds, 60) mm, ss = divmod(self._seconds, 60)

View File

@ -658,11 +658,21 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase):
def test_repr(self): def test_repr(self):
name = 'datetime.' + self.theclass.__name__ name = 'datetime.' + self.theclass.__name__
self.assertEqual(repr(self.theclass(1)), self.assertEqual(repr(self.theclass(1)),
"%s(1)" % name) "%s(days=1)" % name)
self.assertEqual(repr(self.theclass(10, 2)), self.assertEqual(repr(self.theclass(10, 2)),
"%s(10, 2)" % name) "%s(days=10, seconds=2)" % name)
self.assertEqual(repr(self.theclass(-10, 2, 400000)), self.assertEqual(repr(self.theclass(-10, 2, 400000)),
"%s(-10, 2, 400000)" % name) "%s(days=-10, seconds=2, microseconds=400000)" % name)
self.assertEqual(repr(self.theclass(seconds=60)),
"%s(seconds=60)" % name)
self.assertEqual(repr(self.theclass()),
"%s(0)" % name)
self.assertEqual(repr(self.theclass(microseconds=100)),
"%s(microseconds=100)" % name)
self.assertEqual(repr(self.theclass(days=1, microseconds=100)),
"%s(days=1, microseconds=100)" % name)
self.assertEqual(repr(self.theclass(seconds=1, microseconds=100)),
"%s(seconds=1, microseconds=100)" % name)
def test_roundtrip(self): def test_roundtrip(self):
for td in (timedelta(days=999999999, hours=23, minutes=59, for td in (timedelta(days=999999999, hours=23, minutes=59,

View File

@ -50,6 +50,8 @@ for module, suffix in zip(test_modules, test_suffixes):
cls.tearDownClass = tearDownClass cls.tearDownClass = tearDownClass
all_test_classes.extend(test_classes) all_test_classes.extend(test_classes)
all_test_classes.extend(test_classes)
def test_main(): def test_main():
run_unittest(*all_test_classes) run_unittest(*all_test_classes)

View File

@ -0,0 +1 @@
Use keywords in the ``repr`` of ``datetime.timedelta``.

View File

@ -2284,21 +2284,50 @@ delta_bool(PyDateTime_Delta *self)
static PyObject * static PyObject *
delta_repr(PyDateTime_Delta *self) delta_repr(PyDateTime_Delta *self)
{ {
if (GET_TD_MICROSECONDS(self) != 0) PyObject *args = PyUnicode_FromString("");
return PyUnicode_FromFormat("%s(%d, %d, %d)",
Py_TYPE(self)->tp_name,
GET_TD_DAYS(self),
GET_TD_SECONDS(self),
GET_TD_MICROSECONDS(self));
if (GET_TD_SECONDS(self) != 0)
return PyUnicode_FromFormat("%s(%d, %d)",
Py_TYPE(self)->tp_name,
GET_TD_DAYS(self),
GET_TD_SECONDS(self));
return PyUnicode_FromFormat("%s(%d)", if (args == NULL) {
Py_TYPE(self)->tp_name, return NULL;
GET_TD_DAYS(self)); }
const char *sep = "";
if (GET_TD_DAYS(self) != 0) {
Py_SETREF(args, PyUnicode_FromFormat("days=%d", GET_TD_DAYS(self)));
if (args == NULL) {
return NULL;
}
sep = ", ";
}
if (GET_TD_SECONDS(self) != 0) {
Py_SETREF(args, PyUnicode_FromFormat("%U%sseconds=%d", args, sep,
GET_TD_SECONDS(self)));
if (args == NULL) {
return NULL;
}
sep = ", ";
}
if (GET_TD_MICROSECONDS(self) != 0) {
Py_SETREF(args, PyUnicode_FromFormat("%U%smicroseconds=%d", args, sep,
GET_TD_MICROSECONDS(self)));
if (args == NULL) {
return NULL;
}
}
if (PyUnicode_GET_LENGTH(args) == 0) {
Py_SETREF(args, PyUnicode_FromString("0"));
if (args == NULL) {
return NULL;
}
}
PyObject *repr = PyUnicode_FromFormat("%s(%S)", Py_TYPE(self)->tp_name,
args);
Py_DECREF(args);
return repr;
} }
static PyObject * static PyObject *