Skip to content

Commit 3a35898

Browse files
committed
Merge remote-tracking branch 'origin/master' into lru
2 parents 9fe8710 + ebba3eb commit 3a35898

File tree

11 files changed

+77
-18
lines changed

11 files changed

+77
-18
lines changed

changelog/4181.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Handle race condition between creation and deletion of temporary folders.

changelog/4243.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix regression when ``stacklevel`` for warnings was passed as positional argument on python2.

changelog/4248.trivial.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove use of unnecessary compat shim, six.binary_type

src/_pytest/config/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,13 @@ def _getconftestmodules(self, path):
389389
if self._noconftest:
390390
return []
391391

392-
if path.isfile():
393-
directory = path.dirpath()
394-
else:
395-
directory = path
396392
try:
397-
return self._path2confmods[directory]
393+
return self._path2confmods[path]
398394
except KeyError:
395+
if path.isfile():
396+
directory = path.dirpath()
397+
else:
398+
directory = path
399399
# XXX these days we may rather want to use config.rootdir
400400
# and allow users to opt into looking into the rootdir parent
401401
# directories instead of requiring to specify confcutdir
@@ -408,7 +408,7 @@ def _getconftestmodules(self, path):
408408
mod = self._importconftest(conftestpath)
409409
clist.append(mod)
410410

411-
self._path2confmods[directory] = clist
411+
self._path2confmods[path] = clist
412412
return clist
413413

414414
def _rget_with_confmod(self, name, path):

src/_pytest/pathlib.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def create_cleanup_lock(p):
151151
else:
152152
pid = os.getpid()
153153
spid = str(pid)
154-
if not isinstance(spid, six.binary_type):
154+
if not isinstance(spid, bytes):
155155
spid = spid.encode("ascii")
156156
os.write(fd, spid)
157157
os.close(fd)
@@ -177,9 +177,15 @@ def cleanup_on_exit(lock_path=lock_path, original_pid=pid):
177177
return register(cleanup_on_exit)
178178

179179

180-
def delete_a_numbered_dir(path):
181-
"""removes a numbered directory"""
182-
create_cleanup_lock(path)
180+
def maybe_delete_a_numbered_dir(path):
181+
"""removes a numbered directory if its lock can be obtained"""
182+
try:
183+
create_cleanup_lock(path)
184+
except (OSError, EnvironmentError):
185+
# known races:
186+
# * other process did a cleanup at the same time
187+
# * deletable folder was found
188+
return
183189
parent = path.parent
184190

185191
garbage = parent.joinpath("garbage-{}".format(uuid.uuid4()))
@@ -209,7 +215,7 @@ def ensure_deletable(path, consider_lock_dead_if_created_before):
209215
def try_cleanup(path, consider_lock_dead_if_created_before):
210216
"""tries to cleanup a folder if we can ensure its deletable"""
211217
if ensure_deletable(path, consider_lock_dead_if_created_before):
212-
delete_a_numbered_dir(path)
218+
maybe_delete_a_numbered_dir(path)
213219

214220

215221
def cleanup_candidates(root, prefix, keep):

src/_pytest/recwarn.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,27 @@ def __enter__(self):
156156
# trivial patching of `warnings.warn` seems to be enough somehow?
157157
if six.PY2:
158158

159-
def warn(*args, **kwargs):
160-
kwargs.setdefault("stacklevel", 1)
161-
kwargs["stacklevel"] += 1
159+
def warn(message, category=None, stacklevel=1):
160+
# duplicate the stdlib logic due to
161+
# bad handing in the c version of warnings
162+
if isinstance(message, Warning):
163+
category = message.__class__
164+
# Check category argument
165+
if category is None:
166+
category = UserWarning
167+
assert issubclass(category, Warning)
162168

163169
# emulate resetting the warn registry
164-
f_globals = sys._getframe(kwargs["stacklevel"] - 1).f_globals
170+
f_globals = sys._getframe(stacklevel).f_globals
165171
if "__warningregistry__" in f_globals:
166172
orig = f_globals["__warningregistry__"]
167173
f_globals["__warningregistry__"] = None
168174
try:
169-
return self._saved_warn(*args, **kwargs)
175+
return self._saved_warn(message, category, stacklevel + 1)
170176
finally:
171177
f_globals["__warningregistry__"] = orig
172178
else:
173-
return self._saved_warn(*args, **kwargs)
179+
return self._saved_warn(message, category, stacklevel + 1)
174180

175181
warnings.warn, self._saved_warn = warn, warnings.warn
176182
return self
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
foo_*
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import argparse
2+
import pathlib
3+
4+
5+
HERE = pathlib.Path(__file__).parent
6+
TEST_CONTENT = (HERE / "template_test.py").read_bytes()
7+
8+
parser = argparse.ArgumentParser()
9+
parser.add_argument("numbers", nargs="*", type=int)
10+
11+
12+
def generate_folders(root, elements, *more_numbers):
13+
fill_len = len(str(elements))
14+
if more_numbers:
15+
for i in range(elements):
16+
new_folder = root.joinpath(f"foo_{i:0>{fill_len}}")
17+
new_folder.mkdir()
18+
new_folder.joinpath("__init__.py").write_bytes(TEST_CONTENT)
19+
generate_folders(new_folder, *more_numbers)
20+
else:
21+
for i in range(elements):
22+
new_test = root.joinpath(f"test_{i:0<{fill_len}}.py")
23+
new_test.write_bytes(TEST_CONTENT)
24+
25+
26+
if __name__ == "__main__":
27+
args = parser.parse_args()
28+
generate_folders(HERE, *(args.numbers or (10, 100)))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def test_x():
2+
pass

testing/test_recwarn.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ def test_recording(self):
4646
assert values is rec.list
4747
pytest.raises(AssertionError, "rec.pop()")
4848

49+
@pytest.mark.issue(4243)
50+
def test_warn_stacklevel(self):
51+
rec = WarningsRecorder()
52+
with rec:
53+
warnings.warn("test", DeprecationWarning, 2)
54+
4955
def test_typechecking(self):
5056
from _pytest.recwarn import WarningsChecker
5157

0 commit comments

Comments
 (0)