[Zope3-checkins] SVN: Zope3/branches/stub-pytzpickle/src/pytz/ pytz
2005k (prerelease)
Stuart Bishop
stuart at stuartbishop.net
Sat Aug 13 23:59:07 EDT 2005
Log message for revision 37925:
pytz 2005k (prerelease)
Changed:
U Zope3/branches/stub-pytzpickle/src/pytz/README.txt
U Zope3/branches/stub-pytzpickle/src/pytz/__init__.py
U Zope3/branches/stub-pytzpickle/src/pytz/reference.py
U Zope3/branches/stub-pytzpickle/src/pytz/tzinfo.py
-=-
Modified: Zope3/branches/stub-pytzpickle/src/pytz/README.txt
===================================================================
--- Zope3/branches/stub-pytzpickle/src/pytz/README.txt 2005-08-14 02:46:32 UTC (rev 37924)
+++ Zope3/branches/stub-pytzpickle/src/pytz/README.txt 2005-08-14 03:58:36 UTC (rev 37925)
@@ -38,7 +38,11 @@
>>> from datetime import datetime, timedelta
>>> from pytz import timezone
>>> utc = timezone('UTC')
+>>> utc.zone
+'UTC'
>>> eastern = timezone('US/Eastern')
+>>> eastern.zone
+'US/Eastern'
>>> fmt = '%Y-%m-%d %H:%M:%S %Z%z'
The preferred way of dealing with times is to always work in UTC,
Modified: Zope3/branches/stub-pytzpickle/src/pytz/__init__.py
===================================================================
--- Zope3/branches/stub-pytzpickle/src/pytz/__init__.py 2005-08-14 02:46:32 UTC (rev 37924)
+++ Zope3/branches/stub-pytzpickle/src/pytz/__init__.py 2005-08-14 03:58:36 UTC (rev 37925)
@@ -1,7 +1,4 @@
-#!/usr/bin/env python
'''
-$Id: __init__.py,v 1.12 2005/02/15 20:21:41 zenzen Exp $
-
datetime.tzinfo timezone definitions generated from the
Olson timezone database:
@@ -12,22 +9,71 @@
'''
# The Olson database has historically been updated about 4 times a year
-OLSON_VERSION = '2005i'
+OLSON_VERSION = '2005k'
VERSION = OLSON_VERSION
#VERSION = OLSON_VERSION + '.2'
+__version__ = OLSON_VERSION
OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling
-__all__ = ['timezone', 'all_timezones', 'common_timezones', 'utc']
+__all__ = [
+ 'timezone', 'all_timezones', 'common_timezones', 'utc',
+ 'AmbiguousTimeError',
+ ]
import sys, datetime
+from tzinfo import AmbiguousTimeError, unpickler
-from tzinfo import AmbiguousTimeError
+def timezone(zone):
+ ''' Return a datetime.tzinfo implementation for the given timezone
+
+ >>> from datetime import datetime, timedelta
+ >>> utc = timezone('UTC')
+ >>> eastern = timezone('US/Eastern')
+ >>> eastern.zone
+ 'US/Eastern'
+ >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)
+ >>> loc_dt = utc_dt.astimezone(eastern)
+ >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
+ >>> loc_dt.strftime(fmt)
+ '2002-10-27 01:00:00 EST (-0500)'
+ >>> (loc_dt - timedelta(minutes=10)).strftime(fmt)
+ '2002-10-27 00:50:00 EST (-0500)'
+ >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt)
+ '2002-10-27 01:50:00 EDT (-0400)'
+ >>> (loc_dt + timedelta(minutes=10)).strftime(fmt)
+ '2002-10-27 01:10:00 EST (-0500)'
+ '''
+ zone = _munge_zone(zone)
+ if zone.upper() == 'UTC':
+ return utc
+ zone_bits = ['zoneinfo'] + zone.split('/')
+ # Load zone's module
+ module_name = '.'.join(zone_bits)
+ try:
+ module = __import__(module_name, globals(), locals())
+ except ImportError:
+ raise KeyError, zone
+ rv = module
+ for bit in zone_bits[1:]:
+ rv = getattr(rv, bit)
+
+ # Return instance from that module
+ rv = getattr(rv, zone_bits[-1])
+ assert type(rv) != type(sys)
+ return rv
+
+
+def _munge_zone(zone):
+ ''' Convert a zone into a string suitable for use as a Python identifier
+ '''
+ return zone.replace('+', '_plus_').replace('-', '_minus_')
+
+
ZERO = datetime.timedelta(0)
HOUR = datetime.timedelta(hours=1)
-# A UTC class.
class UTC(datetime.tzinfo):
"""UTC
@@ -35,7 +81,11 @@
Identical to the reference UTC implementation given in Python docs except
that it unpickles using the single module global instance defined beneath
this class declaration.
+
+ Also contains extra attributes and methods to match other pytz tzinfo
+ instances.
"""
+ zone = "UTC"
def utcoffset(self, dt):
return ZERO
@@ -62,11 +112,15 @@
return dt.replace(tzinfo=self)
def __repr__(self):
- return '<UTC>'
+ return "<UTC>"
+ def __str__(self):
+ return "UTC"
-UTC = utc = UTC()
+UTC = utc = UTC() # UTC is a singleton
+
+
def _UTC():
"""Factory function for utc unpickling.
@@ -99,50 +153,16 @@
return utc
_UTC.__safe_for_unpickling__ = True
-def timezone(zone):
- ''' Return a datetime.tzinfo implementation for the given timezone
-
- >>> from datetime import datetime, timedelta
- >>> utc = timezone('UTC')
- >>> eastern = timezone('US/Eastern')
- >>> eastern.zone
- 'US/Eastern'
- >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)
- >>> loc_dt = utc_dt.astimezone(eastern)
- >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'
- >>> loc_dt.strftime(fmt)
- '2002-10-27 01:00:00 EST (-0500)'
- >>> (loc_dt - timedelta(minutes=10)).strftime(fmt)
- '2002-10-27 00:50:00 EST (-0500)'
- >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt)
- '2002-10-27 01:50:00 EDT (-0400)'
- >>> (loc_dt + timedelta(minutes=10)).strftime(fmt)
- '2002-10-27 01:10:00 EST (-0500)'
- '''
- zone = _munge_zone(zone)
- if zone.upper() == 'UTC':
- return utc
- zone_bits = ['zoneinfo'] + zone.split('/')
- # Load zone's module
- module_name = '.'.join(zone_bits)
- try:
- module = __import__(module_name, globals(), locals())
- except ImportError:
- raise KeyError, zone
- rv = module
- for bit in zone_bits[1:]:
- rv = getattr(rv, bit)
+def _p(*args):
+ """Factory function for unpickling pytz tzinfo instances.
- # Return instance from that module
- rv = getattr(rv, zone_bits[-1])
- assert type(rv) != type(sys)
- return rv
+ Just a wrapper around tzinfo.unpickler to save a few bytes in each pickle
+ by shortening the path.
+ """
+ return unpickler(*args)
+_p.__safe_for_unpickling__ = True
-def _munge_zone(zone):
- ''' Convert a zone into a string suitable for use as a Python identifier
- '''
- return zone.replace('+', '_plus_').replace('-', '_minus_')
def _test():
import doctest, os, sys
Modified: Zope3/branches/stub-pytzpickle/src/pytz/reference.py
===================================================================
--- Zope3/branches/stub-pytzpickle/src/pytz/reference.py 2005-08-14 02:46:32 UTC (rev 37924)
+++ Zope3/branches/stub-pytzpickle/src/pytz/reference.py 2005-08-14 03:58:36 UTC (rev 37925)
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
'''
$Id: reference.py,v 1.2 2004/10/25 04:14:00 zenzen Exp $
Modified: Zope3/branches/stub-pytzpickle/src/pytz/tzinfo.py
===================================================================
--- Zope3/branches/stub-pytzpickle/src/pytz/tzinfo.py 2005-08-14 02:46:32 UTC (rev 37924)
+++ Zope3/branches/stub-pytzpickle/src/pytz/tzinfo.py 2005-08-14 03:58:36 UTC (rev 37925)
@@ -1,10 +1,13 @@
-#!/usr/bin/env python
-'''$Id: tzinfo.py,v 1.7 2005/02/15 20:21:52 zenzen Exp $'''
+'''Base classes and helpers for building zone specific tzinfo classes'''
from datetime import datetime, timedelta, tzinfo
from bisect import bisect_right
from sets import Set
+import pytz
+
+__all__ = []
+
_timedelta_cache = {}
def memorized_timedelta(seconds):
'''Create only one instance of each distinct timedelta'''
@@ -41,6 +44,11 @@
_notime = memorized_timedelta(0)
+def _to_seconds(td):
+ '''Convert a timedelta to seconds'''
+ return td.seconds + td.days * 24 * 60 * 60
+
+
class BaseTzInfo(tzinfo):
# Overridden in subclass
_utcoffset = None
@@ -49,14 +57,13 @@
def __str__(self):
return self.zone
-
+
class StaticTzInfo(BaseTzInfo):
'''A timezone that has a constant offset from UTC
These timezones are rare, as most regions have changed their
offset from UTC at some point in their history
-
'''
def fromutc(self, dt):
'''See datetime.tzinfo.fromutc'''
@@ -89,7 +96,12 @@
def __repr__(self):
return '<StaticTzInfo %r>' % (self.zone,)
+ def __reduce__(self):
+ # Special pickle to zone remains a singleton and to cope with
+ # database changes.
+ return pytz._p, (self.zone,)
+
class DstTzInfo(BaseTzInfo):
'''A timezone that has a variable offset from UTC
@@ -293,6 +305,17 @@
self.zone, self._tzname, self._utcoffset, dst
)
+ def __reduce__(self):
+ # Special pickle to zone remains a singleton and to cope with
+ # database changes.
+ return pytz._p, (
+ self.zone,
+ _to_seconds(self._utcoffset),
+ _to_seconds(self._dst),
+ self._tzname
+ )
+
+
class AmbiguousTimeError(Exception):
'''Exception raised when attempting to create an ambiguous wallclock time.
@@ -301,7 +324,56 @@
possibilities may be correct, unless further information is supplied.
See DstTzInfo.normalize() for more info
-
'''
+def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None):
+ """Factory function for unpickling pytz tzinfo instances.
+
+ This is shared for both StaticTzInfo and DstTzInfo instances, because
+ database changes could cause a zones implementation to switch between
+ these two base classes and we can't break pickles on a pytz version
+ upgrade.
+ """
+ # Raises a KeyError if zone no longer exists, which should never happen
+ # and would be a bug.
+ tz = pytz.timezone(zone)
+
+ # A StaticTzInfo - just return it
+ if utcoffset is None:
+ return tz
+
+ # This pickle was created from a DstTzInfo. We need to
+ # determine which of the list of tzinfo instances for this zone
+ # to use in order to restore the state of any datetime instances using
+ # it correctly.
+ utcoffset = memorized_timedelta(utcoffset)
+ dstoffset = memorized_timedelta(dstoffset)
+ try:
+ return tz._tzinfos[(utcoffset, dstoffset, tzname)]
+ except KeyError:
+ # The particular state requested in this timezone no longer exists.
+ # This indicates a corrupt pickle, or the timezone database has been
+ # corrected violently enough to make this particular
+ # (utcoffset,dstoffset) no longer exist in the zone, or the
+ # abbreviation has been changed.
+ pass
+
+ # See if we can find an entry differing only by tzname. Abbreviations
+ # get changed from the initial guess by the database maintainers to
+ # match reality when this information is discovered.
+ for localized_tz in tz._tzinfos.values():
+ if (localized_tz._utcoffset == utcoffset
+ and localized_tz._dst == dstoffset):
+ return localized_tz
+
+ # This (utcoffset, dstoffset) information has been removed from the
+ # zone. Add it back. This might occur when the database maintainers have
+ # corrected incorrect information. datetime instances using this
+ # incorrect information will continue to do so, exactly as they were
+ # before being pickled. This is purely an overly paranoid safety net - I
+ # doubt this will ever been needed in real life.
+ inf = (utcoffset, dstoffset, tzname)
+ tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos)
+ return tz._tzinfos[inf]
+
More information about the Zope3-Checkins
mailing list