[Python-checkins] cpython: Issue #15745: Rewrite os.utime() tests in test_os
victor.stinner
python-checkins at python.org
Fri Jun 12 17:48:36 CEST 2015
https://hg.python.org/cpython/rev/4335d898be59
changeset: 96581:4335d898be59
user: Victor Stinner <victor.stinner at gmail.com>
date: Fri Jun 12 17:26:23 2015 +0200
summary:
Issue #15745: Rewrite os.utime() tests in test_os
* Don't use the timestamp of an existing file anymore, only use fixed
timestamp
* Enhance the code checking the resolution of the filesystem timestamps.
* Check timestamps with a resolution of 1 microsecond instead of 1 millisecond
* When os.utime() uses the current system clock, tolerate a delta of 20 ms.
Before some os.utime() tolerated a different of 10 seconds.
* Merge duplicated tests and simplify the code
files:
Lib/test/test_os.py | 439 ++++++++++++++++---------------
1 files changed, 223 insertions(+), 216 deletions(-)
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -2,33 +2,34 @@
# does add tests for a few functions which have been determined to be more
# portable than they had been thought to be.
+import asynchat
+import asyncore
+import codecs
+import contextlib
+import decimal
+import errno
+import fractions
+import getpass
+import itertools
+import locale
+import math
+import mmap
import os
-import errno
-import getpass
-import unittest
-import warnings
-import sys
-import signal
-import subprocess
-import time
-import shutil
-from test import support
-import contextlib
-import mmap
+import pickle
import platform
import re
+import shutil
+import signal
+import socket
+import stat
+import subprocess
+import sys
+import sysconfig
+import time
+import unittest
import uuid
-import asyncore
-import asynchat
-import socket
-import itertools
-import stat
-import locale
-import codecs
-import decimal
-import fractions
-import pickle
-import sysconfig
+import warnings
+from test import support
try:
import threading
except ImportError:
@@ -70,16 +71,6 @@
if hasattr(os, 'geteuid'):
root_in_posix = (os.geteuid() == 0)
-with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
- os.stat_float_times(True)
-st = os.stat(__file__)
-stat_supports_subsecond = (
- # check if float and int timestamps are different
- (st.st_atime != st[7])
- or (st.st_mtime != st[8])
- or (st.st_ctime != st[9]))
-
# Detect whether we're on a Linux system that uses the (now outdated
# and unmaintained) linuxthreads threading library. There's an issue
# when combining linuxthreads with a failed execv call: see
@@ -223,15 +214,10 @@
# Test attributes on return values from os.*stat* family.
class StatAttributeTests(unittest.TestCase):
def setUp(self):
- os.mkdir(support.TESTFN)
- self.fname = os.path.join(support.TESTFN, "f1")
- f = open(self.fname, 'wb')
- f.write(b"ABC")
- f.close()
-
- def tearDown(self):
- os.unlink(self.fname)
- os.rmdir(support.TESTFN)
+ self.fname = support.TESTFN
+ self.addCleanup(support.unlink, self.fname)
+ with open(self.fname, 'wb') as fp:
+ fp.write(b"ABC")
@unittest.skipUnless(hasattr(os, 'stat'), 'test needs os.stat()')
def check_stat_attributes(self, fname):
@@ -383,179 +369,6 @@
unpickled = pickle.loads(p)
self.assertEqual(result, unpickled)
- def test_utime_dir(self):
- delta = 1000000
- st = os.stat(support.TESTFN)
- # round to int, because some systems may support sub-second
- # time stamps in stat, but not in utime.
- os.utime(support.TESTFN, (st.st_atime, int(st.st_mtime-delta)))
- st2 = os.stat(support.TESTFN)
- self.assertEqual(st2.st_mtime, int(st.st_mtime-delta))
-
- def _test_utime(self, filename, attr, utime, delta):
- # Issue #13327 removed the requirement to pass None as the
- # second argument. Check that the previous methods of passing
- # a time tuple or None work in addition to no argument.
- st0 = os.stat(filename)
- # Doesn't set anything new, but sets the time tuple way
- utime(filename, (attr(st0, "st_atime"), attr(st0, "st_mtime")))
- # Setting the time to the time you just read, then reading again,
- # should always return exactly the same times.
- st1 = os.stat(filename)
- self.assertEqual(attr(st0, "st_mtime"), attr(st1, "st_mtime"))
- self.assertEqual(attr(st0, "st_atime"), attr(st1, "st_atime"))
- # Set to the current time in the old explicit way.
- os.utime(filename, None)
- st2 = os.stat(support.TESTFN)
- # Set to the current time in the new way
- os.utime(filename)
- st3 = os.stat(filename)
- self.assertAlmostEqual(attr(st2, "st_mtime"), attr(st3, "st_mtime"), delta=delta)
-
- def test_utime(self):
- def utime(file, times):
- return os.utime(file, times)
- self._test_utime(self.fname, getattr, utime, 10)
- self._test_utime(support.TESTFN, getattr, utime, 10)
-
-
- def _test_utime_ns(self, set_times_ns, test_dir=True):
- def getattr_ns(o, attr):
- return getattr(o, attr + "_ns")
- ten_s = 10 * 1000 * 1000 * 1000
- self._test_utime(self.fname, getattr_ns, set_times_ns, ten_s)
- if test_dir:
- self._test_utime(support.TESTFN, getattr_ns, set_times_ns, ten_s)
-
- def test_utime_ns(self):
- def utime_ns(file, times):
- return os.utime(file, ns=times)
- self._test_utime_ns(utime_ns)
-
- requires_utime_dir_fd = unittest.skipUnless(
- os.utime in os.supports_dir_fd,
- "dir_fd support for utime required for this test.")
- requires_utime_fd = unittest.skipUnless(
- os.utime in os.supports_fd,
- "fd support for utime required for this test.")
- requires_utime_nofollow_symlinks = unittest.skipUnless(
- os.utime in os.supports_follow_symlinks,
- "follow_symlinks support for utime required for this test.")
-
- @requires_utime_nofollow_symlinks
- def test_lutimes_ns(self):
- def lutimes_ns(file, times):
- return os.utime(file, ns=times, follow_symlinks=False)
- self._test_utime_ns(lutimes_ns)
-
- @requires_utime_fd
- def test_futimes_ns(self):
- def futimes_ns(file, times):
- with open(file, "wb") as f:
- os.utime(f.fileno(), ns=times)
- self._test_utime_ns(futimes_ns, test_dir=False)
-
- def _utime_invalid_arguments(self, name, arg):
- with self.assertRaises(ValueError):
- getattr(os, name)(arg, (5, 5), ns=(5, 5))
-
- def test_utime_invalid_arguments(self):
- self._utime_invalid_arguments('utime', self.fname)
-
-
- @unittest.skipUnless(stat_supports_subsecond,
- "os.stat() doesn't has a subsecond resolution")
- def _test_utime_subsecond(self, set_time_func):
- asec, amsec = 1, 901
- atime = asec + amsec * 1e-3
- msec, mmsec = 2, 901
- mtime = msec + mmsec * 1e-3
- filename = self.fname
- os.utime(filename, (0, 0))
- set_time_func(filename, atime, mtime)
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
- os.stat_float_times(True)
- st = os.stat(filename)
- self.assertAlmostEqual(st.st_atime, atime, places=3)
- self.assertAlmostEqual(st.st_mtime, mtime, places=3)
-
- def test_utime_subsecond(self):
- def set_time(filename, atime, mtime):
- os.utime(filename, (atime, mtime))
- self._test_utime_subsecond(set_time)
-
- @requires_utime_fd
- def test_futimes_subsecond(self):
- def set_time(filename, atime, mtime):
- with open(filename, "wb") as f:
- os.utime(f.fileno(), times=(atime, mtime))
- self._test_utime_subsecond(set_time)
-
- @requires_utime_fd
- def test_futimens_subsecond(self):
- def set_time(filename, atime, mtime):
- with open(filename, "wb") as f:
- os.utime(f.fileno(), times=(atime, mtime))
- self._test_utime_subsecond(set_time)
-
- @requires_utime_dir_fd
- def test_futimesat_subsecond(self):
- def set_time(filename, atime, mtime):
- dirname = os.path.dirname(filename)
- dirfd = os.open(dirname, os.O_RDONLY)
- try:
- os.utime(os.path.basename(filename), dir_fd=dirfd,
- times=(atime, mtime))
- finally:
- os.close(dirfd)
- self._test_utime_subsecond(set_time)
-
- @requires_utime_nofollow_symlinks
- def test_lutimes_subsecond(self):
- def set_time(filename, atime, mtime):
- os.utime(filename, (atime, mtime), follow_symlinks=False)
- self._test_utime_subsecond(set_time)
-
- @requires_utime_dir_fd
- def test_utimensat_subsecond(self):
- def set_time(filename, atime, mtime):
- dirname = os.path.dirname(filename)
- dirfd = os.open(dirname, os.O_RDONLY)
- try:
- os.utime(os.path.basename(filename), dir_fd=dirfd,
- times=(atime, mtime))
- finally:
- os.close(dirfd)
- self._test_utime_subsecond(set_time)
-
- # Restrict tests to Win32, since there is no guarantee other
- # systems support centiseconds
- def get_file_system(path):
- if sys.platform == 'win32':
- root = os.path.splitdrive(os.path.abspath(path))[0] + '\\'
- import ctypes
- kernel32 = ctypes.windll.kernel32
- buf = ctypes.create_unicode_buffer("", 100)
- if kernel32.GetVolumeInformationW(root, None, 0, None, None, None, buf, len(buf)):
- return buf.value
-
- @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
- @unittest.skipUnless(get_file_system(support.TESTFN) == "NTFS",
- "requires NTFS")
- def test_1565150(self):
- t1 = 1159195039.25
- os.utime(self.fname, (t1, t1))
- self.assertEqual(os.stat(self.fname).st_mtime, t1)
-
- @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
- @unittest.skipUnless(get_file_system(support.TESTFN) == "NTFS",
- "requires NTFS")
- def test_large_time(self):
- t1 = 5000000000 # some day in 2128
- os.utime(self.fname, (t1, t1))
- self.assertEqual(os.stat(self.fname).st_mtime, t1)
-
@unittest.skipUnless(sys.platform == "win32", "Win32 specific tests")
def test_1686475(self):
# Verify that an open file can be stat'ed
@@ -596,12 +409,206 @@
0)
# test directory st_file_attributes (FILE_ATTRIBUTE_DIRECTORY set)
- result = os.stat(support.TESTFN)
+ dirname = support.TESTFN + "dir"
+ os.mkdir(dirname)
+ self.addCleanup(os.rmdir, dirname)
+
+ result = os.stat(dirname)
self.check_file_attributes(result)
self.assertEqual(
result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
stat.FILE_ATTRIBUTE_DIRECTORY)
+
+class UtimeTests(unittest.TestCase):
+ def setUp(self):
+ self.dirname = support.TESTFN
+ self.fname = os.path.join(self.dirname, "f1")
+
+ self.addCleanup(support.rmtree, self.dirname)
+ os.mkdir(self.dirname)
+ with open(self.fname, 'wb') as fp:
+ fp.write(b"ABC")
+
+ # ensure that st_atime and st_mtime are float
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore", DeprecationWarning)
+
+ old_state = os.stat_float_times(-1)
+ self.addCleanup(os.stat_float_times, old_state)
+
+ os.stat_float_times(True)
+
+ def support_subsecond(self, filename):
+ # Heuristic to check if the filesystem supports timestamp with
+ # subsecond resolution: check if float and int timestamps are different
+ st = os.stat(filename)
+ return ((st.st_atime != st[7])
+ or (st.st_mtime != st[8])
+ or (st.st_ctime != st[9]))
+
+ def _test_utime(self, set_time, filename=None):
+ if not filename:
+ filename = self.fname
+
+ support_subsecond = self.support_subsecond(filename)
+ if support_subsecond:
+ # Timestamp with a resolution of 1 microsecond (10^-6).
+ #
+ # The resolution of the C internal function used by os.utime()
+ # depends on the platform: 1 sec, 1 us, 1 ns. Writing a portable
+ # test with a resolution of 1 ns requires more work:
+ # see the issue #15745.
+ atime_ns = 1002003000 # 1.002003 seconds
+ mtime_ns = 4005006000 # 4.005006 seconds
+ else:
+ # use a resolution of 1 second
+ atime_ns = 5 * 10**9
+ mtime_ns = 8 * 10**9
+
+ set_time(filename, (atime_ns, mtime_ns))
+ st = os.stat(filename)
+
+ if support_subsecond:
+ self.assertAlmostEqual(st.st_atime, atime_ns * 1e-9, delta=1e-6)
+ self.assertAlmostEqual(st.st_mtime, mtime_ns * 1e-9, delta=1e-6)
+ else:
+ self.assertEqual(st.st_atime, atime_ns * 1e-9)
+ self.assertEqual(st.st_mtime, mtime_ns * 1e-9)
+ self.assertEqual(st.st_atime_ns, atime_ns)
+ self.assertEqual(st.st_mtime_ns, mtime_ns)
+
+ def test_utime(self):
+ def set_time(filename, ns):
+ # test the ns keyword parameter
+ os.utime(filename, ns=ns)
+ self._test_utime(set_time)
+
+ @staticmethod
+ def ns_to_sec(ns):
+ # Convert a number of nanosecond (int) to a number of seconds (float).
+ # Round towards infinity by adding 0.5 nanosecond to avoid rounding
+ # issue, os.utime() rounds towards minus infinity.
+ return (ns * 1e-9) + 0.5e-9
+
+ def test_utime_by_indexed(self):
+ # pass times as floating point seconds as the second indexed parameter
+ def set_time(filename, ns):
+ atime_ns, mtime_ns = ns
+ atime = self.ns_to_sec(atime_ns)
+ mtime = self.ns_to_sec(mtime_ns)
+ # test utimensat(timespec), utimes(timeval), utime(utimbuf)
+ # or utime(time_t)
+ os.utime(filename, (atime, mtime))
+ self._test_utime(set_time)
+
+ def test_utime_by_times(self):
+ def set_time(filename, ns):
+ atime_ns, mtime_ns = ns
+ atime = self.ns_to_sec(atime_ns)
+ mtime = self.ns_to_sec(mtime_ns)
+ # test the times keyword parameter
+ os.utime(filename, times=(atime, mtime))
+ self._test_utime(set_time)
+
+ @unittest.skipUnless(os.utime in os.supports_follow_symlinks,
+ "follow_symlinks support for utime required "
+ "for this test.")
+ def test_utime_nofollow_symlinks(self):
+ def set_time(filename, ns):
+ # use follow_symlinks=False to test utimensat(timespec)
+ # or lutimes(timeval)
+ os.utime(filename, ns=ns, follow_symlinks=False)
+ self._test_utime(set_time)
+
+ @unittest.skipUnless(os.utime in os.supports_fd,
+ "fd support for utime required for this test.")
+ def test_utime_fd(self):
+ def set_time(filename, ns):
+ with open(filename, 'wb') as fp:
+ # use a file descriptor to test futimens(timespec)
+ # or futimes(timeval)
+ os.utime(fp.fileno(), ns=ns)
+ self._test_utime(set_time)
+
+ @unittest.skipUnless(os.utime in os.supports_dir_fd,
+ "dir_fd support for utime required for this test.")
+ def test_utime_dir_fd(self):
+ def set_time(filename, ns):
+ dirname, name = os.path.split(filename)
+ dirfd = os.open(dirname, os.O_RDONLY)
+ try:
+ # pass dir_fd to test utimensat(timespec) or futimesat(timeval)
+ os.utime(name, dir_fd=dirfd, ns=ns)
+ finally:
+ os.close(dirfd)
+ self._test_utime(set_time)
+
+ def test_utime_directory(self):
+ def set_time(filename, ns):
+ # test calling os.utime() on a directory
+ os.utime(filename, ns=ns)
+ self._test_utime(set_time, filename=self.dirname)
+
+ def _test_utime_current(self, set_time):
+ # Get the system clock
+ current = time.time()
+
+ # Call os.utime() to set the timestamp to the current system clock
+ set_time(self.fname)
+
+ if not self.support_subsecond(self.fname):
+ delta = 1.0
+ else:
+ # On Windows, the usual resolution of time.time() is 15.6 ms
+ delta = 0.020
+ st = os.stat(self.fname)
+ msg = ("st_time=%r, current=%r, dt=%r"
+ % (st.st_mtime, current, st.st_mtime - current))
+ self.assertAlmostEqual(st.st_mtime, current,
+ delta=delta, msg=msg)
+
+ def test_utime_current(self):
+ def set_time(filename):
+ # Set to the current time in the new way
+ os.utime(self.fname)
+ self._test_utime_current(set_time)
+
+ def test_utime_current_old(self):
+ def set_time(filename):
+ # Set to the current time in the old explicit way.
+ os.utime(self.fname, None)
+ self._test_utime_current(set_time)
+
+ def get_file_system(self, path):
+ if sys.platform == 'win32':
+ root = os.path.splitdrive(os.path.abspath(path))[0] + '\\'
+ import ctypes
+ kernel32 = ctypes.windll.kernel32
+ buf = ctypes.create_unicode_buffer("", 100)
+ ok = kernel32.GetVolumeInformationW(root, None, 0,
+ None, None, None,
+ buf, len(buf))
+ if ok:
+ return buf.value
+ # return None if the filesystem is unknown
+
+ def test_large_time(self):
+ # Many filesystems are limited to the year 2038. At least, the test
+ # pass with NTFS filesystem.
+ if self.get_file_system(self.dirname) != "NTFS":
+ self.skipTest("requires NTFS")
+
+ large = 5000000000 # some day in 2128
+ os.utime(self.fname, (large, large))
+ self.assertEqual(os.stat(self.fname).st_mtime, large)
+
+ def test_utime_invalid_arguments(self):
+ # seconds and nanoseconds parameters are mutually exclusive
+ with self.assertRaises(ValueError):
+ os.utime(self.fname, (5, 5), ns=(5, 5))
+
+
from test import mapping_tests
class EnvironTests(mapping_tests.BasicTestMappingProtocol):
--
Repository URL: https://hg.python.org/cpython
More information about the Python-checkins
mailing list