[pywin32-checkins] /hgroot/pywin32/pywin32: 4 new changesets
OLD project page for the Python extensions for Windows
Brought to you by:
mhammond
From: <pyw...@li...> - 2012-04-26 01:22:37
|
changeset f236bfbddd8e in /hgroot/pywin32/pywin32 details: http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/hgroot/pywin32/pywin32?cmd=changeset;node=f236bfbddd8e summary: Cleaned up some unused imports, indentation issues, and encoding issues. Tests now passing again on Python 2.7.3 changeset 4a170a732caf in /hgroot/pywin32/pywin32 details: http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/hgroot/pywin32/pywin32?cmd=changeset;node=4a170a732caf summary: Added a test to capture failing dynamic info resolution as reported in #3521185. changeset 0d04c356ccdc in /hgroot/pywin32/pywin32 details: http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/hgroot/pywin32/pywin32?cmd=changeset;node=0d04c356ccdc summary: Identified another test that indicates the failure changeset aa3a7ed32634 in /hgroot/pywin32/pywin32 details: http://pywin32.hg.sourceforge.net/hgweb/pywin32/pywin32/hgroot/pywin32/pywin32?cmd=changeset;node=aa3a7ed32634 summary: Updated RangeMap implementation with version from jaraco.util 5.3.1 that includes a fix for RangeMap.get. This fixes the failing tests, including the issue identified by 3521185. diffstat: win32/Lib/win32timezone.py | 185 ++++++++++++++++++++++++++++++-------------- 1 files changed, 124 insertions(+), 61 deletions(-) diffs (truncated from 322 to 300 lines): diff -r da4e0fd94239 -r aa3a7ed32634 win32/Lib/win32timezone.py --- a/win32/Lib/win32timezone.py Sun Apr 22 14:09:05 2012 -0400 +++ b/win32/Lib/win32timezone.py Wed Apr 25 21:20:23 2012 -0400 @@ -147,23 +147,18 @@ True This test helps ensure language support for unicode characters ->>> x = TIME_ZONE_INFORMATION(0, 'français') +>>> x = TIME_ZONE_INFORMATION(0, u'français') """ from __future__ import generators __author__ = 'Jason R. Coombs <ja...@ja...>' -__version__ = '$Revision$'[11:-2] -__sccauthor__ = '$Author$'[9:-2] -__date__ = '$Date$'[10:-2] -import os import _winreg import struct import datetime import win32api import re -import sys import operator import warnings from itertools import count @@ -196,7 +191,7 @@ setattr(self, name, def_val) def field_names(self): - return [f[0] for f in fields] + return [f[0] for f in self._fields_] def __eq__(self, other): if not hasattr(other, "_fields_"): @@ -373,8 +368,19 @@ TimeZoneInfo(<Time Zone Standard Name>, [<Fix Standard Time>]) If <Fix Standard Time> evaluates to True, daylight savings time is - calculated in the same - way as standard time. + calculated in the same way as standard time. + + >>> tzi = TimeZoneInfo('Pacific Standard Time') + >>> march31 = datetime.datetime(2000,3,31) + + We know that time zone definitions haven't changed from 2007 + to 2012, so regardless of whether dynamic info is available, + there should be consistent results for these years. + >>> subsequent_years = [march31.replace(year=year) + ... for year in range(2007, 2013)] + >>> offsets = set(tzi.utcoffset(year) for year in subsequent_years) + >>> len(offsets) + 1 """ # this key works for WinNT+, but not for the Win95 line. @@ -421,6 +427,40 @@ self.staticInfo = tzi def _LoadDynamicInfoFromKey(self, key): + """ + >>> tzi = TimeZoneInfo('Central Standard Time') + + Here's how the RangeMap is supposed to work: + >>> m = RangeMap(zip([2006,2007], 'BC'), + ... sort_params = dict(reverse=True), + ... key_match_comparator=operator.ge) + >>> m.get(2000, 'A') + 'A' + >>> m[2006] + 'B' + >>> m[2007] + 'C' + >>> m[2008] + 'C' + + >>> m[RangeMap.last_item] + 'B' + + >>> m.get(2008, m[RangeMap.last_item]) + 'C' + + + Now test the dynamic info (but fallback to our simple RangeMap + on systems that don't have dynamicInfo). + + >>> dinfo = getattr(tzi, 'dynamicInfo', m) + >>> 2007 in dinfo + True + >>> 2008 in dinfo + False + >>> dinfo[2007] == dinfo[2008] == dinfo[2012] + True + """ try: info = key.subkey('Dynamic DST') except WindowsError: @@ -431,7 +471,9 @@ values = map(TimeZoneDefinition, info.values()) # create a range mapping that searches by descending year and matches # if the target year is greater or equal. - self.dynamicInfo = RangeMap(zip(years, values), descending, operator.ge) + self.dynamicInfo = RangeMap(zip(years, values), + sort_params = dict(reverse=True), + key_match_comparator = operator.ge) def __repr__(self): result = '%s(%s' % (self.__class__.__name__, repr(self.timeZoneName)) @@ -452,12 +494,17 @@ return result def getWinInfo(self, targetYear): + """ + Return the most relevant "info" for this time zone + in the target year. + """ if not hasattr(self, 'dynamicInfo') or not self.dynamicInfo: return self.staticInfo # Find the greatest year entry in self.dynamicInfo which is for # a year greater than or equal to our targetYear. If not found, # default to the earliest year. - return self.dynamicInfo.get(targetYear, self.dynamicInfo[RangeItemLast()]) + return self.dynamicInfo.get(targetYear, + self.dynamicInfo[RangeMap.last_item]) def _getStandardBias(self, dt): winInfo = self.getWinInfo(dt.year) @@ -527,7 +574,7 @@ >>> now_UTC = datetime.datetime.utcnow() >>> (now_UTC - now_local) < datetime.timedelta(seconds = 5) Traceback (most recent call last): - ... + ... TypeError: can't subtract offset-naive and offset-aware datetimes >>> now_UTC = now_UTC.replace(tzinfo = TimeZoneInfo('GMT Standard Time', True)) @@ -601,7 +648,7 @@ """ Return the time zones sorted by some key. key must be a function that takes a TimeZoneInfo object and returns - a value suitable for sorting on. + a value suitable for sorting on. The key defaults to the bias (descending), as is done in Windows (see http://blogs.msdn.com/michkap/archive/2006/12/22/1350684.aspx) """ @@ -654,7 +701,7 @@ when the function is used.""" def newFunc(*args, **kwargs): warnings.warn("Call to deprecated function %s." % name, - category=DeprecationWarning) + category=DeprecationWarning) return func(*args, **kwargs) newFunc.__name__ = func.__name__ newFunc.__doc__ = func.__doc__ @@ -712,6 +759,7 @@ >>> try: unicode and None ... except NameError: unicode=str ... + >>> import sys >>> result = resolveMUITimeZone('@tzres.dll,-110') >>> expectedResultType = [type(None),unicode][sys.getwindowsversion() >= (6,)] >>> type(result) is expectedResultType @@ -727,94 +775,109 @@ try: handle = DLLCache[matcher.groupdict()['dllname']] result = win32api.LoadString(handle, int(matcher.groupdict()['index'])) - except win32api.error, e: + except win32api.error: result = None return result -# the following code implements a RangeMap and its support classes +# from jaraco.util.dictlib 5.3.1 +class RangeMap(dict): + """ + A dictionary-like object that uses the keys as bounds for a range. + Inclusion of the value for that range is determined by the + key_match_comparator, which defaults to less-than-or-equal. + A value is returned for a key if it is the first key that matches in + the sorted list of keys. -ascending = lambda a, b: b < a -def descending(a, b): - return not ascending(a, b) - -class RangeMap(dict): - """A dictionary-like object that uses the keys as bounds for a range. - Inclusion of the value for that range is determined by the - keyMatchComparator, which defaults to greater-than-or-equal. - A value is returned for a key if it is the first key that matches in - the sorted list of keys. By default, keys are sorted in ascending - order, but can be sorted in any other order using the keySortComparator. + One may supply keyword parameters to be passed to the sort function used + to sort keys (i.e. cmp [python 2 only], keys, reverse) as sort_params. Let's create a map that maps 1-3 -> 'a', 4-6 -> 'b' >>> r = RangeMap({3: 'a', 6: 'b'}) # boy, that was easy >>> r[1], r[2], r[3], r[4], r[5], r[6] ('a', 'a', 'a', 'b', 'b', 'b') + Even float values should work so long as the comparison operator + supports it. + >>> r[4.5] + 'b' + But you'll notice that the way rangemap is defined, it must be open-ended on one side. >>> r[0] 'a' >>> r[-1] 'a' - One can close the open-end of the RangeMap by using RangeValueUndefined - >>> r = RangeMap({0: RangeValueUndefined(), 3: 'a', 6: 'b'}) + One can close the open-end of the RangeMap by using undefined_value + >>> r = RangeMap({0: RangeMap.undefined_value, 3: 'a', 6: 'b'}) >>> r[0] Traceback (most recent call last): - ... + ... KeyError: 0 - One can get the first or last elements in the range by using RangeItem - >>> last_item = RangeItem(-1) + One can get the first or last elements in the range by using RangeMap.Item + >>> last_item = RangeMap.Item(-1) >>> r[last_item] 'b' - >>> r[RangeItemLast()] + .last_item is a shortcut for Item(-1) + >>> r[RangeMap.last_item] 'b' + Sometimes it's useful to find the bounds for a RangeMap >>> r.bounds() (0, 6) + RangeMap supports .get(key, default) + >>> r.get(0, 'not found') + 'not found' + + >>> r.get(7, 'not found') + 'not found' + """ - def __init__(self, source, keySortComparator = ascending, keyMatchComparator = operator.le): + def __init__(self, source, sort_params = {}, key_match_comparator = operator.le): dict.__init__(self, source) - self.sort = keySortComparator - self.match = keyMatchComparator - - def _get_sorted_keys(self): - sortedKeys = self.keys() - reverse = self.match != operator.le - sortedKeys.sort(reverse=reverse) - return sortedKeys + self.sort_params = sort_params + self.match = key_match_comparator def __getitem__(self, item): - sortedKeys = self._get_sorted_keys() - if isinstance(item, RangeItem): - result = self.__getitem__(sortedKeys[item]) + sorted_keys = sorted(self.keys(), **self.sort_params) + if isinstance(item, RangeMap.Item): + result = self.__getitem__(sorted_keys[item]) else: - key = self._find_first_match_(sortedKeys, item) + key = self._find_first_match_(sorted_keys, item) result = dict.__getitem__(self, key) - if isinstance(result, RangeValueUndefined): raise KeyError(key) + if result is RangeMap.undefined_value: + raise KeyError(key) return result + def get(self, key, default=None): + """ + Return the value for key if key is in the dictionary, else default. + If default is not given, it defaults to None, so that this method + never raises a KeyError. + """ + try: + return self[key] + except KeyError: + return default + def _find_first_match_(self, keys, item): is_match = lambda k: self.match(item, k) - # use of ifilter here would be more efficent - matches = [k for k in keys if is_match(k)] + matches = list(filter(is_match, keys)) if matches: return matches[0] raise KeyError(item) def bounds(self): - sortedKeys = self._get_sorted_keys() |