2
2
from __future__ import absolute_import , division , print_function
3
3
4
4
import re
5
- from six .moves import reduce
5
+ import os
6
+ import atexit
6
7
8
+ import six
9
+ from functools import reduce
10
+
11
+ from six .moves import map
7
12
import pytest
8
13
import py
9
14
from _pytest .monkeypatch import MonkeyPatch
13
18
import tempfile
14
19
15
20
16
- def make_numbered_dir (root , prefix ):
21
+ def find_prefixed (root , prefix ):
17
22
l_prefix = prefix .lower ()
23
+ for x in root .iterdir ():
24
+ if x .name .lower ().startswith (l_prefix ):
25
+ yield x
26
+
27
+
28
+ def _max (iterable , default ):
29
+ # needed due to python2.7 lacking the default argument for max
30
+ return reduce (max , iterable , default )
18
31
19
- def parse_num (p , cut = len (l_prefix )):
32
+
33
+ def make_numbered_dir (root , prefix ):
34
+
35
+ def parse_num (p , cut = len (prefix )):
20
36
maybe_num = p .name [cut :]
21
37
try :
22
38
return int (maybe_num )
@@ -25,15 +41,7 @@ def parse_num(p, cut=len(l_prefix)):
25
41
26
42
for i in range (10 ):
27
43
# try up to 10 times to create the folder
28
- max_existing = reduce (
29
- max ,
30
- (
31
- parse_num (x )
32
- for x in root .iterdir ()
33
- if x .name .lower ().startswith (l_prefix )
34
- ),
35
- - 1 ,
36
- )
44
+ max_existing = _max (map (parse_num , find_prefixed (root , prefix )), - 1 )
37
45
new_number = max_existing + 1
38
46
new_path = root .joinpath ("{}{}" .format (prefix , new_number ))
39
47
try :
@@ -42,13 +50,60 @@ def parse_num(p, cut=len(l_prefix)):
42
50
pass
43
51
else :
44
52
return new_path
53
+ else :
54
+ raise EnvironmentError (
55
+ "could not create numbered dir with prefix {prefix} in {root})" .format (
56
+ prefix = prefix , root = root ))
57
+
58
+
59
+ def create_cleanup_lock (p ):
60
+ lock_path = p .joinpath ('.lock' )
61
+ fd = os .open (str (lock_path ), os .O_WRONLY | os .O_CREAT | os .O_EXCL , 0o644 )
62
+ pid = os .getpid ()
63
+ spid = str (pid )
64
+ if not isinstance (spid , six .binary_type ):
65
+ spid = spid .encode ("ascii" )
66
+ os .write (fd , spid )
67
+ os .close (fd )
68
+ if not lock_path .is_file ():
69
+ raise EnvironmentError ("lock path got renamed after sucessfull creation" )
70
+ return lock_path
71
+
72
+
73
+ def register_cleanup_lock_removal (lock_path ):
74
+ pid = os .getpid ()
75
+
76
+ def cleanup_on_exit (lock_path = lock_path , original_pid = pid ):
77
+ current_pid = os .getpid ()
78
+ if current_pid != original_pid :
79
+ # fork
80
+ return
81
+ try :
82
+ lock_path .unlink ()
83
+ except (OSError , IOError ):
84
+ pass
85
+ return atexit .register (cleanup_on_exit )
86
+
87
+
88
+ def cleanup_numbered_dir (root , prefix , keep ):
89
+ # todo
90
+ pass
45
91
46
92
47
93
def make_numbered_dir_with_cleanup (root , prefix , keep , consider_lock_dead_after ):
48
- p = make_numbered_dir (root , prefix )
49
- # todo cleanup
50
- return p
94
+ for i in range (10 ):
95
+ try :
96
+ p = make_numbered_dir (root , prefix )
97
+ lock_path = create_cleanup_lock (p )
98
+ register_cleanup_lock_removal (lock_path )
99
+ except Exception as e :
100
+ raise
101
+ else :
102
+ cleanup_numbered_dir (root = root , prefix = prefix , keep = keep )
103
+ return p
51
104
105
+ else :
106
+ raise e
52
107
53
108
@attr .s
54
109
class TempPathFactory (object ):
@@ -76,7 +131,7 @@ def mktemp(self, basename, numbered=True):
76
131
def getbasetemp (self ):
77
132
""" return base temporary directory. """
78
133
if self ._basetemp is None :
79
- if self .given_basetemp :
134
+ if self .given_basetemp is not None :
80
135
basetemp = Path (self .given_basetemp )
81
136
if basetemp .exists ():
82
137
shutil .rmtree (str (basetemp ))
@@ -94,9 +149,10 @@ def getbasetemp(self):
94
149
basetemp = make_numbered_dir_with_cleanup (
95
150
prefix = "pytest-" ,
96
151
root = rootdir ,
97
- keep = None ,
98
- consider_lock_dead_after = None ,
152
+ keep = 3 ,
153
+ consider_lock_dead_after = 10000 ,
99
154
)
155
+ assert basetemp is not None
100
156
self ._basetemp = t = basetemp
101
157
self .trace ("new basetemp" , t )
102
158
return t
0 commit comments