Skip to content

Commit 6f20b4b

Browse files
committed
Introduce compat.fspath
1 parent f93f284 commit 6f20b4b

File tree

3 files changed

+45
-33
lines changed

3 files changed

+45
-33
lines changed

src/_pytest/assertion/rewrite.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from _pytest.assertion.util import ( # noqa: F401
2929
format_explanation as _format_explanation,
3030
)
31+
from _pytest.compat import fspath
3132
from _pytest.pathlib import fnmatch_ex
3233
from _pytest.pathlib import PurePath
3334

@@ -120,7 +121,7 @@ def exec_module(self, module):
120121
write = not sys.dont_write_bytecode
121122
cache_dir = get_cache_dir(fn)
122123
if write:
123-
ok = try_mkdir(cache_dir)
124+
ok = try_makedirs(cache_dir)
124125
if not ok:
125126
write = False
126127
state.trace("read only directory: {}".format(cache_dir))
@@ -259,7 +260,7 @@ def _write_pyc(state, co, source_stat, pyc):
259260
# (C)Python, since these "pycs" should never be seen by builtin
260261
# import. However, there's little reason deviate.
261262
try:
262-
with atomicwrites.atomic_write(str(pyc), mode="wb", overwrite=True) as fp:
263+
with atomicwrites.atomic_write(fspath(pyc), mode="wb", overwrite=True) as fp:
263264
fp.write(importlib.util.MAGIC_NUMBER)
264265
# as of now, bytecode header expects 32-bit numbers for size and mtime (#4903)
265266
mtime = int(source_stat.st_mtime) & 0xFFFFFFFF
@@ -278,7 +279,7 @@ def _write_pyc(state, co, source_stat, pyc):
278279

279280
def _rewrite_test(fn, config):
280281
"""read and rewrite *fn* and return the code object."""
281-
fn = str(fn)
282+
fn = fspath(fn)
282283
stat = os.stat(fn)
283284
with open(fn, "rb") as f:
284285
source = f.read()
@@ -294,12 +295,12 @@ def _read_pyc(source, pyc, trace=lambda x: None):
294295
Return rewritten code if successful or None if not.
295296
"""
296297
try:
297-
fp = open(str(pyc), "rb")
298+
fp = open(fspath(pyc), "rb")
298299
except IOError:
299300
return None
300301
with fp:
301302
try:
302-
stat_result = os.stat(str(source))
303+
stat_result = os.stat(fspath(source))
303304
mtime = int(stat_result.st_mtime)
304305
size = stat_result.st_size
305306
data = fp.read(12)
@@ -751,7 +752,7 @@ def visit_Assert(self, assert_):
751752
"assertion is always true, perhaps remove parentheses?"
752753
),
753754
category=None,
754-
filename=str(self.module_path),
755+
filename=fspath(self.module_path),
755756
lineno=assert_.lineno,
756757
)
757758

@@ -874,7 +875,7 @@ def warn_about_none_ast(self, node, module_path, lineno):
874875
lineno={lineno},
875876
)
876877
""".format(
877-
filename=str(module_path), lineno=lineno
878+
filename=fspath(module_path), lineno=lineno
878879
)
879880
).body
880881
return ast.If(val_is_none, send_warning, [])
@@ -1020,18 +1021,15 @@ def visit_Compare(self, comp: ast.Compare):
10201021
return res, self.explanation_param(self.pop_format_context(expl_call))
10211022

10221023

1023-
def try_mkdir(cache_dir):
1024-
"""Attempts to create the given directory, returns True if successful"""
1024+
def try_makedirs(cache_dir) -> bool:
1025+
"""Attempts to create the given directory and sub-directories exist, returns True if
1026+
successful or it already exists"""
10251027
try:
1026-
os.makedirs(str(cache_dir))
1027-
except FileExistsError:
1028-
# Either the pycache directory already exists (the
1029-
# common case) or it's blocked by a non-dir node. In the
1030-
# latter case, we'll ignore it in _write_pyc.
1031-
return True
1032-
except (FileNotFoundError, NotADirectoryError):
1033-
# One of the path components was not a directory, likely
1034-
# because we're in a zip file.
1028+
os.makedirs(fspath(cache_dir), exist_ok=True)
1029+
except (FileNotFoundError, NotADirectoryError, FileExistsError):
1030+
# One of the path components was not a directory:
1031+
# - we're in a zip file
1032+
# - it is a file
10351033
return False
10361034
except PermissionError:
10371035
return False

src/_pytest/compat.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import functools
55
import inspect
66
import io
7+
import os
78
import re
89
import sys
910
from contextlib import contextmanager
@@ -41,6 +42,19 @@ def _format_args(func):
4142
REGEX_TYPE = type(re.compile(""))
4243

4344

45+
if sys.version_info < (3, 6):
46+
47+
def fspath(p):
48+
"""os.fspath replacement, useful to point out when we should replace it by the
49+
real function once we drop py35.
50+
"""
51+
return str(p)
52+
53+
54+
else:
55+
fspath = os.fspath
56+
57+
4458
def is_generator(func):
4559
genfunc = inspect.isgeneratorfunction(func)
4660
return genfunc and not iscoroutinefunction(func)

testing/test_assertrewrite.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,43 +1554,43 @@ def test_get_assertion_exprs(src, expected):
15541554
assert _get_assertion_exprs(src) == expected
15551555

15561556

1557-
def test_try_mkdir(monkeypatch, tmp_path):
1558-
from _pytest.assertion.rewrite import try_mkdir
1557+
def test_try_makedirs(monkeypatch, tmp_path):
1558+
from _pytest.assertion.rewrite import try_makedirs
15591559

15601560
p = tmp_path / "foo"
15611561

15621562
# create
1563-
assert try_mkdir(str(p))
1563+
assert try_makedirs(str(p))
15641564
assert p.is_dir()
15651565

15661566
# already exist
1567-
assert try_mkdir(str(p))
1567+
assert try_makedirs(str(p))
15681568

15691569
# monkeypatch to simulate all error situations
1570-
def fake_mkdir(p, mode, *, exc):
1570+
def fake_mkdir(p, exist_ok=False, *, exc):
15711571
assert isinstance(p, str)
15721572
raise exc
15731573

1574-
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=FileNotFoundError()))
1575-
assert not try_mkdir(str(p))
1574+
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=FileNotFoundError()))
1575+
assert not try_makedirs(str(p))
15761576

1577-
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=NotADirectoryError()))
1578-
assert not try_mkdir(str(p))
1577+
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=NotADirectoryError()))
1578+
assert not try_makedirs(str(p))
15791579

1580-
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=PermissionError()))
1581-
assert not try_mkdir(str(p))
1580+
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=PermissionError()))
1581+
assert not try_makedirs(str(p))
15821582

15831583
err = OSError()
15841584
err.errno = errno.EROFS
1585-
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=err))
1586-
assert not try_mkdir(str(p))
1585+
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=err))
1586+
assert not try_makedirs(str(p))
15871587

15881588
# unhandled OSError should raise
15891589
err = OSError()
15901590
err.errno = errno.ECHILD
1591-
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=err))
1591+
monkeypatch.setattr(os, "makedirs", partial(fake_mkdir, exc=err))
15921592
with pytest.raises(OSError) as exc_info:
1593-
try_mkdir(str(p))
1593+
try_makedirs(str(p))
15941594
assert exc_info.value.errno == errno.ECHILD
15951595

15961596

0 commit comments

Comments
 (0)