-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Internal error py.error.EEXIST: [File exists]: mkdir(...)
on case insensitive file systems
#3451
Internal error py.error.EEXIST: [File exists]: mkdir(...)
on case insensitive file systems
#3451
Comments
Thanks @asottile! |
Strangely I cannot reproduce this on Windows (which is also case insensitive but preserving). I see the relevant code and there's a try/except for @asottile could you please report which version of |
this is a path normalization issue in pylib since osx is case-insensitive while pylib is developed based on posix i beleive a few normcase calls are missing in pylib |
(the |
(Duh sorry, the
I'm not sure @RonnyPfannschmidt, the code which triggers this error is properly guarded with a try/except which should catch try:
udir = rootdir.mkdir(prefix + str(maxnum+1))
if lock_timeout:
lockfile = create_lockfile(udir)
atexit_remove_lockfile(lockfile)
except (py.error.EEXIST, py.error.ENOENT, py.error.EBUSY): Not sure what's going on here... |
@asottile please provide the output with |
The issue is here:
so the first time through the loop it sets The second pass through the loop, Output is a bit long so here's a paste: https://i.fluffy.cc/rWxqMTZQBzCqZwtpRJWdc384Q5r5G6R1.html |
good find - quite an edge-case |
Here's a "simpler" reproduction: def test(tmpdir):
tmpdir.make_numbered_dir('a')
tmpdir.make_numbered_dir('A') |
I guess the further rootcause is this trashfire:
|
Reading through a few bpo bugs, (notably this one), it seems that
which ignores the filesystem type entirely (you could have a case-insensitive mount on a posix platform and you could have a case sensitive mount on a windows platform). I guess the fix (?) is to write a "more correct" normcase which does some filesystem detection (probably easiest to do this via feature detection?) |
since filesystem detection is going to be a expensive mess, i would like to propose to normalize filenames to lowercase and to a certain unicode encoding if necessary, making the normalization function an optional argument defaulting to methodcaller('lower') seems the most sensible to me for now |
makes sense, this patch to diff --git a/py/_path/local.py b/py/_path/local.py
index 5a785b0f..ec56cb2e 100644
--- a/py/_path/local.py
+++ b/py/_path/local.py
@@ -810,6 +810,7 @@ class LocalPath(FSBase):
if rootdir is None:
rootdir = cls.get_temproot()
+ prefix = prefix.lower()
nprefix = normcase(prefix)
def parse_num(path):
""" parse the number out of a path (if it matches the prefix) """ |
@asottile great job, please submit it together with the proposed testcase |
it (unfortunately) breaks this test case: def test_make_numbered_dir_case_sensitive(self, tmpdir, monkeypatch):
# https://github.com/pytest-dev/pytest/issues/708
monkeypatch.setattr(py._path.local, 'normcase', lambda path: path)
monkeypatch.setattr(tmpdir, 'listdir',
lambda: [tmpdir._fastjoin('case.0')])
numdir = local.make_numbered_dir(prefix='CAse.', rootdir=tmpdir,
keep=2, lock_timeout=0)
assert numdir.basename.endswith('.0') though that's just a consequence of (bad) mocking? |
@asottile as far as i can tell that test is bad - it ensures that we break on case-insensitive filesystems |
here's that PR: pytest-dev/py#186 |
This has a fix from the |
Summary: - Fix pytest-dev/pytest#3451: don't make assumptions about fs case sensitivity in `make_numbered_dir`. Test Plan: Tested through `pylint` and `python-pytest`. Reviewers: #triage_team, sunnyflunk Reviewed By: #triage_team, sunnyflunk Differential Revision: https://dev.solus-project.com/D3469
real world case
Originally hit for these tests
I typically don't develop on a mac, but noticed the tests failing there.
version
I'm running pytest 3.5.1, but have been able to reproduce this on every version back to 2.5.2 (at which I stopped trying because it can't run python3.6!)
minimal reproduction
minimal reproduction output
The text was updated successfully, but these errors were encountered: