Skip to content

Commit 83be1e3

Browse files
authored
Add time function (enthought#129)
* Add Time function in pywintypes Add adapted tests from pywin32 in separate folder * run pywin32 tests on ci * Fix flake8 errors
1 parent 31bdaf6 commit 83be1e3

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

.github/workflows/test.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ jobs:
3030
- name: Test on ${{ matrix.python-version }} 64-bit
3131
run: |
3232
coverage run -p -m haas -v win32ctypes
33+
coverage run -p -m haas -v pywin32-tests
3334
pip install --upgrade cffi
3435
coverage run -p -m haas -v win32ctypes
36+
coverage run -p -m haas -v pywin32-tests
3537
env:
3638
PYTHONFAULTHANDLER: 1
3739
- name: Set up Python ${{ matrix.python-version }}
@@ -47,8 +49,10 @@ jobs:
4749
- name: test on ${{ matrix.python-version }} 32-bit
4850
run: |
4951
coverage run -p -m haas -v win32ctypes
52+
coverage run -p -m haas -v pywin32-tests
5053
pip install --upgrade cffi
5154
coverage run -p -m haas -v win32ctypes
55+
coverage run -p -m haas -v pywin32-tests
5256
env:
5357
PYTHONFAULTHANDLER: 1
5458
- name: Upload Coverage info

pywin32-tests/test_pywintypes.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#
2+
# Tests addapted from the test_pywintypes.py of pywin32 to test the
3+
# win32ctypes implementation
4+
#
5+
import os
6+
import sys
7+
import unittest
8+
import contextlib
9+
import tempfile
10+
import shutil
11+
import faulthandler
12+
import datetime
13+
import time
14+
15+
from win32ctypes import pywin32
16+
from win32ctypes.pywin32.pywintypes import error
17+
18+
class TestPyWINTypes(unittest.TestCase):
19+
20+
# the pywin32ctypes implementation
21+
module = pywin32.pywintypes
22+
23+
def testPyTimeFormat(self):
24+
struct_current = time.localtime()
25+
pytime_current = self.module.Time(struct_current)
26+
# try and test all the standard parts of the format
27+
# Note we used to include '%Z' testing, but that was pretty useless as
28+
# it always returned the local timezone.
29+
format_strings = "%a %A %b %B %c %d %H %I %j %m %M %p %S %U %w %W %x %X %y %Y"
30+
for fmt in format_strings.split():
31+
v1 = pytime_current.Format(fmt)
32+
v2 = time.strftime(fmt, struct_current)
33+
self.assertEqual(v1, v2, "format %s failed - %r != %r" % (fmt, v1, v2))
34+
35+
def testPyTimePrint(self):
36+
# This used to crash with an invalid, or too early time.
37+
# We don't really want to check that it does cause a ValueError
38+
# (as hopefully this wont be true forever). So either working, or
39+
# ValueError is OK.
40+
try:
41+
t = self.module.Time(-2)
42+
t.Format()
43+
except ValueError:
44+
return
45+
46+
def testTimeInDict(self):
47+
d = {}
48+
d["t1"] = self.module.Time(1)
49+
self.assertEqual(d["t1"], self.module.Time(1))
50+
51+
def testPyTimeCompare(self):
52+
t1 = self.module.Time(100)
53+
t1_2 = self.module.Time(100)
54+
t2 = self.module.Time(101)
55+
56+
self.assertEqual(t1, t1_2)
57+
self.assertTrue(t1 <= t1_2)
58+
self.assertTrue(t1_2 >= t1)
59+
60+
self.assertNotEqual(t1, t2)
61+
self.assertTrue(t1 < t2)
62+
self.assertTrue(t2 > t1)
63+
64+
def testPyTimeCompareOther(self):
65+
t1 = self.module.Time(100)
66+
t2 = None
67+
self.assertNotEqual(t1, t2)
68+
69+
def testTimeTuple(self):
70+
now = datetime.datetime.now() # has usec...
71+
# timetuple() lost usec - pt must be <=...
72+
pt = self.module.Time(now.timetuple())
73+
# *sob* - only if we have a datetime object can we compare like this.
74+
if isinstance(pt, datetime.datetime):
75+
self.assertTrue(pt <= now)
76+
77+
def testTimeTuplems(self):
78+
now = datetime.datetime.now() # has usec...
79+
tt = now.timetuple() + (now.microsecond // 1000,)
80+
pt = self.module.Time(tt)
81+
# we can't compare if using the old type, as it loses all sub-second res.
82+
if isinstance(pt, datetime.datetime):
83+
# but even with datetime, we lose sub-millisecond.
84+
expectedDelta = datetime.timedelta(milliseconds=1)
85+
self.assertTrue(-expectedDelta < (now - pt) < expectedDelta)
86+
87+
def testPyTimeFromTime(self):
88+
t1 = self.module.Time(time.time())
89+
self.assertTrue(self.module.Time(t1) is t1)

win32ctypes/pywin32/pywintypes.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
#
88
""" A module which supports common Windows types. """
99
import contextlib
10+
import collections
11+
import time
12+
from datetime import datetime as _datetime
1013

1114

1215
class error(Exception):
@@ -35,3 +38,30 @@ def pywin32error():
3538
if not hasattr(exception, 'function'):
3639
exception.function = 'unknown'
3740
raise error(exception.winerror, exception.function, exception.strerror)
41+
42+
43+
class datetime(_datetime):
44+
45+
def Format(self, fmt='%c'):
46+
return self.strftime(fmt)
47+
48+
49+
def Time(value):
50+
if isinstance(value, datetime):
51+
return value
52+
elif hasattr(value, 'timetuple'):
53+
timetuple = value.timetuple()
54+
return datetime.fromtimestamp(time.mktime(timetuple))
55+
elif isinstance(value, collections.abc.Sequence):
56+
time_value = time.mktime(value[:9])
57+
if len(value) == 10:
58+
time_value += value[9] / 1000.0
59+
return datetime.fromtimestamp(time_value)
60+
else:
61+
try:
62+
return datetime.fromtimestamp(value)
63+
except OSError as error:
64+
if error.errno == 22:
65+
raise ValueError(error.strerror)
66+
else:
67+
raise

0 commit comments

Comments
 (0)