@@ -239,17 +239,30 @@ is the convenience argument :ref:`allow_root_user`:
239
239
If accessing files as another user and/or group, the respective group/other file
240
240
permissions are considered.
241
241
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
+
242
256
.. _usage_with_mock_open :
243
257
244
258
Pyfakefs and mock_open
245
- ----------------------
259
+ ~~~~~~~~~~~~~~~~~~~~~~
246
260
If you patch ``open `` using ``mock_open `` before the initialization of
247
261
``pyfakefs ``, it will not work properly, because the ``pyfakefs ``
248
262
initialization 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.
253
266
If you still want to use ``mock_open ``, make sure it is only used while
254
267
patching is in progress. For example, if you are using ``pytest `` with the
255
268
``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:
266
279
# works correctly
267
280
mocker.patch(" builtins.open" , mocker.mock_open(read_data = " content" ))
268
281
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:
276
318
277
319
.. code :: python
278
320
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))
281
331
282
332
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)
286
336
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.
292
339
293
340
Pathlib.Path objects created outside of tests
294
341
---------------------------------------------
0 commit comments