Skip to content

Commit cb09b93

Browse files
committed
Added xtime_ns in stat result
- added fake stat_result to make this possible - fixes #196
1 parent b157fd2 commit cb09b93

5 files changed

+291
-139
lines changed

Diff for: CHANGES.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ The release versions are PyPi releases.
44
## Version 3.3 (as yet unreleased)
55

66
#### New Features
7+
* Added support for `ns` argument in `os.utime()` (Python >= 3.3) ([#192](../../issues/192)).
8+
* Added nanosecond time members in `os.stat_result` (Python >= 3.3) ([#196](../../issues/196)).
79

810
#### Infrastructure
911

1012
#### Fixes
1113

1214

13-
## Version 3.2
15+
## [Version 3.2](https://pypi.python.org/pypi/pyfakefs/3.2)
1416

1517
#### New Features
1618
* The `errors` argument is supported for `io.open()` and `os.open()`

Diff for: fake_filesystem_test.py

+74-32
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,21 @@
3232
from pyfakefs import fake_filesystem
3333

3434

35-
def _GetDummyTime(start_time, increment):
36-
def _DummyTime():
37-
_DummyTime._curr_time += increment
38-
return _DummyTime._curr_time
35+
class _DummyTime(object):
36+
"""Mock replacement for time.time. Increases returned time on access."""
3937

40-
_DummyTime._curr_time = start_time - increment # pylint: disable-msg=W0612
41-
return _DummyTime
38+
def __init__(self, curr_time, increment):
39+
self.curr_time = curr_time
40+
self.increment = increment
41+
self.started = False
42+
43+
def start(self):
44+
self.started = True
45+
46+
def __call__(self, *args, **kwargs):
47+
if self.started:
48+
self.curr_time += self.increment
49+
return self.curr_time
4250

4351

4452
class TestCase(unittest.TestCase):
@@ -67,7 +75,7 @@ def assertRaisesOSError(self, subtype, expression, *args, **kwargs):
6775
class FakeDirectoryUnitTest(TestCase):
6876
def setUp(self):
6977
self.orig_time = time.time
70-
time.time = _GetDummyTime(10, 1)
78+
time.time = _DummyTime(10, 1)
7179
self.fake_file = fake_filesystem.FakeFile('foobar', contents='dummy_file')
7280
self.fake_dir = fake_filesystem.FakeDirectory('somedir')
7381

@@ -676,7 +684,7 @@ def setUp(self):
676684
self.rwx = self.os.R_OK | self.os.W_OK | self.os.X_OK
677685
self.rw = self.os.R_OK | self.os.W_OK
678686
self.orig_time = time.time
679-
time.time = _GetDummyTime(200, 20)
687+
time.time = _DummyTime(200, 20)
680688

681689
def tearDown(self):
682690
time.time = self.orig_time
@@ -1717,6 +1725,8 @@ def testChmodStCtime(self):
17171725
file_path = 'some_file'
17181726
self.filesystem.CreateFile(file_path)
17191727
self.assertTrue(self.filesystem.Exists(file_path))
1728+
time.time.start()
1729+
17201730
st = self.os.stat(file_path)
17211731
self.assertEqual(200, st.st_ctime)
17221732
# tests
@@ -1728,6 +1738,8 @@ def testUtimeSetsCurrentTimeIfArgsIsNone(self):
17281738
# set up
17291739
path = '/some_file'
17301740
self._CreateTestFile(path)
1741+
time.time.start()
1742+
17311743
st = self.os.stat(path)
17321744
# 200 is the current time established in setUp().
17331745
self.assertEqual(200, st.st_atime)
@@ -1736,39 +1748,51 @@ def testUtimeSetsCurrentTimeIfArgsIsNone(self):
17361748
self.os.utime(path, None)
17371749
st = self.os.stat(path)
17381750
self.assertEqual(220, st.st_atime)
1739-
self.assertEqual(240, st.st_mtime)
1751+
self.assertEqual(220, st.st_mtime)
17401752

17411753
def testUtimeSetsCurrentTimeIfArgsIsNoneWithFloats(self):
17421754
# set up
17431755
# we set os.stat_float_times() to False, so atime/ctime/mtime
17441756
# are converted as ints (seconds since epoch)
1745-
time.time = _GetDummyTime(200.9123, 20)
1757+
time.time = _DummyTime(200.9123, 20)
17461758
path = '/some_file'
17471759
fake_filesystem.FakeOsModule.stat_float_times(False)
17481760
self._CreateTestFile(path)
1761+
time.time.start()
1762+
17491763
st = self.os.stat(path)
17501764
# 200 is the current time established above (if converted to int).
17511765
self.assertEqual(200, st.st_atime)
17521766
self.assertTrue(isinstance(st.st_atime, int))
17531767
self.assertEqual(200, st.st_mtime)
17541768
self.assertTrue(isinstance(st.st_mtime, int))
1769+
1770+
if sys.version_info >= (3, 3):
1771+
self.assertEqual(200912300000, st.st_atime_ns)
1772+
self.assertEqual(200912300000, st.st_mtime_ns)
1773+
1774+
self.assertEqual(200, st.st_mtime)
17551775
# actual tests
17561776
self.os.utime(path, None)
17571777
st = self.os.stat(path)
17581778
self.assertEqual(220, st.st_atime)
17591779
self.assertTrue(isinstance(st.st_atime, int))
1760-
self.assertEqual(240, st.st_mtime)
1780+
self.assertEqual(220, st.st_mtime)
17611781
self.assertTrue(isinstance(st.st_mtime, int))
1782+
if sys.version_info >= (3, 3):
1783+
self.assertEqual(220912300000, st.st_atime_ns)
1784+
self.assertEqual(220912300000, st.st_mtime_ns)
17621785

17631786
def testUtimeSetsCurrentTimeIfArgsIsNoneWithFloatsNSec(self):
17641787
self.filesystem = fake_filesystem.FakeFilesystem(path_separator='/')
17651788
self.os = fake_filesystem.FakeOsModule(self.filesystem)
1766-
self.assertTrue(not self.os.stat_float_times())
1789+
fake_filesystem.FakeOsModule.stat_float_times(False)
17671790

1768-
time.time = _GetDummyTime(200.9123, 20)
1791+
time.time = _DummyTime(200.9123, 20)
17691792
path = '/some_file'
17701793
test_file = self._CreateTestFile(path)
17711794

1795+
time.time.start()
17721796
st = self.os.stat(path)
17731797
self.assertEqual(200, st.st_ctime)
17741798
self.assertEqual(200, test_file.st_ctime)
@@ -1796,7 +1820,7 @@ def testUtimeSetsCurrentTimeIfArgsIsNoneWithFloatsNSec(self):
17961820
self.os.utime(path, None)
17971821
st = self.os.stat(path)
17981822
self.assertEqual(220.9123, st.st_atime)
1799-
self.assertEqual(240.9123, st.st_mtime)
1823+
self.assertEqual(220.9123, st.st_mtime)
18001824

18011825
def testUtimeSetsSpecifiedTime(self):
18021826
# set up
@@ -1865,6 +1889,8 @@ def testUtimeSetsSpecifiedTimeInNs(self):
18651889
# set up
18661890
path = '/some_file'
18671891
self._CreateTestFile(path)
1892+
time.time.start()
1893+
18681894
st = self.os.stat(path)
18691895
# actual tests
18701896
self.os.utime(path, ns=(200000000, 400000000))
@@ -2358,6 +2384,12 @@ def testStat(self):
23582384
self.assertEqual(self.filesystem.ResolveObject('/linked/plugh/dir').st_mtime,
23592385
self.dir_entries[2].stat().st_mtime)
23602386

2387+
def testIndexAccessToStatTimesReturnsInt(self):
2388+
self.assertEqual(self.os.stat('/xyzzy/plugh/dir')[stat.ST_CTIME],
2389+
int(self.dir_entries[0].stat().st_ctime))
2390+
self.assertEqual(self.os.stat('/linked/plugh/dir')[stat.ST_MTIME],
2391+
int(self.dir_entries[2].stat().st_mtime))
2392+
23612393
def testStatInoDevPosix(self):
23622394
self.filesystem.is_windows_fs = False
23632395
file_obj = self.filesystem.ResolveObject('/linked/plugh/file')
@@ -2522,7 +2554,7 @@ def testCreateTopLevelDirectory(self):
25222554
class FakePathModuleTest(TestCase):
25232555
def setUp(self):
25242556
self.orig_time = time.time
2525-
time.time = _GetDummyTime(10, 1)
2557+
time.time = _DummyTime(10, 1)
25262558
self.filesystem = fake_filesystem.FakeFilesystem(path_separator='!')
25272559
self.os = fake_filesystem.FakeOsModule(self.filesystem)
25282560
self.path = self.os.path
@@ -2726,9 +2758,8 @@ def testIsfile(self):
27262758

27272759
def testGetMtime(self):
27282760
test_file = self.filesystem.CreateFile('foo!bar1.txt')
2729-
# The root directory ('', effectively '!') is created at time 10,
2730-
# the parent directory ('foo') at time 11, and the file at time 12.
2731-
self.assertEqual(12, test_file.st_mtime)
2761+
time.time.start()
2762+
self.assertEqual(10, test_file.st_mtime)
27322763
test_file.SetMTime(24)
27332764
self.assertEqual(24, self.path.getmtime('foo!bar1.txt'))
27342765

@@ -2897,7 +2928,7 @@ def setUp(self):
28972928
self.open = self.file
28982929
self.os = fake_filesystem.FakeOsModule(self.filesystem)
28992930
self.orig_time = time.time
2900-
time.time = _GetDummyTime(100, 10)
2931+
time.time = _DummyTime(100, 10)
29012932

29022933
def tearDown(self):
29032934
time.time = self.orig_time
@@ -3276,41 +3307,52 @@ def testOpenStCtime(self):
32763307
self.assertFalse(self.filesystem.Exists(file_path))
32773308
# tests
32783309
fake_file = self.file(file_path, 'w')
3310+
time.time.start()
32793311
st = self.os.stat(file_path)
3280-
self.assertEqual(100, st.st_ctime, st.st_mtime)
3312+
self.assertEqual(100, st.st_ctime)
3313+
self.assertEqual(100, st.st_mtime)
32813314
fake_file.close()
32823315
st = self.os.stat(file_path)
3283-
self.assertEqual(110, st.st_ctime, st.st_mtime)
3316+
self.assertEqual(110, st.st_ctime)
3317+
self.assertEqual(110, st.st_mtime)
32843318

32853319
fake_file = self.file(file_path, 'w')
32863320
st = self.os.stat(file_path)
32873321
# truncating the file cause an additional stat update
3288-
self.assertEqual(120, st.st_ctime, st.st_mtime)
3322+
self.assertEqual(120, st.st_ctime)
3323+
self.assertEqual(120, st.st_mtime)
32893324
fake_file.close()
32903325
st = self.os.stat(file_path)
3291-
self.assertEqual(130, st.st_ctime, st.st_mtime)
3326+
self.assertEqual(130, st.st_ctime)
3327+
self.assertEqual(130, st.st_mtime)
32923328

32933329
fake_file = self.file(file_path, 'w+')
32943330
st = self.os.stat(file_path)
3295-
self.assertEqual(140, st.st_ctime, st.st_mtime)
3331+
self.assertEqual(140, st.st_ctime)
3332+
self.assertEqual(140, st.st_mtime)
32963333
fake_file.close()
32973334
st = self.os.stat(file_path)
3298-
self.assertEqual(150, st.st_ctime, st.st_mtime)
3335+
self.assertEqual(150, st.st_ctime)
3336+
self.assertEqual(150, st.st_mtime)
32993337

33003338
fake_file = self.file(file_path, 'a')
33013339
st = self.os.stat(file_path)
33023340
# not updating m_time or c_time here, since no truncating.
3303-
self.assertEqual(150, st.st_ctime, st.st_mtime)
3341+
self.assertEqual(150, st.st_ctime)
3342+
self.assertEqual(150, st.st_mtime)
33043343
fake_file.close()
33053344
st = self.os.stat(file_path)
3306-
self.assertEqual(160, st.st_ctime, st.st_mtime)
3345+
self.assertEqual(160, st.st_ctime)
3346+
self.assertEqual(160, st.st_mtime)
33073347

33083348
fake_file = self.file(file_path, 'r')
33093349
st = self.os.stat(file_path)
3310-
self.assertEqual(160, st.st_ctime, st.st_mtime)
3350+
self.assertEqual(160, st.st_ctime)
3351+
self.assertEqual(160, st.st_mtime)
33113352
fake_file.close()
33123353
st = self.os.stat(file_path)
3313-
self.assertEqual(160, st.st_ctime, st.st_mtime)
3354+
self.assertEqual(160, st.st_ctime)
3355+
self.assertEqual(160, st.st_mtime)
33143356

33153357
def _CreateWithPermission(self, file_path, perm_bits):
33163358
self.filesystem.CreateFile(file_path)
@@ -4589,9 +4631,9 @@ def checkFakeFileStat(self, fake_file, real_file_path):
45894631
real_stat = os.stat(real_file_path)
45904632
self.assertIsNone(fake_file._byte_contents)
45914633
self.assertEqual(fake_file.st_size, real_stat.st_size)
4592-
self.assertEqual(fake_file.st_ctime, real_stat.st_ctime)
4593-
self.assertEqual(fake_file.st_atime, real_stat.st_atime)
4594-
self.assertEqual(fake_file.st_mtime, real_stat.st_mtime)
4634+
self.assertAlmostEqual(fake_file.st_ctime, real_stat.st_ctime, places=5)
4635+
self.assertAlmostEqual(fake_file.st_atime, real_stat.st_atime, places=5)
4636+
self.assertAlmostEqual(fake_file.st_mtime, real_stat.st_mtime, places=5)
45954637
self.assertEqual(fake_file.st_uid, real_stat.st_uid)
45964638
self.assertEqual(fake_file.st_gid, real_stat.st_gid)
45974639

Diff for: fake_filesystem_unittest_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,10 @@ def testCopyRealFile(self):
216216

217217
self.assertEqual(oct(fake_file.st_mode), oct(self.real_stat.st_mode))
218218
self.assertEqual(fake_file.st_size, self.real_stat.st_size)
219-
self.assertEqual(fake_file.st_ctime, self.real_stat.st_ctime)
219+
self.assertAlmostEqual(fake_file.st_ctime, self.real_stat.st_ctime, places=5)
220220
self.assertGreaterEqual(fake_file.st_atime, self.real_stat.st_atime)
221221
self.assertLess(fake_file.st_atime, self.real_stat.st_atime + 10)
222-
self.assertEqual(fake_file.st_mtime, self.real_stat.st_mtime)
222+
self.assertAlmostEqual(fake_file.st_mtime, self.real_stat.st_mtime, places=5)
223223
self.assertEqual(fake_file.st_uid, self.real_stat.st_uid)
224224
self.assertEqual(fake_file.st_gid, self.real_stat.st_gid)
225225

Diff for: fake_pathlib_test.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,22 @@ def test_stat(self):
235235
file_object = self.filesystem.ResolveObject('/home/jane/test.py')
236236

237237
stat_result = self.path('/test.py').stat()
238-
self.assertFalse(stat_result[stat.ST_MODE] & stat.S_IFDIR)
239-
self.assertTrue(stat_result[stat.ST_MODE] & stat.S_IFREG)
240-
self.assertEqual(stat_result[stat.ST_INO], file_object.st_ino)
241-
self.assertEqual(stat_result[stat.ST_SIZE], 100)
242-
self.assertEqual(stat_result[stat.ST_MTIME], file_object.st_mtime)
238+
self.assertFalse(stat_result.st_mode & stat.S_IFDIR)
239+
self.assertTrue(stat_result.st_mode & stat.S_IFREG)
240+
self.assertEqual(stat_result.st_ino, file_object.st_ino)
241+
self.assertEqual(stat_result.st_size, 100)
242+
self.assertEqual(stat_result.st_mtime, file_object.st_mtime)
243+
self.assertEqual(stat_result[stat.ST_MTIME], int(file_object.st_mtime))
243244

244245
def test_lstat(self):
245246
link_object = self.filesystem.LResolveObject('/test.py')
246247

247248
stat_result = self.path('/test.py').lstat()
248-
self.assertTrue(stat_result[stat.ST_MODE] & stat.S_IFREG)
249-
self.assertTrue(stat_result[stat.ST_MODE] & stat.S_IFLNK)
250-
self.assertEqual(stat_result[stat.ST_INO], link_object.st_ino)
251-
self.assertEqual(stat_result[stat.ST_SIZE], len('/home/jane/test.py'))
252-
self.assertEqual(stat_result[stat.ST_MTIME], link_object.st_mtime)
249+
self.assertTrue(stat_result.st_mode & stat.S_IFREG)
250+
self.assertTrue(stat_result.st_mode & stat.S_IFLNK)
251+
self.assertEqual(stat_result.st_ino, link_object.st_ino)
252+
self.assertEqual(stat_result.st_size, len('/home/jane/test.py'))
253+
self.assertEqual(stat_result.st_mtime, link_object.st_mtime)
253254

254255
def test_chmod(self):
255256
file_object = self.filesystem.ResolveObject('/home/jane/test.py')

0 commit comments

Comments
 (0)