-
Notifications
You must be signed in to change notification settings - Fork 91
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
adding a realdir with target to '/' creates a self-referential '' entry that makes the fs unusable #901
Comments
Workaround The following produces the desired result. cd $(mktemp -d)
mkdir -p data/root/foo/bar
touch data/root/foo/bar/file-{0,1,2,3}.txt
touch data/root/hello.txt
touch __init__.py
cat > conftest.py <<"EOF"
import os
import pytest
@pytest.fixture
def myfs(fs):
fs.pause()
content = [(e.name, e.path, os.path.isdir(e)) for e in os.scandir('data/root')]
fs.resume()
for name, path, isdir in content:
if isdir:
fs.add_real_directory(path, target_path=f'/{name}')
else:
fs.add_real_file(path, target_path=f'/{name}')
yield fs
EOF
cat > test_fake.py <<"EOF"
import os
def test_fake(myfs):
print('\n\nwith fake fs')
for _, e in zip(range(10), os.walk('/')):
print(e)
def test_real():
print('\n\nwith real fs')
os.chdir('data/root')
for _, e in zip(range(10), os.walk('.')):
print(e)
EOF
pytest -s test_fake.py Output:
|
Thanks for the report and the investigation! |
So far I have not been able to reproduce your problem. I let the test run in the CI and got no errors on any system - maybe I'm doing something wrong. Here is the latest varaint of the test I have been using (modified it a bit to work on different systems): import os
import shutil
import tempfile
from pathlib import Path
import pytest
@pytest.fixture(scope="session")
def real_dir():
path = Path(tempfile.gettempdir()) / "data" / "root" / "foo" / "bar"
os.makedirs(path, exist_ok=True)
(path / "file.txt").touch(exist_ok=True)
(path / "__init__.py").touch(exist_ok=True)
yield path
shutil.rmtree(path, ignore_errors=True)
@pytest.fixture
def myfs(real_dir, fs):
fs.add_real_directory(real_dir, target_path=fs.root.path)
yield fs
def test_fake(myfs):
print("\n\nwith fake fs")
for _, e in zip(range(10), os.walk(myfs.root.path)):
print(e)
def test_real(real_dir):
print("\n\nwith real fs")
for _, e in zip(range(10), os.walk(real_dir)):
print(e) Can you please check the outcome of this test in your environment? |
I am away from my desktop right now. But what I provided was a full reproducible example (including setting up of the |
Update: when I try your test code, I can see the unexpected output (same as in my case). You have to use pytest -s test_it.py
================================================================================================ test session starts =================================================================================================
platform linux -- Python 3.10.9, pytest-7.1.2, pluggy-1.0.0
rootdir: /home/pierred/tmp/foobar
plugins: xdist-2.5.0, anyio-3.5.0, cov-3.0.0, pyfakefs-5.3.0, hypothesis-6.29.3, forked-1.3.0
collected 2 items
test_it.py
with fake fs
('/', ['tmp', ''], [])
('/tmp', [], [])
('/', ['tmp', ''], [])
('/tmp', [], [])
('/', ['tmp', ''], [])
('/tmp', [], [])
('/', ['tmp', ''], [])
('/tmp', [], [])
('/', ['tmp', ''], [])
('/tmp', [], [])
.
with real fs
('/tmp/data/root/foo/bar', [], ['__init__.py', 'file.txt'])
.
================================================================================================= 2 passed in 0.21s ========= Addendum def test_fake(myfs):
print("\n\nwith fake fs")
for _, e in zip(range(10), os.walk(myfs.root.path)):
print(e) into: def test_fake(myfs):
print("\n\nwith fake fs")
for e in os.walk(myfs.root.path):
print(e) You should then get a recursion error. |
Ah sorry, ignore that - I just noticed that I can reproduce it, I just made a dumb mistake... |
No worries at all. I am grateful that you're willing to take a look. If I had time, I would dig in, but alas, I have zero time at the moment. |
The problem is not mapping to the root dir as such, but mapping to a directory already existing in the fake directory - this is currently not supported (never come up before). This may take a bit... |
There was actually a test that checked that mapping to an existing directory raises an exception - which it does, except for the root path (which was actually a bug). |
- changed behavior of add_real_directory() to be able to map a real directory to an existing directory in the fake filesystem - fixes pytest-dev#901
- changed behavior of add_real_directory() to be able to map a real directory to an existing directory in the fake filesystem - fixes pytest-dev#901
I think the merge could be done in a few ways, a bit similar to some of the ways
We would need to think about how to control this by a clear set of flags. But how does it sound in terms of the logic? |
Sorry, I seem to have missed your comment and completely forgot about my PR (#903)... EDIT: Yours was not the only comment I missed - looks like I accidentally removed myself from the watchers for this repo (or have been removed somehow). The PR uses a mix of the second and third approach. If a directory exists, the directories are merged to the extent that no files are overwritten. If a file would be overwritten (or a file exists where a directory would be created), an exception is raised (you can have a look at the PR, especially the tests which should show the behavior). If this is ok for you, I would merge it. |
@pdemarti - I'm going to merge the PR, and if that isn't sufficient for you, I can see if I can make more changes. |
- changed behavior of add_real_directory() to be able to map a real directory to an existing directory in the fake filesystem - fixes #901
@mrbean-bremen : that sounds perfect. We probably don't need the other cases. Thank you so much for doing this.
|
Good to hear! I'm waiting for another PR to be finished and probably will make a bug fix release afterwards (I wanted to do it anyway because of another fixed bug). |
Describe the bug
My first baby steps with
pyfakefs
aren't going well... I am trying to populate a fake fs with custom entries under root (to test a system that expects certain files at absolute locations).Instead of seeing the desired content, doing a simple
os.walk()
results in an infinite loop, seemingly because an extra, self-referential entry (the empty string''
) is created under/
. If I look at the beginning of the iterator ofos.walk()
, I see a repeating alternation of'/'
and'/tmp'
.How To Reproduce
The output of the above is:
What I was expecting was to see the same output for
test_fake
as fortest_real
, but relocated under'/'
.Your environment
Probable cause
When I run the test in PyCharm's debugger, I noticed a strange entry under the root dir of
myfs
: the empty string (''
, third line of the output below):Incidentally, if I try to print that in the unit test itself (rather than copying the view from the debugger above), I get:
In any case, it seems that this erroneous entry has been created during
fs.add_real_directory
. Inspecting it in the debugger, that entry refers to the filesystem itself. Specifically:The text was updated successfully, but these errors were encountered: