[Python-checkins] python/nondist/sandbox/datetime obj_tzinfo.c,NONE,1.1 datetime.c,1.53,1.54 datetime.h,1.13,1.14 doc.txt,1.42,1.43 test_both.py,1.57,1.58 test_datetime.py,1.61,1.62

tim_one@users.sourceforge.net tim_one@users.sourceforge.net
Tue, 10 Dec 2002 17:47:23 -0800


Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv30696

Modified Files:
	datetime.c datetime.h doc.txt test_both.py test_datetime.py 
Added Files:
	obj_tzinfo.c 
Log Message:
Gave the tzinfo abstract base class a C implementation, and moved the
tests for it into test_both.

I never tried to implement an abstract base class in C before, and had
lots of problems, mostly cured by poking 0 into type slots.  Some Guido
who knows what he's doing here should review obj_tzinfo.c!


--- NEW FILE: obj_tzinfo.c ---
/*
 * PyDateTime_TZInfo implementation.
 */

/* This is a pure abstract base class, so doesn't do anything beyond
 * raising NotImplemented exceptions.  Real tzinfo classes need
 * to derive from this.  This is mostly for clarity, and for efficiency in
 * datetimetz and timetz constructors (their tzinfo arguments need to
 * be subclasses of this tzinfo class, which is easy and quick to check).
 */

static PyObject *
tzinfo_nogo(const char* methodname)
{
	PyErr_Format(PyExc_NotImplementedError,
		     "a tzinfo subclass must implement %s()",
		     methodname);
	return NULL;
}

/* Constructors -- you can't actually construct one of these!  Well,
 * you can, via fooling __new__, but you can't do much with it.
 */

static int
tzinfo_init(PyDateTime_TZInfo *self, PyObject *args, PyObject *kw)
{
	(void)tzinfo_nogo("__init__");
	return -1;
}

/* Methods.  A subclass must implement these. */

static PyObject*
tzinfo_tzname(PyTypeObject *self, PyObject *dt)
{
	return tzinfo_nogo("tzname");
}

static PyObject*
tzinfo_utcoffset(PyTypeObject *self, PyObject *dt)
{
	return tzinfo_nogo("utcoffset");
}

static PyObject*
tzinfo_dst(PyTypeObject *self, PyObject *dt)
{
	return tzinfo_nogo("dst");
}

static PyMethodDef tzinfo_methods[] = {
	{"tzname",	(PyCFunction)tzinfo_tzname,		METH_O,
	 PyDoc_STR("datetime -> string name of time zone.")},

	{"utcoffset",	(PyCFunction)tzinfo_utcoffset,		METH_O,
	 PyDoc_STR("datetime -> minutes east of UTC (negative for "
	 	   "west of UTC).")},

	{"dst",		(PyCFunction)tzinfo_dst,		METH_O,
	 PyDoc_STR("datetime -> DST offset in minutes east of UTC.")},

	{NULL, NULL}
};

static char tzinfo_doc[] =
PyDoc_STR("Abstract base class for time zone info objects.");

 statichere PyTypeObject PyDateTime_TZInfoType = {
	PyObject_HEAD_INIT(NULL)
	0,					/* ob_size */
	/* XXX When this module is renamed to datetime, change tp_name. */
	"_datetime.tzinfo",			/* tp_name */
	sizeof(PyDateTime_TZInfo),		/* tp_basicsize */
	0,					/* tp_itemsize */
	0,					/* tp_dealloc */
	0,					/* tp_print */
	0,					/* tp_getattr */
	0,					/* tp_setattr */
	0,					/* tp_compare */
	0,					/* tp_repr */
	0,					/* tp_as_number */
	0,					/* tp_as_sequence */
	0,					/* tp_as_mapping */
	0,					/* tp_hash */
	0,              			/* tp_call */
	0,					/* tp_str */
	PyObject_GenericGetAttr,		/* tp_getattro */
	0,					/* tp_setattro */
	0,					/* tp_as_buffer */
	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
        Py_TPFLAGS_BASETYPE,			/* tp_flags */
	tzinfo_doc,				/* tp_doc */
	0,					/* tp_traverse */
	0,					/* tp_clear */
	0,					/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	0,					/* tp_iter */
	0,					/* tp_iternext */
	tzinfo_methods,				/* tp_methods */
	0,					/* tp_members */
	0,					/* tp_getset */
	0,					/* tp_base */
	0,					/* tp_dict */
	0,					/* tp_descr_get */
	0,					/* tp_descr_set */
	0,					/* tp_dictoffset */
	(initproc)tzinfo_init,			/* tp_init */
	0,					/* tp_alloc */
	PyType_GenericNew,			/* tp_new */
	0,					/* tp_free */
};

Index: datetime.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.c,v
retrieving revision 1.53
retrieving revision 1.54
diff -C2 -d -r1.53 -r1.54
*** datetime.c	10 Dec 2002 02:04:26 -0000	1.53
--- datetime.c	11 Dec 2002 01:47:20 -0000	1.54
***************
*** 72,75 ****
--- 72,76 ----
  static PyTypeObject PyDateTime_DeltaType;
  static PyTypeObject PyDateTime_TimeType;
+ static PyTypeObject PyDateTime_TZInfoType;
  static PyTypeObject PyDateTime_TimeTZType;
  
***************
*** 665,668 ****
--- 666,670 ----
  #include "obj_datetime.c"
  #include "obj_time.c"
+ #include "obj_tzinfo.c"
  #include "obj_timetz.c"
  
***************
*** 704,707 ****
--- 706,711 ----
  	if (PyType_Ready(&PyDateTime_TimeType) < 0)
  		return;
+ 	if (PyType_Ready(&PyDateTime_TZInfoType) < 0)
+ 		return;
  	if (PyType_Ready(&PyDateTime_TimeTZType) < 0)
  		return;
***************
*** 802,805 ****
--- 806,812 ----
  	Py_INCREF(&PyDateTime_TimeType);
  	PyModule_AddObject(m, "time", (PyObject *) &PyDateTime_TimeType);
+ 
+ 	Py_INCREF(&PyDateTime_TZInfoType);
+ 	PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);
  
  	Py_INCREF(&PyDateTime_TimeTZType);

Index: datetime.h
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** datetime.h	10 Dec 2002 02:04:26 -0000	1.13
--- datetime.h	11 Dec 2002 01:47:20 -0000	1.14
***************
*** 67,70 ****
--- 67,75 ----
  } PyDateTime_Delta;
  
+ typedef struct
+ {
+ 	PyObject_HEAD		/* a pure abstract base clase */
+ } PyDateTime_TZInfo;
+ 
  /* Apply for date instances. */
  #define PyDateTime_GET_YEAR(o)     ((((PyDateTime_Date*)o)->data[0] << 8) | \

Index: doc.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/doc.txt,v
retrieving revision 1.42
retrieving revision 1.43
diff -C2 -d -r1.42 -r1.43
*** doc.txt	10 Dec 2002 21:59:51 -0000	1.42
--- doc.txt	11 Dec 2002 01:47:20 -0000	1.43
***************
*** 1,13 ****
  TODO/OPEN
  =========
- - Implement an abstract base tzinfo class.  Variant tzinfo classes must
-   subclass from this.
- 
  - datetimetz needs a C implementation.
  
  - timetz needs a C implementation.
  
- - tzinfo needs a C implementation.
- 
  - LaTeXize the docs.
  
--- 1,8 ----
***************
*** 17,20 ****
--- 12,23 ----
  CLOSED
  ======
+ - tzinfo needs a C implementation.
+   Done.
+ 
+ - Implement an abstract base tzinfo class.  Variant tzinfo classes must
+   subclass from this.
+   Done.
+ 
+ 
  - Subclass relationships.  Currently datetime is a subclass of date.
    I like this in practice, and think it's theoretically sound too.

Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.57
retrieving revision 1.58
diff -C2 -d -r1.57 -r1.58
*** test_both.py	9 Dec 2002 19:50:33 -0000	1.57
--- test_both.py	11 Dec 2002 01:47:20 -0000	1.58
***************
*** 41,44 ****
--- 41,45 ----
  timedelta = datetime.timedelta
  time = datetime.time
+ tzinfo = datetime.tzinfo
  MINYEAR = datetime.MINYEAR
  MAXYEAR = datetime.MAXYEAR
***************
*** 54,57 ****
--- 55,102 ----
  
  #############################################################################
+ # tzinfo tests
+ 
+ class NotEnough(tzinfo):
+     def __init__(self, offset, name):
+         self.__offset = offset
+         self.__name = name
+ 
+ class FixedOffset(tzinfo):
+     def __init__(self, offset, name):
+         self.__offset = offset
+         self.__name = name
+     def __repr__(self):
+         return self.__name.lower()
+     def utcoffset(self, dt):
+         return self.__offset
+     def tzname(self, dt):
+         return self.__name
+     def dst(self, dt):
+         return 0
+ 
+ class TestTZInfo(unittest.TestCase):
+ 
+     def test_abstractness(self):
+         self.assertRaises(NotImplementedError, tzinfo)
+ 
+     def test_subclass_must_override(self):
+         self.failUnless(issubclass(NotEnough, tzinfo))
+         ne = NotEnough(3, "NotByALongShot")
+         self.failUnless(isinstance(ne, tzinfo))
+ 
+         dt = datetime.datetime.now()
+         self.assertRaises(NotImplementedError, ne.tzname, dt)
+         self.assertRaises(NotImplementedError, ne.utcoffset, dt)
+         self.assertRaises(NotImplementedError, ne.dst, dt)
+ 
+     def test_normal(self):
+         fo = FixedOffset(3, "Three")
+         self.failUnless(isinstance(fo, tzinfo))
+         for dt in datetime.datetime.now(), None:
+             self.assertEqual(fo.utcoffset(dt), 3)
+             self.assertEqual(fo.tzname(dt), "Three")
+             self.assertEqual(fo.dst(dt), 0)
+ 
+ #############################################################################
  # timedelta tests
  
***************
*** 1397,1400 ****
--- 1442,1446 ----
      allsuites = [unittest.makeSuite(klass, 'test')
                   for klass in (TestModule,
+                                TestTZInfo,
                                 TestTimeDelta,
                                 TestDateOnly,

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.61
retrieving revision 1.62
diff -C2 -d -r1.61 -r1.62
*** test_datetime.py	10 Dec 2002 20:44:24 -0000	1.61
--- test_datetime.py	11 Dec 2002 01:47:20 -0000	1.62
***************
*** 16,24 ****
                       tzinfo, MINYEAR, MAXYEAR
  
- class NotEnough(tzinfo):
-     def __init__(self, offset, name):
-         self.__offset = offset
-         self.__name = name
- 
  class FixedOffset(tzinfo):
      def __init__(self, offset, name):
--- 16,19 ----
***************
*** 34,60 ****
          return 0
  
- class TestTZInfo(unittest.TestCase):
- 
-     def test_abstractness(self):
-         self.assertRaises(NotImplementedError, tzinfo)
- 
-     def test_subclass_must_override(self):
-         self.failUnless(issubclass(NotEnough, tzinfo))
-         ne = NotEnough(3, "NotByALongShot")
-         self.failUnless(isinstance(ne, tzinfo))
- 
-         dt = datetime.now()
-         self.assertRaises(NotImplementedError, ne.tzname, dt)
-         self.assertRaises(NotImplementedError, ne.utcoffset, dt)
-         self.assertRaises(NotImplementedError, ne.dst, dt)
- 
-     def test_normal(self):
-         fo = FixedOffset(3, "Three")
-         self.failUnless(isinstance(fo, tzinfo))
-         for dt in datetime.now(), None:
-             self.assertEqual(fo.utcoffset(dt), 3)
-             self.assertEqual(fo.tzname(dt), "Three")
-             self.assertEqual(fo.dst(dt), 0)
- 
  
  class TestTimeTZ(unittest.TestCase):
--- 29,32 ----
***************
*** 170,178 ****
  
  def test_suite():
-     s3 = unittest.makeSuite(TestTZInfo, 'test')
      s4 = unittest.makeSuite(TestTimeTZ, 'test')
      s5 = unittest.makeSuite(TestDateTime, 'test')
      s6 = unittest.makeSuite(TestDateTimeTZ, 'test')
!     return unittest.TestSuite([s3, s4, s5, s6])
  
  def test_main():
--- 142,149 ----
  
  def test_suite():
      s4 = unittest.makeSuite(TestTimeTZ, 'test')
      s5 = unittest.makeSuite(TestDateTime, 'test')
      s6 = unittest.makeSuite(TestDateTimeTZ, 'test')
!     return unittest.TestSuite([s4, s5, s6])
  
  def test_main():