Skip to content

Commit

Permalink
Make DateTime a new-style class and limit its available attributes vi…
Browse files Browse the repository at this point in the history
…a a slots definition. The pickle size increases to 110 bytes thanks to the `ccopy_reg\n_reconstructor` stanza. But the memory size drops from 3kb to 500 bytes for each instance.
  • Loading branch information
hannosch committed May 8, 2011
1 parent 83b35fd commit c74219c
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog
3.0 (unreleased)
----------------

- Make DateTime a new-style class and limit its available attributes via a
slots definition. The pickle size increases to 110 bytes thanks to the
`ccopy_reg\n_reconstructor` stanza. But the memory size drops from 3kb to
500 bytes for each instance.

3.0a1 (2011-05-06)
------------------
Expand Down
55 changes: 42 additions & 13 deletions src/DateTime/DateTime.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def _tzoffset2iso8601zone(seconds):
return "%+03d:%02d" % divmod( (seconds/60), 60)


class DateTime:
class DateTime(object):
"""DateTime objects represent instants in time and provide
interfaces for controlling its representation without
affecting the absolute value of the object.
Expand Down Expand Up @@ -327,15 +327,47 @@ class DateTime:
implements(IDateTime)

# For security machinery:
__roles__=None
__allow_access_to_unprotected_subobjects__=1
__roles__ = None
__allow_access_to_unprotected_subobjects__ = 1

# Make class-specific exceptions available as attributes.
DateError = DateError
TimeError = TimeError
DateTimeError = DateTimeError
SyntaxError = SyntaxError

# Limit the amount of instance attributes
__slots__ = (
'_timezone_naive',
'_tz',
'_pm',
'_pmhour',
'_dayoffset',
'_fmon',
'_amon',
'_pmon',
'_months',
'_months_a',
'_months_p',
'_fday',
'_aday',
'_pday',
'_days',
'_days_a',
'_days_p',
'_year',
'_month',
'_day',
'_hour',
'_minute',
'_second',
'_nearsec',
'_d',
'_t',
'_micros',
'time',
)

def __init__(self, *args, **kw):
"""Return a new date-time object"""
if args and args[0] is None:
Expand All @@ -349,20 +381,17 @@ def __init__(self, *args, **kw):
raise SyntaxError('Unable to parse %s, %s' % (args, kw))

def __getstate__(self):
state = self.__dict__
return (state['_micros'] / 1000000.0,
state.get('_timezone_naive', False),
state['_tz'])
return (self._micros / 1000000.0, self._timezone_naive, self._tz)

def __setstate__(self, value):
state = self.__dict__
if isinstance(value, tuple):
self._parse_args(value[0], value[2])
state['_micros'] = long(value[0] * 1000000)
state['_timezone_naive'] = value[1]
self._micros = long(value[0] * 1000000)
self._timezone_naive = value[1]
else:
state.clear()
state.update(value)
for k,v in value.items():
if k in self.__slots__:
setattr(self, k, v)

def _parse_args(self, *args, **kw):
"""Return a new date-time object.
Expand Down Expand Up @@ -1050,7 +1079,7 @@ def _validTime(self,h,m,s):
def __getattr__(self, name):
if '%' in name:
return strftimeFormatter(self, name)
raise AttributeError, name
raise AttributeError(name)

# Conversion and comparison methods
def timeTime(self):
Expand Down
2 changes: 1 addition & 1 deletion src/DateTime/DateTime.txt
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ however, a DateTime may not be subtracted from a number:
>>> 1 - dt
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for -: 'int' and 'instance'
TypeError: unsupported operand type(s) for -: 'int' and 'DateTime'

DateTimes can also be converted to integers (number of seconds since
the epoch), longs (not too long ;)) and floats:
Expand Down
12 changes: 8 additions & 4 deletions src/DateTime/tests/testDateTime.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,19 +202,22 @@ def test_pickle(self):
dt = DateTime()
data = cPickle.dumps(dt, 1)
new = cPickle.loads(data)
self.assertEqual(dt.__dict__, new.__dict__)
for key in DateTime.__slots__:
self.assertEqual(getattr(dt, key), getattr(new, key))

def test_pickle_with_tz(self):
dt = DateTime('2002/5/2 8:00am GMT+8')
data = cPickle.dumps(dt, 1)
new = cPickle.loads(data)
self.assertEqual(dt.__dict__, new.__dict__)
for key in DateTime.__slots__:
self.assertEqual(getattr(dt, key), getattr(new, key))

def test_pickle_with_micros(self):
dt = DateTime('2002/5/2 8:00:14.123 GMT+8')
data = cPickle.dumps(dt, 1)
new = cPickle.loads(data)
self.assertEqual(dt.__dict__, new.__dict__)
for key in DateTime.__slots__:
self.assertEqual(getattr(dt, key), getattr(new, key))

def test_pickle_old(self):
dt = DateTime('2002/5/2 8:00am GMT+0')
Expand All @@ -231,7 +234,8 @@ def test_pickle_old(self):
'\x00U\x07_pmhourq\x1dK\x08U\n_dayoffsetq\x1eK\x04U\x04timeq'
'\x1fG?\xd5UUUV\x00\x00ub.')
new = cPickle.loads(data)
self.assertEqual(dt.__dict__, new.__dict__)
for key in DateTime.__slots__:
self.assertEqual(getattr(dt, key), getattr(new, key))

def testTZ2(self):
# Time zone manipulation test 2
Expand Down

0 comments on commit c74219c

Please sign in to comment.