From b328f7406a3154370f94892c3026e348652852f7 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Wed, 7 Mar 2018 12:48:13 -0800 Subject: [PATCH] Refactor out the mtime fudging --- mypy/test/helpers.py | 20 ++++++++++++++++++++ mypy/test/testcheck.py | 12 +++--------- mypy/test/testdmypy.py | 10 ++-------- mypy/test/testfinegrained.py | 15 ++------------- 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/mypy/test/helpers.py b/mypy/test/helpers.py index 267f99e5586b..794499825a1d 100644 --- a/mypy/test/helpers.py +++ b/mypy/test/helpers.py @@ -3,6 +3,7 @@ import subprocess import sys import time +import shutil from typing import List, Dict, Tuple, Callable, Any, Optional @@ -356,3 +357,22 @@ def run_command(cmdline: List[str], *, env: Optional[Dict[str, str]] = None, out = err = b'' process.kill() return process.returncode, split_lines(out, err) + + +def copy_and_fudge_mtime(source_path: str, target_path: str) -> None: + # In some systems, mtime has a resolution of 1 second which can + # cause annoying-to-debug issues when a file has the same size + # after a change. We manually set the mtime to circumvent this. + # Note that we increment the old file's mtime, which guarentees a + # different value, rather than incrementing the mtime after the + # copy, which could leave the mtime unchanged if the old file had + # a similarly fudged mtime. + new_time = None + if os.path.isfile(target_path): + new_time = os.stat(target_path).st_mtime + 1 + + # Use retries to work around potential flakiness on Windows (AppVeyor). + retry_on_error(lambda: shutil.copy(source_path, target_path)) + + if new_time: + os.utime(target_path, times=(new_time, new_time)) diff --git a/mypy/test/testcheck.py b/mypy/test/testcheck.py index 0b1f1573760e..45303ce8b420 100644 --- a/mypy/test/testcheck.py +++ b/mypy/test/testcheck.py @@ -12,7 +12,8 @@ from mypy.test.data import DataDrivenTestCase, DataSuite from mypy.test.helpers import ( assert_string_arrays_equal, normalize_error_messages, - retry_on_error, update_testcase_output, parse_options + retry_on_error, update_testcase_output, parse_options, + copy_and_fudge_mtime ) from mypy.errors import CompileError from mypy.options import Options @@ -132,14 +133,7 @@ def run_case_once(self, testcase: DataDrivenTestCase, incremental_step: int = 0) if file.endswith('.' + str(incremental_step)): full = os.path.join(dn, file) target = full[:-2] - # Use retries to work around potential flakiness on Windows (AppVeyor). - retry_on_error(lambda: shutil.copy(full, target)) - - # In some systems, mtime has a resolution of 1 second which can cause - # annoying-to-debug issues when a file has the same size after a - # change. We manually set the mtime to circumvent this. - new_time = os.stat(target).st_mtime + 1 - os.utime(target, times=(new_time, new_time)) + copy_and_fudge_mtime(full, target) # Delete files scheduled to be deleted in [delete .num] sections. for path in testcase.deleted_paths.get(incremental_step, set()): # Use retries to work around potential flakiness on Windows (AppVeyor). diff --git a/mypy/test/testdmypy.py b/mypy/test/testdmypy.py index 7d8b2b76110a..a51085645186 100644 --- a/mypy/test/testdmypy.py +++ b/mypy/test/testdmypy.py @@ -15,6 +15,7 @@ from mypy.test.helpers import ( assert_string_arrays_equal, normalize_error_messages, retry_on_error, testcase_pyversion, update_testcase_output, + copy_and_fudge_mtime, ) from mypy.options import Options @@ -91,14 +92,7 @@ def run_case_once(self, testcase: DataDrivenTestCase, incremental_step: int) -> if file.endswith('.' + str(incremental_step)): full = os.path.join(dn, file) target = full[:-2] - # Use retries to work around potential flakiness on Windows (AppVeyor). - retry_on_error(lambda: shutil.copy(full, target)) - - # In some systems, mtime has a resolution of 1 second which can cause - # annoying-to-debug issues when a file has the same size after a - # change. We manually set the mtime to circumvent this. - new_time = os.stat(target).st_mtime + 1 - os.utime(target, times=(new_time, new_time)) + copy_and_fudge_mtime(full, target) # Delete files scheduled to be deleted in [delete .num] sections. for path in testcase.deleted_paths.get(incremental_step, set()): # Use retries to work around potential flakiness on Windows (AppVeyor). diff --git a/mypy/test/testfinegrained.py b/mypy/test/testfinegrained.py index 79495606897e..d261076c6c31 100644 --- a/mypy/test/testfinegrained.py +++ b/mypy/test/testfinegrained.py @@ -9,7 +9,6 @@ import os import re -import shutil from typing import List, Tuple, Optional, cast @@ -22,7 +21,7 @@ from mypy.test.data import ( DataDrivenTestCase, DataSuite, UpdateFile, module_from_path ) -from mypy.test.helpers import assert_string_arrays_equal, parse_options +from mypy.test.helpers import assert_string_arrays_equal, parse_options, copy_and_fudge_mtime from mypy.server.mergecheck import check_consistency from mypy.dmypy_server import Server from mypy.main import expand_dir @@ -102,17 +101,7 @@ def run_case(self, testcase: DataDrivenTestCase) -> None: for op in operations: if isinstance(op, UpdateFile): # Modify/create file - - # In some systems, mtime has a resolution of 1 second which can cause - # annoying-to-debug issues when a file has the same size after a - # change. We manually set the mtime to circumvent this. - new_time = None - if os.path.isfile(op.target_path): - new_time = os.stat(op.target_path).st_mtime + 1 - - shutil.copy(op.source_path, op.target_path) - if new_time: - os.utime(op.target_path, times=(new_time, new_time)) + copy_and_fudge_mtime(op.source_path, op.target_path) else: # Delete file os.remove(op.path)