mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	datetime.timedelta is now subclassable in Python. The new test shows
one good use: a subclass adding a method to express the duration as a number of hours (or minutes, or whatever else you want to add). The native breakdown into days+seconds+us is often clumsy. Incidentally moved a large chunk of object-initialization code closer to the top of the file, to avoid worse forward-reference trickery.
This commit is contained in:
		
							parent
							
								
									108c40c74c
								
							
						
					
					
						commit
						b0c854d6a7
					
				
					 3 changed files with 203 additions and 167 deletions
				
			
		|  | @ -443,6 +443,37 @@ def test_bool(self): | ||||||
|         self.failUnless(timedelta(microseconds=1)) |         self.failUnless(timedelta(microseconds=1)) | ||||||
|         self.failUnless(not timedelta(0)) |         self.failUnless(not timedelta(0)) | ||||||
| 
 | 
 | ||||||
|  |     def test_subclass_timedelta(self): | ||||||
|  | 
 | ||||||
|  |         class T(timedelta): | ||||||
|  |             def from_td(td): | ||||||
|  |                 return T(td.days, td.seconds, td.microseconds) | ||||||
|  |             from_td = staticmethod(from_td) | ||||||
|  | 
 | ||||||
|  |             def as_hours(self): | ||||||
|  |                 sum = (self.days * 24 + | ||||||
|  |                        self.seconds / 3600.0 + | ||||||
|  |                        self.microseconds / 3600e6) | ||||||
|  |                 return round(sum) | ||||||
|  | 
 | ||||||
|  |         t1 = T(days=1) | ||||||
|  |         self.assert_(type(t1) is T) | ||||||
|  |         self.assertEqual(t1.as_hours(), 24) | ||||||
|  | 
 | ||||||
|  |         t2 = T(days=-1, seconds=-3600) | ||||||
|  |         self.assert_(type(t2) is T) | ||||||
|  |         self.assertEqual(t2.as_hours(), -25) | ||||||
|  | 
 | ||||||
|  |         t3 = t1 + t2 | ||||||
|  |         self.assert_(type(t3) is timedelta) | ||||||
|  |         t4 = T.from_td(t3) | ||||||
|  |         self.assert_(type(t4) is T) | ||||||
|  |         self.assertEqual(t3.days, t4.days) | ||||||
|  |         self.assertEqual(t3.seconds, t4.seconds) | ||||||
|  |         self.assertEqual(t3.microseconds, t4.microseconds) | ||||||
|  |         self.assertEqual(str(t3), str(t4)) | ||||||
|  |         self.assertEqual(t4.as_hours(), -1) | ||||||
|  | 
 | ||||||
| ############################################################################# | ############################################################################# | ||||||
| # date tests | # date tests | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -26,8 +26,8 @@ Core and builtins | ||||||
| Extension modules | Extension modules | ||||||
| ----------------- | ----------------- | ||||||
| 
 | 
 | ||||||
| - The datetime.datetime and datetime.time classes are now properly | - The datetime module classes datetime, time, and timedelta are now | ||||||
|   subclassable. |   properly subclassable. | ||||||
| 
 | 
 | ||||||
| - _tkinter.{get|set}busywaitinterval was added. | - _tkinter.{get|set}busywaitinterval was added. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -561,6 +561,168 @@ normalize_datetime(int *year, int *month, int *day, | ||||||
| 	return normalize_date(year, month, day); | 	return normalize_date(year, month, day); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* ---------------------------------------------------------------------------
 | ||||||
|  |  * Basic object allocation:  tp_alloc implementations.  These allocate | ||||||
|  |  * Python objects of the right size and type, and do the Python object- | ||||||
|  |  * initialization bit.  If there's not enough memory, they return NULL after | ||||||
|  |  * setting MemoryError.  All data members remain uninitialized trash. | ||||||
|  |  * | ||||||
|  |  * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo | ||||||
|  |  * member is needed.  This is ugly. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | time_alloc(PyTypeObject *type, int aware) | ||||||
|  | { | ||||||
|  | 	PyObject *self; | ||||||
|  | 
 | ||||||
|  | 	self = (PyObject *) | ||||||
|  | 		PyObject_MALLOC(aware ? | ||||||
|  | 				sizeof(PyDateTime_Time) : | ||||||
|  | 				sizeof(_PyDateTime_BaseTime)); | ||||||
|  | 	if (self == NULL) | ||||||
|  | 		return (PyObject *)PyErr_NoMemory(); | ||||||
|  | 	PyObject_INIT(self, type); | ||||||
|  | 	return self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | datetime_alloc(PyTypeObject *type, int aware) | ||||||
|  | { | ||||||
|  | 	PyObject *self; | ||||||
|  | 
 | ||||||
|  | 	self = (PyObject *) | ||||||
|  | 		PyObject_MALLOC(aware ? | ||||||
|  | 				sizeof(PyDateTime_DateTime) : | ||||||
|  | 				sizeof(_PyDateTime_BaseDateTime)); | ||||||
|  | 	if (self == NULL) | ||||||
|  | 		return (PyObject *)PyErr_NoMemory(); | ||||||
|  | 	PyObject_INIT(self, type); | ||||||
|  | 	return self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ---------------------------------------------------------------------------
 | ||||||
|  |  * Helpers for setting object fields.  These work on pointers to the | ||||||
|  |  * appropriate base class. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* For date and datetime. */ | ||||||
|  | static void | ||||||
|  | set_date_fields(PyDateTime_Date *self, int y, int m, int d) | ||||||
|  | { | ||||||
|  | 	self->hashcode = -1; | ||||||
|  | 	SET_YEAR(self, y); | ||||||
|  | 	SET_MONTH(self, m); | ||||||
|  | 	SET_DAY(self, d); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ---------------------------------------------------------------------------
 | ||||||
|  |  * Create various objects, mostly without range checking. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* Create a date instance with no range checking. */ | ||||||
|  | static PyObject * | ||||||
|  | new_date_ex(int year, int month, int day, PyTypeObject *type) | ||||||
|  | { | ||||||
|  | 	PyDateTime_Date *self; | ||||||
|  | 
 | ||||||
|  | 	self = (PyDateTime_Date *) (type->tp_alloc(type, 0)); | ||||||
|  | 	if (self != NULL) | ||||||
|  | 		set_date_fields(self, year, month, day); | ||||||
|  | 	return (PyObject *) self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define new_date(year, month, day) \ | ||||||
|  | 	new_date_ex(year, month, day, &PyDateTime_DateType) | ||||||
|  | 
 | ||||||
|  | /* Create a datetime instance with no range checking. */ | ||||||
|  | static PyObject * | ||||||
|  | new_datetime_ex(int year, int month, int day, int hour, int minute, | ||||||
|  | 	     int second, int usecond, PyObject *tzinfo, PyTypeObject *type) | ||||||
|  | { | ||||||
|  | 	PyDateTime_DateTime *self; | ||||||
|  | 	char aware = tzinfo != Py_None; | ||||||
|  | 
 | ||||||
|  | 	self = (PyDateTime_DateTime *) (type->tp_alloc(type, aware)); | ||||||
|  | 	if (self != NULL) { | ||||||
|  | 		self->hastzinfo = aware; | ||||||
|  | 		set_date_fields((PyDateTime_Date *)self, year, month, day); | ||||||
|  | 		DATE_SET_HOUR(self, hour); | ||||||
|  | 		DATE_SET_MINUTE(self, minute); | ||||||
|  | 		DATE_SET_SECOND(self, second); | ||||||
|  | 		DATE_SET_MICROSECOND(self, usecond); | ||||||
|  | 		if (aware) { | ||||||
|  | 			Py_INCREF(tzinfo); | ||||||
|  | 			self->tzinfo = tzinfo; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (PyObject *)self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define new_datetime(y, m, d, hh, mm, ss, us, tzinfo)		\ | ||||||
|  | 	new_datetime_ex(y, m, d, hh, mm, ss, us, tzinfo,	\ | ||||||
|  | 			&PyDateTime_DateTimeType) | ||||||
|  | 
 | ||||||
|  | /* Create a time instance with no range checking. */ | ||||||
|  | static PyObject * | ||||||
|  | new_time_ex(int hour, int minute, int second, int usecond, | ||||||
|  | 	    PyObject *tzinfo, PyTypeObject *type) | ||||||
|  | { | ||||||
|  | 	PyDateTime_Time *self; | ||||||
|  | 	char aware = tzinfo != Py_None; | ||||||
|  | 
 | ||||||
|  | 	self = (PyDateTime_Time *) (type->tp_alloc(type, aware)); | ||||||
|  | 	if (self != NULL) { | ||||||
|  | 		self->hastzinfo = aware; | ||||||
|  | 		self->hashcode = -1; | ||||||
|  | 		TIME_SET_HOUR(self, hour); | ||||||
|  | 		TIME_SET_MINUTE(self, minute); | ||||||
|  | 		TIME_SET_SECOND(self, second); | ||||||
|  | 		TIME_SET_MICROSECOND(self, usecond); | ||||||
|  | 		if (aware) { | ||||||
|  | 			Py_INCREF(tzinfo); | ||||||
|  | 			self->tzinfo = tzinfo; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return (PyObject *)self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define new_time(hh, mm, ss, us, tzinfo)		\ | ||||||
|  | 	new_time_ex(hh, mm, ss, us, tzinfo, &PyDateTime_TimeType) | ||||||
|  | 
 | ||||||
|  | /* Create a timedelta instance.  Normalize the members iff normalize is
 | ||||||
|  |  * true.  Passing false is a speed optimization, if you know for sure | ||||||
|  |  * that seconds and microseconds are already in their proper ranges.  In any | ||||||
|  |  * case, raises OverflowError and returns NULL if the normalized days is out | ||||||
|  |  * of range). | ||||||
|  |  */ | ||||||
|  | static PyObject * | ||||||
|  | new_delta_ex(int days, int seconds, int microseconds, int normalize, | ||||||
|  | 	     PyTypeObject *type) | ||||||
|  | { | ||||||
|  | 	PyDateTime_Delta *self; | ||||||
|  | 
 | ||||||
|  | 	if (normalize) | ||||||
|  | 		normalize_d_s_us(&days, &seconds, µseconds); | ||||||
|  | 	assert(0 <= seconds && seconds < 24*3600); | ||||||
|  | 	assert(0 <= microseconds && microseconds < 1000000); | ||||||
|  | 
 | ||||||
|  |  	if (check_delta_day_range(days) < 0) | ||||||
|  |  		return NULL; | ||||||
|  | 
 | ||||||
|  | 	self = (PyDateTime_Delta *) (type->tp_alloc(type, 0)); | ||||||
|  | 	if (self != NULL) { | ||||||
|  | 		self->hashcode = -1; | ||||||
|  | 		SET_TD_DAYS(self, days); | ||||||
|  | 		SET_TD_SECONDS(self, seconds); | ||||||
|  | 		SET_TD_MICROSECONDS(self, microseconds); | ||||||
|  | 	} | ||||||
|  | 	return (PyObject *) self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #define new_delta(d, s, us, normalize)	\ | ||||||
|  | 	new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType) | ||||||
|  | 
 | ||||||
| /* ---------------------------------------------------------------------------
 | /* ---------------------------------------------------------------------------
 | ||||||
|  * tzinfo helpers. |  * tzinfo helpers. | ||||||
|  */ |  */ | ||||||
|  | @ -695,8 +857,6 @@ call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg, int *none) | ||||||
| 	return call_utc_tzinfo_method(tzinfo, "utcoffset", tzinfoarg, none); | 	return call_utc_tzinfo_method(tzinfo, "utcoffset", tzinfoarg, none); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject *new_delta(int d, int sec, int usec, int normalize); |  | ||||||
| 
 |  | ||||||
| /* Call tzinfo.name(tzinfoarg), and return the offset as a timedelta or None.
 | /* Call tzinfo.name(tzinfoarg), and return the offset as a timedelta or None.
 | ||||||
|  */ |  */ | ||||||
| static PyObject * | static PyObject * | ||||||
|  | @ -1234,165 +1394,6 @@ cmperror(PyObject *a, PyObject *b) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ---------------------------------------------------------------------------
 |  | ||||||
|  * Basic object allocation:  tp_alloc implementatiosn.  These allocate |  | ||||||
|  * Python objects of the right size and type, and do the Python object- |  | ||||||
|  * initialization bit.  If there's not enough memory, they return NULL after |  | ||||||
|  * setting MemoryError.  All data members remain uninitialized trash. |  | ||||||
|  * |  | ||||||
|  * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo |  | ||||||
|  * member is needed.  This is ugly. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| static PyObject * |  | ||||||
| time_alloc(PyTypeObject *type, int aware) |  | ||||||
| { |  | ||||||
| 	PyObject *self; |  | ||||||
| 
 |  | ||||||
| 	self = (PyObject *) |  | ||||||
| 		PyObject_MALLOC(aware ? |  | ||||||
| 				sizeof(PyDateTime_Time) : |  | ||||||
| 				sizeof(_PyDateTime_BaseTime)); |  | ||||||
| 	if (self == NULL) |  | ||||||
| 		return (PyObject *)PyErr_NoMemory(); |  | ||||||
| 	PyObject_INIT(self, type); |  | ||||||
| 	return self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * |  | ||||||
| datetime_alloc(PyTypeObject *type, int aware) |  | ||||||
| { |  | ||||||
| 	PyObject *self; |  | ||||||
| 
 |  | ||||||
| 	self = (PyObject *) |  | ||||||
| 		PyObject_MALLOC(aware ? |  | ||||||
| 				sizeof(PyDateTime_DateTime) : |  | ||||||
| 				sizeof(_PyDateTime_BaseDateTime)); |  | ||||||
| 	if (self == NULL) |  | ||||||
| 		return (PyObject *)PyErr_NoMemory(); |  | ||||||
| 	PyObject_INIT(self, type); |  | ||||||
| 	return self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* ---------------------------------------------------------------------------
 |  | ||||||
|  * Helpers for setting object fields.  These work on pointers to the |  | ||||||
|  * appropriate base class. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /* For date and datetime. */ |  | ||||||
| static void |  | ||||||
| set_date_fields(PyDateTime_Date *self, int y, int m, int d) |  | ||||||
| { |  | ||||||
| 	self->hashcode = -1; |  | ||||||
| 	SET_YEAR(self, y); |  | ||||||
| 	SET_MONTH(self, m); |  | ||||||
| 	SET_DAY(self, d); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* ---------------------------------------------------------------------------
 |  | ||||||
|  * Create various objects, mostly without range checking. |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| /* Create a date instance with no range checking. */ |  | ||||||
| static PyObject * |  | ||||||
| new_date_ex(int year, int month, int day, PyTypeObject *type) |  | ||||||
| { |  | ||||||
| 	PyDateTime_Date *self; |  | ||||||
| 
 |  | ||||||
| 	self = (PyDateTime_Date *) (type->tp_alloc(type, 0)); |  | ||||||
| 	if (self != NULL) |  | ||||||
| 		set_date_fields(self, year, month, day); |  | ||||||
| 	return (PyObject *) self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #define new_date(year, month, day) \ |  | ||||||
| 	new_date_ex(year, month, day, &PyDateTime_DateType) |  | ||||||
| 
 |  | ||||||
| /* Create a datetime instance with no range checking. */ |  | ||||||
| static PyObject * |  | ||||||
| new_datetime_ex(int year, int month, int day, int hour, int minute, |  | ||||||
| 	     int second, int usecond, PyObject *tzinfo, PyTypeObject *type) |  | ||||||
| { |  | ||||||
| 	PyDateTime_DateTime *self; |  | ||||||
| 	char aware = tzinfo != Py_None; |  | ||||||
| 
 |  | ||||||
| 	self = (PyDateTime_DateTime *) (type->tp_alloc(type, aware)); |  | ||||||
| 	if (self != NULL) { |  | ||||||
| 		self->hastzinfo = aware; |  | ||||||
| 		set_date_fields((PyDateTime_Date *)self, year, month, day); |  | ||||||
| 		DATE_SET_HOUR(self, hour); |  | ||||||
| 		DATE_SET_MINUTE(self, minute); |  | ||||||
| 		DATE_SET_SECOND(self, second); |  | ||||||
| 		DATE_SET_MICROSECOND(self, usecond); |  | ||||||
| 		if (aware) { |  | ||||||
| 			Py_INCREF(tzinfo); |  | ||||||
| 			self->tzinfo = tzinfo; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return (PyObject *)self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #define new_datetime(y, m, d, hh, mm, ss, us, tzinfo)		\ |  | ||||||
| 	new_datetime_ex(y, m, d, hh, mm, ss, us, tzinfo,	\ |  | ||||||
| 			&PyDateTime_DateTimeType) |  | ||||||
| 
 |  | ||||||
| /* Create a time instance with no range checking. */ |  | ||||||
| static PyObject * |  | ||||||
| new_time_ex(int hour, int minute, int second, int usecond, |  | ||||||
| 	    PyObject *tzinfo, PyTypeObject *type) |  | ||||||
| { |  | ||||||
| 	PyDateTime_Time *self; |  | ||||||
| 	char aware = tzinfo != Py_None; |  | ||||||
| 
 |  | ||||||
| 	self = (PyDateTime_Time *) (type->tp_alloc(type, aware)); |  | ||||||
| 	if (self != NULL) { |  | ||||||
| 		self->hastzinfo = aware; |  | ||||||
| 		self->hashcode = -1; |  | ||||||
| 		TIME_SET_HOUR(self, hour); |  | ||||||
| 		TIME_SET_MINUTE(self, minute); |  | ||||||
| 		TIME_SET_SECOND(self, second); |  | ||||||
| 		TIME_SET_MICROSECOND(self, usecond); |  | ||||||
| 		if (aware) { |  | ||||||
| 			Py_INCREF(tzinfo); |  | ||||||
| 			self->tzinfo = tzinfo; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return (PyObject *)self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #define new_time(hh, mm, ss, us, tzinfo)		\ |  | ||||||
| 	new_time_ex(hh, mm, ss, us, tzinfo, &PyDateTime_TimeType) |  | ||||||
| 
 |  | ||||||
| /* Create a timedelta instance.  Normalize the members iff normalize is
 |  | ||||||
|  * true.  Passing false is a speed optimization, if you know for sure |  | ||||||
|  * that seconds and microseconds are already in their proper ranges.  In any |  | ||||||
|  * case, raises OverflowError and returns NULL if the normalized days is out |  | ||||||
|  * of range). |  | ||||||
|  */ |  | ||||||
| static PyObject * |  | ||||||
| new_delta(int days, int seconds, int microseconds, int normalize) |  | ||||||
| { |  | ||||||
| 	PyDateTime_Delta *self; |  | ||||||
| 
 |  | ||||||
| 	if (normalize) |  | ||||||
| 		normalize_d_s_us(&days, &seconds, µseconds); |  | ||||||
| 	assert(0 <= seconds && seconds < 24*3600); |  | ||||||
| 	assert(0 <= microseconds && microseconds < 1000000); |  | ||||||
| 
 |  | ||||||
|  	if (check_delta_day_range(days) < 0) |  | ||||||
|  		return NULL; |  | ||||||
| 
 |  | ||||||
| 	self = PyObject_New(PyDateTime_Delta, &PyDateTime_DeltaType); |  | ||||||
| 	if (self != NULL) { |  | ||||||
| 		self->hashcode = -1; |  | ||||||
| 		SET_TD_DAYS(self, days); |  | ||||||
| 		SET_TD_SECONDS(self, seconds); |  | ||||||
| 		SET_TD_MICROSECONDS(self, microseconds); |  | ||||||
| 	} |  | ||||||
| 	return (PyObject *) self; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /* ---------------------------------------------------------------------------
 | /* ---------------------------------------------------------------------------
 | ||||||
|  * Cached Python objects; these are set by the module init function. |  * Cached Python objects; these are set by the module init function. | ||||||
|  */ |  */ | ||||||
|  | @ -1472,7 +1473,7 @@ delta_to_microseconds(PyDateTime_Delta *self) | ||||||
| /* Convert a number of us (as a Python int or long) to a timedelta.
 | /* Convert a number of us (as a Python int or long) to a timedelta.
 | ||||||
|  */ |  */ | ||||||
| static PyObject * | static PyObject * | ||||||
| microseconds_to_delta(PyObject *pyus) | microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) | ||||||
| { | { | ||||||
| 	int us; | 	int us; | ||||||
| 	int s; | 	int s; | ||||||
|  | @ -1542,7 +1543,7 @@ microseconds_to_delta(PyObject *pyus) | ||||||
| 				"large to fit in a C int"); | 				"large to fit in a C int"); | ||||||
| 		goto Done; | 		goto Done; | ||||||
| 	} | 	} | ||||||
| 	result = new_delta(d, s, us, 0); | 	result = new_delta_ex(d, s, us, 0, type); | ||||||
| 
 | 
 | ||||||
| Done: | Done: | ||||||
| 	Py_XDECREF(tuple); | 	Py_XDECREF(tuple); | ||||||
|  | @ -1550,6 +1551,9 @@ microseconds_to_delta(PyObject *pyus) | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define microseconds_to_delta(pymicros)	\ | ||||||
|  | 	microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType) | ||||||
|  | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) | multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) | ||||||
| { | { | ||||||
|  | @ -1924,7 +1928,7 @@ delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) | ||||||
| 		CLEANUP; | 		CLEANUP; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	self = microseconds_to_delta(x); | 	self = microseconds_to_delta_ex(x, type); | ||||||
| 	Py_DECREF(x); | 	Py_DECREF(x); | ||||||
| Done: | Done: | ||||||
| 	return self; | 	return self; | ||||||
|  | @ -2110,7 +2114,8 @@ static PyTypeObject PyDateTime_DeltaType = { | ||||||
| 	PyObject_GenericGetAttr,			/* tp_getattro */ | 	PyObject_GenericGetAttr,			/* tp_getattro */ | ||||||
| 	0,						/* tp_setattro */ | 	0,						/* tp_setattro */ | ||||||
| 	0,						/* tp_as_buffer */ | 	0,						/* tp_as_buffer */ | ||||||
| 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES,	/* tp_flags */ | 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | | ||||||
|  | 	        Py_TPFLAGS_BASETYPE,			/* tp_flags */ | ||||||
| 	delta_doc,					/* tp_doc */ | 	delta_doc,					/* tp_doc */ | ||||||
| 	0,						/* tp_traverse */ | 	0,						/* tp_traverse */ | ||||||
| 	0,						/* tp_clear */ | 	0,						/* tp_clear */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tim Peters
						Tim Peters