Skip to content

Commit d053cdf

Browse files
factor out max and iterate on locks and cleanups
1 parent 2e39fd8 commit d053cdf

File tree

1 file changed

+74
-18
lines changed

1 file changed

+74
-18
lines changed

src/_pytest/tmpdir.py

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
from __future__ import absolute_import, division, print_function
33

44
import re
5-
from six.moves import reduce
5+
import os
6+
import atexit
67

8+
import six
9+
from functools import reduce
10+
11+
from six.moves import map
712
import pytest
813
import py
914
from _pytest.monkeypatch import MonkeyPatch
@@ -13,10 +18,21 @@
1318
import tempfile
1419

1520

16-
def make_numbered_dir(root, prefix):
21+
def find_prefixed(root, prefix):
1722
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)
1831

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)):
2036
maybe_num = p.name[cut:]
2137
try:
2238
return int(maybe_num)
@@ -25,15 +41,7 @@ def parse_num(p, cut=len(l_prefix)):
2541

2642
for i in range(10):
2743
# 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)
3745
new_number = max_existing + 1
3846
new_path = root.joinpath("{}{}".format(prefix, new_number))
3947
try:
@@ -42,13 +50,60 @@ def parse_num(p, cut=len(l_prefix)):
4250
pass
4351
else:
4452
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
4591

4692

4793
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
51104

105+
else:
106+
raise e
52107

53108
@attr.s
54109
class TempPathFactory(object):
@@ -76,7 +131,7 @@ def mktemp(self, basename, numbered=True):
76131
def getbasetemp(self):
77132
""" return base temporary directory. """
78133
if self._basetemp is None:
79-
if self.given_basetemp:
134+
if self.given_basetemp is not None:
80135
basetemp = Path(self.given_basetemp)
81136
if basetemp.exists():
82137
shutil.rmtree(str(basetemp))
@@ -94,9 +149,10 @@ def getbasetemp(self):
94149
basetemp = make_numbered_dir_with_cleanup(
95150
prefix="pytest-",
96151
root=rootdir,
97-
keep=None,
98-
consider_lock_dead_after=None,
152+
keep=3,
153+
consider_lock_dead_after=10000,
99154
)
155+
assert basetemp is not None
100156
self._basetemp = t = basetemp
101157
self.trace("new basetemp", t)
102158
return t

0 commit comments

Comments
 (0)