14
14
15
15
16
16
def lock_file (filename : str , duration : float ) -> Thread :
17
- '''
18
- Opens filename (which must exist) for reading
19
- After duration sec, releases the handle
20
- '''
17
+ """Open a file and keep it open in a background thread for duration sec."""
21
18
def _lock_file () -> None :
22
19
with open (filename ):
23
20
time .sleep (duration )
@@ -28,7 +25,6 @@ def _lock_file() -> None:
28
25
29
26
@skipUnless (WIN32 , "only relevant for Windows" )
30
27
class ReliableReplace (TestCase ):
31
- # will be cleaned up automatically when this class goes out of scope
32
28
tmpdir = tempfile .TemporaryDirectory (prefix = 'mypy-test-' ,
33
29
dir = os .path .abspath ('tmp-test-dirs' ))
34
30
timeout = 1
@@ -39,12 +35,15 @@ class ReliableReplace(TestCase):
39
35
40
36
@classmethod
41
37
def tearDownClass (cls ) -> None :
38
+ # Need to wait for threads to complete, otherwise we'll get PermissionError
39
+ # at the end (whether tmpdir goes out of scope or we explicitly call cleanup).
42
40
for t in cls .threads :
43
41
t .join ()
42
+ cls .tmpdir .cleanup ()
44
43
45
44
def prepare_src_dest (self , src_lock_duration : float , dest_lock_duration : float
46
45
) -> Tuple [str , str ]:
47
- # create two temporary files
46
+ # Create two temporary files with random names.
48
47
src = os .path .join (self .tmpdir .name , random_string ())
49
48
dest = os .path .join (self .tmpdir .name , random_string ())
50
49
@@ -63,16 +62,16 @@ def replace_ok(self, src_lock_duration: float, dest_lock_duration: float,
63
62
self .assertEqual (open (dest ).read (), src , 'replace failed' )
64
63
65
64
def test_everything (self ) -> None :
66
- # normal use, no locks
65
+ # No files locked.
67
66
self .replace_ok (0 , 0 , self .timeout )
68
- # make sure the problem is real
67
+ # Make sure we can reproduce the issue with our setup.
69
68
src , dest = self .prepare_src_dest (self .short_lock , 0 )
70
69
with self .assertRaises (PermissionError ):
71
70
os .replace (src , dest )
72
- # short lock
71
+ # Lock files for a time short enough that util.replace won't timeout.
73
72
self .replace_ok (self .short_lock , 0 , self .timeout )
74
73
self .replace_ok (0 , self .short_lock , self .timeout )
75
- # long lock
74
+ # Lock files for a time long enough that util.replace times out.
76
75
with self .assertRaises (PermissionError ):
77
76
self .replace_ok (self .long_lock , 0 , self .timeout )
78
77
with self .assertRaises (PermissionError ):
0 commit comments