@@ -239,17 +239,30 @@ is the convenience argument :ref:`allow_root_user`:
239239If accessing files as another user and/or group, the respective group/other file
240240permissions are considered.
241241
242+ Interaction with other fixtures working on the filesystem
243+ ---------------------------------------------------------
244+ Generally, if you are using a pytest fixture working on the filesystem,
245+ you should check if you really need it. Chances are that the fixture does
246+ something that could be more naturally achieved with ``pyfakefs `` using
247+ standard file system functions.
248+ If you really *do * need such fixtures, the order in which they are used with
249+ respect to the ``fs `` fixture does matter. If the fixture should work with
250+ the fake filesystem instead of the real filesystem, it should be placed
251+ *after * the ``fs `` fixture. If it shall be used with the real filesystem
252+ instead (a case that should almost never be needed), it shall be placed *before *
253+ the ``fs `` fixture.
254+ Following are some related examples.
255+
242256.. _usage_with_mock_open :
243257
244258Pyfakefs and mock_open
245- ----------------------
259+ ~~~~~~~~~~~~~~~~~~~~~~
246260If you patch ``open `` using ``mock_open `` before the initialization of
247261``pyfakefs ``, it will not work properly, because the ``pyfakefs ``
248262initialization relies on ``open `` working correctly.
249- Generally, you should not need ``mock_open `` if using ``pyfakefs ``, because you
250- always can create the files with the needed content using ``create_file ``.
251- This is true for patching any filesystem functions--avoid patching them
252- while working with ``pyfakefs ``.
263+ Generally, you should not need ``mock_open `` if using ``pyfakefs `` at all,
264+ because you can always create the files with the needed content using
265+ ``create_file `` or the standard filesystem functions.
253266If you still want to use ``mock_open ``, make sure it is only used while
254267patching is in progress. For example, if you are using ``pytest `` with the
255268``mocker `` fixture used to patch ``open ``, make sure that the ``fs `` fixture is
@@ -266,29 +279,63 @@ passed before the ``mocker`` fixture to ensure this:
266279 # works correctly
267280 mocker.patch(" builtins.open" , mocker.mock_open(read_data = " content" ))
268281
269- tmp_path fixture with pyfakefs
270- ------------------------------
271- If you are using the ``tmp_path `` fixture, or a similar pytest fixture
272- relying on the real filesystem, you may have the opposite problem: now the ``fs ``
273- fixture must be added *after * the ``tmp_path `` fixture. Otherwise, the path will be
274- created in the fake filesystem, and pytest will later try to access it in the real
275- filesystem.
282+ The tmp_path fixture
283+ ~~~~~~~~~~~~~~~~~~~~
284+ The ``tmp_path `` fixture is an example for a fixture that always works on the real
285+ filesystem. If you invoke it after the *fs * fixture, the path will be
286+ created in the fake filesystem, but pytest will later try to access it in the real
287+ filesystem. While invoking it before the *fs * fixture will technically work, it makes
288+ no real sense. The temporary directory will be created and removed in the real
289+ filesystem, but never actually used by the test that is working in the fake filesystem.
290+
291+ A replacement for the tmp_path fixture
292+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
293+ As an example for a useful fixture working on the filesystem, let's write a simple
294+ replacement for ``tmp_path `` that uses ``tempfile.TemporaryDirectory ``.
295+
296+ There are two ways to do this with respect to the ``fs `` fixture. The common
297+ way is to base your fixture on the ``fs `` fixture (imports are omitted):
298+
299+ .. code :: python
300+
301+ @pytest.fixture
302+ def temp_path (fs ):
303+ tmp_dir = tempfile.TemporaryDirectory()
304+ yield Path(tmp_dir.name)
305+
306+
307+ def test_temp_path (temp_path ):
308+ assert temp_path.exists()
309+ assert isinstance (temp_path, fake_pathlib.FakePath)
310+
311+ This way, the fixture will always use the fake filesystem. Note that you can
312+ add the ``fs `` fixture to the test additionally, if you need to access any
313+ convenience function in the fake filesystem.
314+
315+ The other possibility is to write the fixture independently of ``pyfakefs ``,
316+ so it can be used both in tests with the real filesystem and with the fake
317+ filesystem:
276318
277319.. code :: python
278320
279- def test_working (tmp_path , fs ):
280- fs.create_file(tmp_path / " foo" )
321+ @pytest.fixture
322+ def temp_path ():
323+ tmp_dir = tempfile.TemporaryDirectory()
324+ yield Path(tmp_dir.name)
325+
326+
327+ def test_real_temp_path (temp_path ):
328+ assert temp_path.exists()
329+ # we do not check for pathlib.Path, because FakePath is derived from it
330+ assert isinstance (temp_path, (pathlib.PosixPath, pathlib.WindowsPath))
281331
282332
283- def test_not_working (fs , tmp_path ):
284- # causes an error while pytest tries to access the temporary directory
285- pass
333+ def test_fake_temp_path (fs , temp_path ):
334+ assert temp_path.exists()
335+ assert isinstance (temp_path, fake_pathlib.FakePath)
286336
287- Note though that ``tmp_path `` and similar fixtures may not make much sense in the
288- first place if used with ``pyfakefs ``. While the directory will be created and
289- removed in the real filesystem, all files you create will live in the fake filesystem
290- only. You could as well use hardcoded paths in your tests, as they will not interfere
291- with paths created in other tests.
337+ Note that in the last case, your fixture must be invoked *after * the ``fs ``
338+ fixture, in order for it to work in the fake filesystem.
292339
293340Pathlib.Path objects created outside of tests
294341---------------------------------------------
0 commit comments