Merge pull request #5684 from nicoddemus/errno-nomore
Use OSError subclasses instead of handling errno
This commit is contained in:
commit
82763a293a
|
@ -0,0 +1 @@
|
||||||
|
Replace manual handling of ``OSError.errno`` in the codebase by new ``OSError`` subclasses (``PermissionError``, ``FileNotFoundError``, etc.).
|
|
@ -116,24 +116,11 @@ class AssertionRewritingHook:
|
||||||
write = not sys.dont_write_bytecode
|
write = not sys.dont_write_bytecode
|
||||||
cache_dir = os.path.join(os.path.dirname(fn), "__pycache__")
|
cache_dir = os.path.join(os.path.dirname(fn), "__pycache__")
|
||||||
if write:
|
if write:
|
||||||
try:
|
ok = try_mkdir(cache_dir)
|
||||||
os.mkdir(cache_dir)
|
if not ok:
|
||||||
except OSError:
|
write = False
|
||||||
e = sys.exc_info()[1].errno
|
state.trace("read only directory: {}".format(os.path.dirname(fn)))
|
||||||
if e == errno.EEXIST:
|
|
||||||
# Either the __pycache__ directory already exists (the
|
|
||||||
# common case) or it's blocked by a non-dir node. In the
|
|
||||||
# latter case, we'll ignore it in _write_pyc.
|
|
||||||
pass
|
|
||||||
elif e in {errno.ENOENT, errno.ENOTDIR}:
|
|
||||||
# One of the path components was not a directory, likely
|
|
||||||
# because we're in a zip file.
|
|
||||||
write = False
|
|
||||||
elif e in {errno.EACCES, errno.EROFS, errno.EPERM}:
|
|
||||||
state.trace("read only directory: %r" % os.path.dirname(fn))
|
|
||||||
write = False
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
cache_name = os.path.basename(fn)[:-3] + PYC_TAIL
|
cache_name = os.path.basename(fn)[:-3] + PYC_TAIL
|
||||||
pyc = os.path.join(cache_dir, cache_name)
|
pyc = os.path.join(cache_dir, cache_name)
|
||||||
# Notice that even if we're in a read-only directory, I'm going
|
# Notice that even if we're in a read-only directory, I'm going
|
||||||
|
@ -1026,3 +1013,26 @@ warn_explicit(
|
||||||
else:
|
else:
|
||||||
res = load_names[0]
|
res = load_names[0]
|
||||||
return res, self.explanation_param(self.pop_format_context(expl_call))
|
return res, self.explanation_param(self.pop_format_context(expl_call))
|
||||||
|
|
||||||
|
|
||||||
|
def try_mkdir(cache_dir):
|
||||||
|
"""Attempts to create the given directory, returns True if successful"""
|
||||||
|
try:
|
||||||
|
os.mkdir(cache_dir)
|
||||||
|
except FileExistsError:
|
||||||
|
# Either the __pycache__ directory already exists (the
|
||||||
|
# common case) or it's blocked by a non-dir node. In the
|
||||||
|
# latter case, we'll ignore it in _write_pyc.
|
||||||
|
return True
|
||||||
|
except (FileNotFoundError, NotADirectoryError):
|
||||||
|
# One of the path components was not a directory, likely
|
||||||
|
# because we're in a zip file.
|
||||||
|
return False
|
||||||
|
except PermissionError:
|
||||||
|
return False
|
||||||
|
except OSError as e:
|
||||||
|
# as of now, EROFS doesn't have an equivalent OSError-subclass
|
||||||
|
if e.errno == errno.EROFS:
|
||||||
|
return False
|
||||||
|
raise
|
||||||
|
return True
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import atexit
|
import atexit
|
||||||
import errno
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import itertools
|
import itertools
|
||||||
import operator
|
import operator
|
||||||
|
@ -163,14 +162,8 @@ def create_cleanup_lock(p):
|
||||||
lock_path = get_lock_path(p)
|
lock_path = get_lock_path(p)
|
||||||
try:
|
try:
|
||||||
fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
|
fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
|
||||||
except OSError as e:
|
except FileExistsError as e:
|
||||||
if e.errno == errno.EEXIST:
|
raise EnvironmentError("cannot create lockfile in {path}".format(path=p)) from e
|
||||||
raise EnvironmentError(
|
|
||||||
"cannot create lockfile in {path}".format(path=p)
|
|
||||||
) from e
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise
|
|
||||||
else:
|
else:
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
spid = str(pid).encode()
|
spid = str(pid).encode()
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import ast
|
import ast
|
||||||
|
import errno
|
||||||
import glob
|
import glob
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
|
@ -7,6 +8,7 @@ import stat
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
|
||||||
|
@ -1528,3 +1530,43 @@ class TestAssertionPass:
|
||||||
)
|
)
|
||||||
def test_get_assertion_exprs(src, expected):
|
def test_get_assertion_exprs(src, expected):
|
||||||
assert _get_assertion_exprs(src) == expected
|
assert _get_assertion_exprs(src) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_try_mkdir(monkeypatch, tmp_path):
|
||||||
|
from _pytest.assertion.rewrite import try_mkdir
|
||||||
|
|
||||||
|
p = tmp_path / "foo"
|
||||||
|
|
||||||
|
# create
|
||||||
|
assert try_mkdir(str(p))
|
||||||
|
assert p.is_dir()
|
||||||
|
|
||||||
|
# already exist
|
||||||
|
assert try_mkdir(str(p))
|
||||||
|
|
||||||
|
# monkeypatch to simulate all error situations
|
||||||
|
def fake_mkdir(p, *, exc):
|
||||||
|
assert isinstance(p, str)
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=FileNotFoundError()))
|
||||||
|
assert not try_mkdir(str(p))
|
||||||
|
|
||||||
|
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=NotADirectoryError()))
|
||||||
|
assert not try_mkdir(str(p))
|
||||||
|
|
||||||
|
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=PermissionError()))
|
||||||
|
assert not try_mkdir(str(p))
|
||||||
|
|
||||||
|
err = OSError()
|
||||||
|
err.errno = errno.EROFS
|
||||||
|
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=err))
|
||||||
|
assert not try_mkdir(str(p))
|
||||||
|
|
||||||
|
# unhandled OSError should raise
|
||||||
|
err = OSError()
|
||||||
|
err.errno = errno.ECHILD
|
||||||
|
monkeypatch.setattr(os, "mkdir", partial(fake_mkdir, exc=err))
|
||||||
|
with pytest.raises(OSError) as exc_info:
|
||||||
|
try_mkdir(str(p))
|
||||||
|
assert exc_info.value.errno == errno.ECHILD
|
||||||
|
|
Loading…
Reference in New Issue