Skip to content

Commit

Permalink
Fail sooner on creating invalid TimeZoneInfo (#2338)
Browse files Browse the repository at this point in the history
  • Loading branch information
Avasam authored Oct 13, 2024
1 parent c670569 commit 79ac904
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
3 changes: 2 additions & 1 deletion CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ https://mhammond.github.io/pywin32_installers.html.
Coming in build 309, as yet unreleased
--------------------------------------

* Remove temporary `win32com.server.policy` reexports hack (#2344, @Avasam)
* Fail sooner on invalid `win32timezone.TimeZoneInfo` creation (#2338, @Avasam)
* Removed temporary `win32com.server.policy` reexports hack (#2344, @Avasam)
Import `DispatcherWin32trace` and `DispatcherTrace` from `win32com.server.dispatcher` instead.
* Fixed `win32timezone.TimeZoneInfo` initialization from a `[DYNAMIC_]TIME_ZONE_INFORMATION` (#2339, @Avasam)
* Added runtime deprecation warning of `win2kras`, use `win32ras` instead (#2356, @Avasam)
Expand Down
45 changes: 38 additions & 7 deletions win32/Lib/win32timezone.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# -*- coding: UTF-8 -*-
from __future__ import annotations

"""
win32timezone:
Expand Down Expand Up @@ -33,7 +32,7 @@
(note that the result of utcoffset call will be different based on when now was
generated, unless standard time is always used)
>>> now = datetime.datetime.now(TimeZoneInfo('Mountain Standard Time', True))
>>> now = datetime.datetime.now(win32timezone.TimeZoneInfo('Mountain Standard Time', True))
>>> now.utcoffset()
datetime.timedelta(days=-1, seconds=61200)
Expand Down Expand Up @@ -77,10 +76,15 @@
It's possible to construct a TimeZoneInfo from a TimeZoneDescription
including the currently-defined zone.
>>> tz = win32timezone.TimeZoneInfo(TimeZoneDefinition.current())
>>> code, info = win32timezone.TimeZoneDefinition.current()
>>> tz = win32timezone.TimeZoneInfo(info, not code)
>>> tz == pickle.loads(pickle.dumps(tz))
True
Although it's easier to use TimeZoneInfo.local() to get the local info
>>> tz == TimeZoneInfo.local()
True
>>> aest = win32timezone.TimeZoneInfo('AUS Eastern Standard Time')
>>> est = win32timezone.TimeZoneInfo('E. Australia Standard Time')
>>> dt = datetime.datetime(2006, 11, 11, 1, 0, 0, tzinfo = aest)
Expand Down Expand Up @@ -233,6 +237,8 @@
"""

from __future__ import annotations

import datetime
import logging
import operator
Expand Down Expand Up @@ -504,19 +510,41 @@ class TimeZoneInfo(datetime.tzinfo):
>>> offsets = set(tzi.utcoffset(year) for year in subsequent_years)
>>> len(offsets)
1
Cannot create a `TimeZoneInfo` with an invalid name.
>>> TimeZoneInfo('Does not exist')
Traceback (most recent call last):
...
ValueError: Timezone Name 'Does not exist' not found
>>> TimeZoneInfo(None)
Traceback (most recent call last):
...
ValueError: subkey name cannot be empty
>>> TimeZoneInfo("")
Traceback (most recent call last):
...
ValueError: subkey name cannot be empty
"""

# this key works for WinNT+, but not for the Win95 line.
tzRegKey = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"

def __init__(self, param=None, fix_standard_time=False):
def __init__(
self,
param: str | TimeZoneDefinition,
fix_standard_time: bool = False,
) -> None:
if isinstance(param, TimeZoneDefinition):
self._LoadFromTZI(param)
if isinstance(param, str):
else:
self.timeZoneName = param
self._LoadInfoFromKey()
self.fixedStandardTime = fix_standard_time

# For tzinfo pickle support
def __getinitargs__(self) -> tuple[TimeZoneDefinition, bool]:
return (self.staticInfo, self.fixedStandardTime)

def _FindTimeZoneKey(self):
"""Find the registry key for the time zone name (self.timeZoneName)."""
# for multi-language compatability, match the time zone name in the
Expand All @@ -528,8 +556,9 @@ def _FindTimeZoneKey(self):
key = _RegKeyDict.open(winreg.HKEY_LOCAL_MACHINE, self.tzRegKey)
try:
result = key.subkey(timeZoneName)
except Exception:
raise ValueError("Timezone Name %s not found." % timeZoneName)
except FileNotFoundError:
# Don't catch ValueError, keep the original error message
raise ValueError(f"Timezone Name {timeZoneName!r} not found")
return result

def _LoadInfoFromKey(self):
Expand Down Expand Up @@ -821,6 +850,8 @@ def open(cls, *args, **kargs):
return _RegKeyDict(winreg.OpenKeyEx(*args, **kargs))

def subkey(self, name):
if not name:
raise ValueError("subkey name cannot be empty")
return _RegKeyDict(winreg.OpenKeyEx(self.key, name))

def __load_values(self):
Expand Down

0 comments on commit 79ac904

Please sign in to comment.