[Python-checkins] python/nondist/sandbox/datetime datetime.py,1.152,1.153 test_datetime.py,1.106,1.107

gvanrossum@users.sourceforge.net gvanrossum@users.sourceforge.net
Wed, 29 Jan 2003 22:01:10 -0800


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

Modified Files:
	datetime.py test_datetime.py 
Log Message:
Experimental support for pickle protocol 2.  Classes timedelta, date,
time, and datetime now have a __new__ method instead of __init__.
(Class tzinfo not yet; I'll have to think more about it.)  I've added
__getnewargs__ as an alias for __getstate__ for each of these classes.
The state for date is now a tuple (for the others it already was a
tuple).

The test suite now tests protocols 0, 1 and 2; this is the only change
(except one place where the state of a date was compared to a string
literal).  It passes for Python 2.2 as well as for Python 2.3.

XXX The pickles are not compatible with those of the C implementation!
XXX But I think the C implementation can be changed to match, and it
XXX will work for all three protocols, in both Python versions.
XXX Fingers crossed.  Goodnight.



Index: datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/datetime.py,v
retrieving revision 1.152
retrieving revision 1.153
diff -C2 -d -r1.152 -r1.153
*** datetime.py	24 Jan 2003 18:56:35 -0000	1.152
--- datetime.py	30 Jan 2003 06:01:06 -0000	1.153
***************
*** 403,409 ****
      """
  
!     def __init__(self, days=0, seconds=0, microseconds=0,
!                  # XXX The following should only be used as keyword args:
!                  milliseconds=0, minutes=0, hours=0, weeks=0):
          # Doing this efficiently and accurately in C is going to be difficult
          # and error-prone, due to ubiquitous overflow possibilities, and that
--- 403,409 ----
      """
  
!     def __new__(cls, days=0, seconds=0, microseconds=0,
!                 # XXX The following should only be used as keyword args:
!                 milliseconds=0, minutes=0, hours=0, weeks=0):
          # Doing this efficiently and accurately in C is going to be difficult
          # and error-prone, due to ubiquitous overflow possibilities, and that
***************
*** 506,509 ****
--- 506,512 ----
          assert isinstance(s, int) and 0 <= s < 24*3600
          assert isinstance(us, int) and 0 <= us < 1000000
+ 
+         self = object.__new__(cls)
+ 
          self.__days = d
          self.__seconds = s
***************
*** 512,515 ****
--- 515,520 ----
              raise OverflowError("timedelta # of days is too large: %d" % d)
  
+         return self
+ 
      def __repr__(self):
          if self.__microseconds:
***************
*** 611,619 ****
      __safe_for_unpickling__ = True
  
-     def __reduce__(self):
-         return type(self), (), self.__getstate__()
- 
      def __getstate__(self):
          return (self.__days, self.__seconds, self.__microseconds)
  
      def __setstate__(self, tup):
--- 616,622 ----
      __safe_for_unpickling__ = True
  
      def __getstate__(self):
          return (self.__days, self.__seconds, self.__microseconds)
+     __getnewargs__ = __getstate__
  
      def __setstate__(self, tup):
***************
*** 630,634 ****
      Constructors:
  
!     __init__()
      fromtimestamp()
      today()
--- 633,637 ----
      Constructors:
  
!     __new__()
      fromtimestamp()
      today()
***************
*** 654,658 ****
      """
  
!     def __init__(self, year, month, day):
          """Constructor.
  
--- 657,661 ----
      """
  
!     def __new__(cls, year, month=None, day=None):
          """Constructor.
  
***************
*** 661,668 ****
--- 664,678 ----
          year, month, day (required, base 1)
          """
+         if isinstance(year, str):
+             # From pickle __getstate__
+             self = object.__new__(cls)
+             self.__setstate__((year,))
+             return self
          _check_date_fields(year, month, day)
+         self = object.__new__(cls)
          self.__year = year
          self.__month = month
          self.__day = day
+         return self
  
      # Additional constructors
***************
*** 845,851 ****
      def __getstate__(self):
          yhi, ylo = divmod(self.__year, 256)
!         return "%c%c%c%c" % (yhi, ylo, self.__month, self.__day)
  
!     def __setstate__(self, string):
          assert len(string) == 4
          yhi, ylo, self.__month, self.__day = map(ord, string)
--- 855,864 ----
      def __getstate__(self):
          yhi, ylo = divmod(self.__year, 256)
!         return ("%c%c%c%c" % (yhi, ylo, self.__month, self.__day), )
!     __getnewargs__ = __getstate__
  
!     def __setstate__(self, t):
!         assert isinstance(t, tuple) and len(t) == 1, `t`
!         string = t[0]
          assert len(string) == 4
          yhi, ylo, self.__month, self.__day = map(ord, string)
***************
*** 911,914 ****
--- 924,928 ----
  
      # pickle support
+     # XXX Should do something with __new__ instead
  
      __safe_for_unpickling__ = True
***************
*** 917,920 ****
--- 931,936 ----
          return type(self), (), self.__dict__
  
+ _tzinfo_class = tzinfo   # so functions w/ args named "tinfo" can get at it
+ 
  class time(object):
      """Time with time zone.
***************
*** 922,926 ****
      Constructors:
  
!     __init__()
  
      Operators:
--- 938,942 ----
      Constructors:
  
!     __new__()
  
      Operators:
***************
*** 941,945 ****
      """
  
!     def __init__(self, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
          """Constructor.
  
--- 957,961 ----
      """
  
!     def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
          """Constructor.
  
***************
*** 950,953 ****
--- 966,979 ----
          tzinfo (default to None)
          """
+         self = object.__new__(cls)
+         if isinstance(hour, str):
+             # Call from protocol 2 unpickling
+             assert len(hour) == 6
+             assert minute == 0 or isinstance(minute, _tzinfo_class), `minute`
+             self.__hour, self.__minute, self.__second, us1, us2, us3 = \
+               map(ord, hour)
+             self.__microsecond = (((us1 << 8) | us2) << 8) | us3
+             self._tzinfo = minute or None
+             return self
          _check_tzinfo_arg(tzinfo)
          _check_time_fields(hour, minute, second, microsecond)
***************
*** 957,960 ****
--- 983,987 ----
          self.__microsecond = microsecond
          self._tzinfo = tzinfo
+         return self
  
      # Read-only field accessors
***************
*** 1148,1151 ****
--- 1175,1179 ----
          else:
              return (basestate, self._tzinfo)
+     __getnewargs__ = __getstate__
  
      def __setstate__(self, state):
***************
*** 1176,1184 ****
      # See http://www.zope.org/Members/fdrake/DateTimeWiki/TimeZoneInfo
  
!     def __init__(self, year, month, day, hour=0, minute=0, second=0,
!                  microsecond=0, tzinfo=None):
          _check_tzinfo_arg(tzinfo)
          _check_time_fields(hour, minute, second, microsecond)
!         date.__init__(self, year, month, day)
          # XXX This duplicates __year, __month, __day for convenience :-(
          self.__year = year
--- 1204,1217 ----
      # See http://www.zope.org/Members/fdrake/DateTimeWiki/TimeZoneInfo
  
!     def __new__(cls, year, month=None, day=None, hour=0, minute=0, second=0,
!                 microsecond=0, tzinfo=None):
!         if isinstance(year, str):
!             # Pickle support
!             self = date.__new__(cls, 1, 1, 1)
!             self.__setstate__((year, month))
!             return self
          _check_tzinfo_arg(tzinfo)
          _check_time_fields(hour, minute, second, microsecond)
!         self = date.__new__(cls, year, month, day)
          # XXX This duplicates __year, __month, __day for convenience :-(
          self.__year = year
***************
*** 1190,1193 ****
--- 1223,1227 ----
          self.__microsecond = microsecond
          self._tzinfo = tzinfo
+         return self
  
      # Read-only field accessors
***************
*** 1533,1536 ****
--- 1567,1571 ----
          else:
              return (basestate, self._tzinfo)
+     __getnewargs__ = __getstate__
  
      def __setstate__(self, state):
***************
*** 1607,1618 ****
      self.__setstate__(state)
      return self
- 
- # Register pickle/unpickle functions.
- from copy_reg import pickle
- pickle(date, _date_pickler, _date_unpickler)
- pickle(tzinfo, _tzinfo_pickler, _tzinfo_unpickler)
- pickle(time, _time_pickler, _time_unpickler)
- pickle(datetime, _datetime_pickler, _datetime_unpickler)
- del pickle
  
  """
--- 1642,1645 ----

Index: test_datetime.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_datetime.py,v
retrieving revision 1.106
retrieving revision 1.107
diff -C2 -d -r1.106 -r1.107
*** test_datetime.py	24 Jan 2003 22:32:27 -0000	1.106
--- test_datetime.py	30 Jan 2003 06:01:07 -0000	1.107
***************
*** 107,112 ****
          self.failUnless(type(orig) is tzinfo)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.failUnless(type(derived) is tzinfo)
--- 107,112 ----
          self.failUnless(type(orig) is tzinfo)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.failUnless(type(derived) is tzinfo)
***************
*** 123,128 ****
          self.assertEqual(orig.tzname(None), 'cookie')
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.failUnless(isinstance(derived, tzinfo))
--- 123,128 ----
          self.assertEqual(orig.tzname(None), 'cookie')
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.failUnless(isinstance(derived, tzinfo))
***************
*** 272,277 ****
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 272,277 ----
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 826,836 ****
          orig = self.theclass(*args)
          state = orig.__getstate__()
!         self.assertEqual(state, '\x00\x06\x07\x17')
          derived = self.theclass(1, 1, 1)
          derived.__setstate__(state)
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 826,836 ----
          orig = self.theclass(*args)
          state = orig.__getstate__()
!         self.assertEqual(state, ('\x00\x06\x07\x17',))
          derived = self.theclass(1, 1, 1)
          derived.__setstate__(state)
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 1190,1195 ****
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 1190,1195 ----
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 1576,1581 ****
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 1576,1581 ----
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 1892,1897 ****
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 1892,1897 ----
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 1909,1914 ****
  
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 1909,1914 ----
  
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 2111,2116 ****
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 2111,2116 ----
          self.assertEqual(orig, derived)
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
***************
*** 2128,2133 ****
  
          for pickler in pickle, cPickle:
!             for binary in 0, 1:
!                 green = pickler.dumps(orig, binary)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)
--- 2128,2133 ----
  
          for pickler in pickle, cPickle:
!             for proto in 0, 1, 2:
!                 green = pickler.dumps(orig, proto)
                  derived = pickler.loads(green)
                  self.assertEqual(orig, derived)