• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Usage
2=====
3
4Test Scenarios
5--------------
6There are several approaches for implementing tests using ``pyfakefs``.
7
8Patch using fake_filesystem_unittest
9~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10If you are using the Python ``unittest`` package, the easiest approach is to
11use test classes derived from ``fake_filesystem_unittest.TestCase``.
12
13If you call ``setUpPyfakefs()`` in your ``setUp()``, ``pyfakefs`` will
14automatically find all real file functions and modules, and stub these out
15with the fake file system functions and modules:
16
17.. code:: python
18
19    from pyfakefs.fake_filesystem_unittest import TestCase
20
21    class ExampleTestCase(TestCase):
22        def setUp(self):
23            self.setUpPyfakefs()
24
25        def test_create_file(self):
26            file_path = '/test/file.txt'
27            self.assertFalse(os.path.exists(file_path))
28            self.fs.create_file(file_path)
29            self.assertTrue(os.path.exists(file_path))
30
31The usage is explained in more detail in :ref:`auto_patch` and
32demonstrated in the files `example.py`_ and `example_test.py`_.
33
34Patch using the pytest plugin
35~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36If you use `pytest`_, you will be interested in the pytest plugin in
37``pyfakefs``.
38This automatically patches all file system functions and modules in a
39similar manner as described above.
40
41The pytest plugin provides the ``fs`` fixture for use in your test. The plugin
42is registered for pytest on installing ``pyfakefs`` as usual for pytest
43plugins, so you can just use it:
44
45.. code:: python
46
47   def my_fakefs_test(fs):
48       # "fs" is the reference to the fake file system
49       fs.create_file('/var/data/xx1.txt')
50       assert os.path.exists('/var/data/xx1.txt')
51
52If you are bothered by the ``pylint`` warning,
53``C0103: Argument name "fs" doesn't conform to snake_case naming style
54(invalid-name)``,
55you can define a longer name in your ``conftest.py`` and use that in your
56tests:
57
58.. code:: python
59
60    @pytest.fixture
61    def fake_filesystem(fs):  # pylint:disable=invalid-name
62        """Variable name 'fs' causes a pylint warning. Provide a longer name
63        acceptable to pylint for use in tests.
64        """
65        yield fs
66
67
68Patch using fake_filesystem_unittest.Patcher
69~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
70If you are using other means of testing like `nose`_,
71you can do the patching using ``fake_filesystem_unittest.Patcher``--the class
72doing the actual work of replacing the filesystem modules with the fake modules
73in the first two approaches.
74
75The easiest way is to just use ``Patcher`` as a context manager:
76
77.. code:: python
78
79   from pyfakefs.fake_filesystem_unittest import Patcher
80
81   with Patcher() as patcher:
82       # access the fake_filesystem object via patcher.fs
83       patcher.fs.create_file('/foo/bar', contents='test')
84
85       # the following code works on the fake filesystem
86       with open('/foo/bar') as f:
87           contents = f.read()
88
89You can also initialize ``Patcher`` manually:
90
91.. code:: python
92
93   from pyfakefs.fake_filesystem_unittest import Patcher
94
95   patcher = Patcher()
96   patcher.setUp()     # called in the initialization code
97   ...
98   patcher.tearDown()  # somewhere in the cleanup code
99
100Patch using fake_filesystem_unittest.patchfs decorator
101~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102This is basically a convenience wrapper for the previous method.
103If you are not using ``pytest`` and  want to use the fake filesystem for a
104single function, you can write:
105
106.. code:: python
107
108   from pyfakefs.fake_filesystem_unittest import patchfs
109
110   @patchfs
111   def test_something(fake_fs):
112       # access the fake_filesystem object via fake_fs
113       fake_fs.create_file('/foo/bar', contents='test')
114
115Note that ``fake_fs`` is a positional argument and the argument name does
116not matter. If there are additional ``mock.patch`` decorators that also
117create positional arguments, the argument order is the same as the decorator
118order, as shown here:
119
120.. code:: python
121
122   @patchfs
123   @mock.patch('foo.bar')
124   def test_something(fake_fs, mocked_bar):
125       ...
126
127   @mock.patch('foo.bar')
128   @patchfs
129   def test_something(mocked_bar, fake_fs):
130       ...
131
132.. note::
133  Avoid writing the ``patchfs`` decorator *between* ``mock.patch`` operators,
134  as the order will not be what you expect. Due to implementation details,
135  all arguments created by ``mock.patch`` decorators are always expected to
136  be contiguous, regardless of other decorators positioned between them.
137
138.. caution::
139  In previous versions, the keyword argument `fs` has been used instead,
140  which had to be positioned *after* all positional arguments regardless of
141  the decorator order. If you upgrade from a version before pyfakefs 4.2,
142  you may have to adapt the argument order.
143
144You can also use this to make a single unit test use the fake fs:
145
146.. code:: python
147
148    class TestSomething(unittest.TestCase):
149
150        @patchfs
151        def test_something(self, fs):
152            fs.create_file('/foo/bar', contents='test')
153
154
155.. _customizing_patcher:
156
157Customizing patching
158--------------------
159
160``fake_filesystem_unittest.Patcher`` provides a few arguments to adapt
161patching for cases where it does not work out of the box. These arguments
162can also be used with ``unittest`` and ``pytest``.
163
164Using custom arguments
165~~~~~~~~~~~~~~~~~~~~~~
166The following sections describe how to apply these arguments in different
167scenarios, using the argument :ref:`allow_root_user` as an example.
168
169Patcher
170.......
171If you use the ``Patcher`` directly, you can just pass the arguments in the
172constructor:
173
174.. code:: python
175
176  from pyfakefs.fake_filesystem_unittest import Patcher
177
178  with Patcher(allow_root_user=False) as patcher:
179      ...
180
181Unittest
182........
183If you are using ``fake_filesystem_unittest.TestCase``, the arguments can be
184passed to ``setUpPyfakefs()``, which will pass them to the ``Patcher``
185instance:
186
187.. code:: python
188
189  from pyfakefs.fake_filesystem_unittest import TestCase
190
191  class SomeTest(TestCase):
192      def setUp(self):
193          self.setUpPyfakefs(allow_root_user=False)
194
195      def testSomething(self):
196          ...
197
198Pytest
199......
200
201In case of ``pytest``, you have two possibilities:
202
203- The standard way to customize the ``fs`` fixture is to write your own
204  fixture which uses the ``Patcher`` with arguments as has been shown above:
205
206.. code:: python
207
208  import pytest
209  from pyfakefs.fake_filesystem_unittest import Patcher
210
211  @pytest.fixture
212  def fs_no_root():
213      with Patcher(allow_root_user=False) as patcher:
214          yield patcher.fs
215
216  def test_something(fs_no_root):
217      ...
218
219- You can also pass the arguments using ``@pytest.mark.parametrize``. Note that
220  you have to provide `all Patcher arguments`_ before the needed ones, as
221  keyword arguments cannot be used, and you have to add ``indirect=True``.
222  This makes it less readable, but gives you a quick possibility to adapt a
223  single test:
224
225.. code:: python
226
227  import pytest
228
229  @pytest.mark.parametrize('fs', [[None, None, None, False]], indirect=True)
230  def test_something(fs):
231      ...
232
233
234patchfs
235.......
236If you use the ``patchfs`` decorator, you can pass the arguments directly to
237the decorator:
238
239.. code:: python
240
241  from pyfakefs.fake_filesystem_unittest import patchfs
242
243  @patchfs(allow_root_user=False)
244  def test_something(fake_fs):
245      ...
246
247
248List of custom arguments
249~~~~~~~~~~~~~~~~~~~~~~~~
250
251Following is a description of the optional arguments that can be used to
252customize ``pyfakefs``.
253
254.. _modules_to_reload:
255
256modules_to_reload
257.................
258``Pyfakefs`` patches modules that are imported before starting the test by
259finding and replacing file system modules in all loaded modules at test
260initialization time.
261This allows to automatically patch file system related modules that are:
262
263- imported directly, for example:
264
265.. code:: python
266
267  import os
268  import pathlib.Path
269
270- imported as another name:
271
272.. code:: python
273
274  import os as my_os
275
276- imported using one of these two specially handled statements:
277
278.. code:: python
279
280  from os import path
281  from pathlib import Path
282
283Additionally, functions from file system related modules are patched
284automatically if imported like:
285
286.. code:: python
287
288  from os.path import exists
289  from os import stat
290
291This also works if importing the functions as another name:
292
293.. code:: python
294
295  from os.path import exists as my_exists
296  from io import open as io_open
297  from builtins import open as bltn_open
298
299There are a few cases where automatic patching does not work. We know of at
300least two specific cases where this is the case:
301
302Initializing a default argument with a file system function is not patched
303automatically due to performance reasons (though it can be switched on using
304:ref:`patch_default_args`):
305
306.. code:: python
307
308  import os
309
310  def check_if_exists(filepath, file_exists=os.path.exists):
311      return file_exists(filepath)
312
313
314If initializing a global variable using a file system function, the
315initialization will be done using the real file system:
316
317.. code:: python
318
319  from pathlib import Path
320
321  path = Path("/example_home")
322
323In this case, ``path`` will hold the real file system path inside the test.
324The same is true, if a file system function is used in a decorator (this is
325an example from a related issue):
326
327.. code:: python
328
329  import pathlib
330
331  @click.command()
332  @click.argument('foo', type=click.Path(path_type=pathlib.Path))
333  def hello(foo):
334      pass
335
336To get these cases to work as expected under test, the respective modules
337containing the code shall be added to the ``modules_to_reload`` argument (a
338module list).
339The passed modules will be reloaded, thus allowing ``pyfakefs`` to patch them
340dynamically. All modules loaded after the initial patching described above
341will be patched using this second mechanism.
342
343Given that the example function ``check_if_exists`` shown above is located in
344the file ``example/sut.py``, the following code will work:
345
346.. code:: python
347
348  import example
349
350  # example using unittest
351  class ReloadModuleTest(fake_filesystem_unittest.TestCase):
352      def setUp(self):
353          self.setUpPyfakefs(modules_to_reload=[example.sut])
354
355      def test_path_exists(self):
356          file_path = '/foo/bar'
357          self.fs.create_dir(file_path)
358          self.assertTrue(example.sut.check_if_exists(file_path))
359
360  # example using pytest
361  @pytest.mark.parametrize('fs', [[None, [example.sut]]], indirect=True)
362  def test_path_exists(fs):
363      file_path = '/foo/bar'
364      fs.create_dir(file_path)
365      assert example.sut.check_if_exists(file_path)
366
367  # example using Patcher
368  def test_path_exists():
369      with Patcher(modules_to_reload=[example.sut]) as patcher:
370        file_path = '/foo/bar'
371        patcher.fs.create_dir(file_path)
372        assert example.sut.check_if_exists(file_path)
373
374  # example using patchfs decorator
375  @patchfs(modules_to_reload=[example.sut])
376  def test_path_exists(fs):
377      file_path = '/foo/bar'
378      fs.create_dir(file_path)
379      assert example.sut.check_if_exists(file_path)
380
381
382modules_to_patch
383................
384Sometimes there are file system modules in other packages that are not
385patched in standard ``pyfakefs``. To allow patching such modules,
386``modules_to_patch`` can be used by adding a fake module implementation for
387a module name. The argument is a dictionary of fake modules mapped to the
388names to be faked.
389
390This mechanism is used in ``pyfakefs`` itself to patch the external modules
391`pathlib2` and `scandir` if present, and the following example shows how to
392fake a module in Django that uses OS file system functions (note that this
393has now been been integrated into ``pyfakefs``):
394
395.. code:: python
396
397  class FakeLocks:
398      """django.core.files.locks uses low level OS functions, fake it."""
399      _locks_module = django.core.files.locks
400
401      def __init__(self, fs):
402          """Each fake module expects the fake file system as an __init__
403          parameter."""
404          # fs represents the fake filesystem; for a real example, it can be
405          # saved here and used in the implementation
406          pass
407
408      @staticmethod
409      def lock(f, flags):
410          return True
411
412      @staticmethod
413      def unlock(f):
414          return True
415
416      def __getattr__(self, name):
417          return getattr(self._locks_module, name)
418
419  ...
420  # test code using Patcher
421  with Patcher(modules_to_patch={'django.core.files.locks': FakeLocks}):
422      test_django_stuff()
423
424  # test code using unittest
425  class TestUsingDjango(fake_filesystem_unittest.TestCase):
426      def setUp(self):
427          self.setUpPyfakefs(modules_to_patch={'django.core.files.locks': FakeLocks})
428
429      def test_django_stuff(self)
430          ...
431
432  # test code using pytest
433  @pytest.mark.parametrize('fs', [[None, None,
434    {'django.core.files.locks': FakeLocks}]], indirect=True)
435  def test_django_stuff(fs):
436      ...
437
438  # test code using patchfs decorator
439  @patchfs(modules_to_patch={'django.core.files.locks': FakeLocks})
440  def test_django_stuff(fake_fs):
441      ...
442
443additional_skip_names
444.....................
445This may be used to add modules that shall not be patched. This is mostly
446used to avoid patching the Python file system modules themselves, but may be
447helpful in some special situations, for example if a testrunner needs to access
448the file system after test setup. To make this possible, the affected module
449can be added to ``additional_skip_names``:
450
451.. code:: python
452
453  with Patcher(additional_skip_names=['pydevd']) as patcher:
454      patcher.fs.create_file('foo')
455
456Alternatively to the module names, the modules themselves may be used:
457
458.. code:: python
459
460  import pydevd
461
462  with Patcher(additional_skip_names=[pydevd]) as patcher:
463      patcher.fs.create_file('foo')
464
465.. _allow_root_user:
466
467allow_root_user
468...............
469This is ``True`` by default, meaning that the user is considered a root user
470if the real user is a root user (e.g. has the user ID 0). If you want to run
471your tests as a non-root user regardless of the actual user rights, you may
472want to set this to ``False``.
473
474use_known_patches
475.................
476Some libraries are known to require patching in order to work with
477``pyfakefs``.
478If ``use_known_patches`` is set to ``True`` (the default), ``pyfakefs`` patches
479these libraries so that they will work with the fake filesystem. Currently, this
480includes patches for ``pandas`` read methods like ``read_csv`` and
481``read_excel``, and for ``Django`` file locks--more may follow. Ordinarily,
482the default value of ``use_known_patches`` should be used, but it is present
483to allow users to disable this patching in case it causes any problems. It
484may be removed or replaced by more fine-grained arguments in future releases.
485
486patch_open_code
487...............
488Since Python 3.8, the ``io`` module has the function ``open_code``, which
489opens a file read-only and is used to open Python code files. By default, this
490function is not patched, because the files it opens usually belong to the
491executed library code and are not present in the fake file system.
492Under some circumstances, this may not be the case, and the opened file
493lives in the fake filesystem. For these cases, you can set ``patch_open_code``
494to ``PatchMode.ON``. If you just want to patch ``open_case`` for files that
495live in the fake filesystem, and use the real function for the rest, you can
496set ``patch_open_code`` to ``PatchMode.AUTO``:
497
498.. code:: python
499
500  from pyfakefs.fake_filesystem_unittest import PatchMode
501
502  @patchfs(patch_open_code=PatchMode.AUTO)
503  def test_something(fs):
504      ...
505
506.. note:: This argument is subject to change or removal in future
507  versions of ``pyfakefs``, depending on the upcoming use cases.
508
509.. _patch_default_args:
510
511patch_default_args
512..................
513As already mentioned, a default argument that is initialized with a file
514system function is not patched automatically:
515
516.. code:: python
517
518  import os
519
520  def check_if_exists(filepath, file_exists=os.path.exists):
521      return file_exists(filepath)
522
523As this is rarely needed, and the check to patch this automatically is quite
524expansive, it is not done by default. Using ``patch_default_args`` will
525search for this kind of default arguments and patch them automatically.
526You could also use the :ref:`modules_to_reload` option with the module that
527contains the default argument instead, if you want to avoid the overhead.
528
529use_cache
530.........
531If True (the default), patched and non-patched modules are cached between tests
532to avoid the performance hit of the file system function lookup (the
533patching itself is reverted after each test). As this is a new
534feature, this argument allows to turn it off in case it causes any problems:
535
536.. code:: python
537
538  @patchfs(use_cache=False)
539  def test_something(fake_fs):
540      fake_fs.create_file("foo", contents="test")
541      ...
542
543Please write an issue if you encounter any problem that can be fixed by using
544this parameter. Note that this argument may be removed in a later version, if
545no problems come up.
546
547If you want to clear the cache just for a specific test instead, you can call
548``clear_cache`` on the ``Patcher`` or the ``fake_filesystem`` instance:
549
550.. code:: python
551
552  def test_something(fs):  # using pytest fixture
553      fs.clear_cache()
554      ...
555
556
557Using convenience methods
558-------------------------
559While ``pyfakefs`` can be used just with the standard Python file system
560functions, there are few convenience methods in ``fake_filesystem`` that can
561help you setting up your tests. The methods can be accessed via the
562``fake_filesystem`` instance in your tests: ``Patcher.fs``, the ``fs``
563fixture in pytest, ``TestCase.fs`` for ``unittest``, and the ``fs`` argument
564for the ``patchfs`` decorator.
565
566File creation helpers
567~~~~~~~~~~~~~~~~~~~~~
568To create files, directories or symlinks together with all the directories
569in the path, you may use ``create_file()``, ``create_dir()``,
570``create_symlink()`` and ``create_link()``, respectively.
571
572``create_file()`` also allows you to set the file mode and the file contents
573together with the encoding if needed. Alternatively, you can define a file
574size without contents--in this case, you will not be able to perform
575standard I\O operations on the file (may be used to fill up the file system
576with large files, see also :ref:`set-fs-size`).
577
578.. code:: python
579
580    from pyfakefs.fake_filesystem_unittest import TestCase
581
582    class ExampleTestCase(TestCase):
583        def setUp(self):
584            self.setUpPyfakefs()
585
586        def test_create_file(self):
587            file_path = '/foo/bar/test.txt'
588            self.fs.create_file(file_path, contents = 'test')
589            with open(file_path) as f:
590                self.assertEqual('test', f.read())
591
592``create_dir()`` behaves like ``os.makedirs()``.
593``create_symlink`` and ``create_link`` behave like ``os.symlink`` and
594``os.link``, with any missing parent directories of the link created
595automatically.
596
597.. caution::
598  The first two arguments in ``create_symlink`` are reverted in relation to
599  ``os.symlink`` for historical reasons.
600
601Access to files in the real file system
602~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
603If you want to have read access to real files or directories, you can map
604them into the fake file system using ``add_real_file()``,
605``add_real_directory()``, ``add_real_symlink()`` and ``add_real_paths()``.
606They take a file path, a directory path, a symlink path, or a list of paths,
607respectively, and make them accessible from the fake file system. By
608default, the contents of the mapped files and directories are read only on
609demand, so that mapping them is relatively cheap. The access to the files is
610by default read-only, but even if you add them using ``read_only=False``,
611the files are written only in the fake system (e.g. in memory). The real
612files are never changed.
613
614``add_real_file()``, ``add_real_directory()`` and ``add_real_symlink()`` also
615allow you to map a file or a directory tree into another location in the
616fake filesystem via the argument ``target_path``.
617
618.. code:: python
619
620    from pyfakefs.fake_filesystem_unittest import TestCase
621
622    class ExampleTestCase(TestCase):
623
624        fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
625        def setUp(self):
626            self.setUpPyfakefs()
627            # make the file accessible in the fake file system
628            self.fs.add_real_directory(self.fixture_path)
629
630        def test_using_fixture1(self):
631            with open(os.path.join(self.fixture_path, 'fixture1.txt') as f:
632                # file contents are copied to the fake file system
633                # only at this point
634                contents = f.read()
635
636You can do the same using ``pytest`` by using a fixture for test setup:
637
638.. code:: python
639
640    import pytest
641    import os
642
643    fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
644
645    @pytest.fixture
646    def my_fs(fs):
647        fs.add_real_directory(fixture_path)
648        yield fs
649
650    def test_using_fixture1(my_fs):
651        with open(os.path.join(fixture_path, 'fixture1.txt') as f:
652            contents = f.read()
653
654When using ``pytest`` another option is to load the contents of the real file
655in a fixture and pass this fixture to the test function **before** passing
656the ``fs`` fixture.
657
658.. code:: python
659
660    import pytest
661    import os
662
663    @pytest.fixture
664    def content():
665        fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
666        with open(os.path.join(fixture_path, 'fixture1.txt') as f:
667            contents = f.read()
668        return contents
669
670    def test_using_file_contents(content, fs):
671        fs.create_file("fake/path.txt")
672        assert content != ""
673
674
675Handling mount points
676~~~~~~~~~~~~~~~~~~~~~
677Under Linux and MacOS, the root path (``/``) is the only mount point created
678in the fake file system. If you need support for more mount points, you can add
679them using ``add_mount_point()``.
680
681Under Windows, drives and UNC paths are internally handled as mount points.
682Adding a file or directory on another drive or UNC path automatically
683adds a mount point for that drive or UNC path root if needed. Explicitly
684adding mount points shall not be needed under Windows.
685
686A mount point has a separate device ID (``st_dev``) under all systems, and
687some operations (like ``rename``) are not possible for files located on
688different mount points. The fake file system size (if used) is also set per
689mount point.
690
691.. _set-fs-size:
692
693Setting the file system size
694~~~~~~~~~~~~~~~~~~~~~~~~~~~~
695If you need to know the file system size in your tests (for example for
696testing cleanup scripts), you can set the fake file system size using
697``set_disk_usage()``. By default, this sets the total size in bytes of the
698root partition; if you add a path as parameter, the size will be related to
699the mount point (see above) the path is related to.
700
701By default, the size of the fake file system is set to 1 TB (which
702for most tests can be considered as infinite). As soon as you set a
703size, all files will occupy the space according to their size,
704and you may fail to create new files if the fake file system is full.
705
706.. code:: python
707
708    from pyfakefs.fake_filesystem_unittest import TestCase
709
710    class ExampleTestCase(TestCase):
711
712        def setUp(self):
713            self.setUpPyfakefs()
714            self.fs.set_disk_usage(100)
715
716        def test_disk_full(self):
717            with open('/foo/bar.txt', 'w') as f:
718                with self.assertRaises(OSError):
719                    f.write('a' * 200)
720                    f.flush()
721
722To get the file system size, you may use ``get_disk_usage()``, which is
723modeled after ``shutil.disk_usage()``.
724
725Suspending patching
726~~~~~~~~~~~~~~~~~~~
727Sometimes, you may want to access the real filesystem inside the test with
728no patching applied. This can be achieved by using the ``pause/resume``
729functions, which exist in ``fake_filesystem_unittest.Patcher``,
730``fake_filesystem_unittest.TestCase`` and ``fake_filesystem.FakeFilesystem``.
731There is also a context manager class ``fake_filesystem_unittest.Pause``
732which encapsulates the calls to ``pause()`` and ``resume()``.
733
734Here is an example that tests the usage with the ``pyfakefs`` pytest fixture:
735
736.. code:: python
737
738    from pyfakefs.fake_filesystem_unittest import Pause
739
740    def test_pause_resume_contextmanager(fs):
741        fake_temp_file = tempfile.NamedTemporaryFile()
742        assert os.path.exists(fake_temp_file.name)
743        fs.pause()
744        assert not os.path.exists(fake_temp_file.name)
745        real_temp_file = tempfile.NamedTemporaryFile()
746        assert os.path.exists(real_temp_file.name)
747        fs.resume()
748        assert not os.path.exists(real_temp_file.name)
749        assert os.path.exists(fake_temp_file.name)
750
751Here is the same code using a context manager:
752
753.. code:: python
754
755    from pyfakefs.fake_filesystem_unittest import Pause
756
757    def test_pause_resume_contextmanager(fs):
758        fake_temp_file = tempfile.NamedTemporaryFile()
759        assert os.path.exists(fake_temp_file.name)
760        with Pause(fs):
761            assert not os.path.exists(fake_temp_file.name)
762            real_temp_file = tempfile.NamedTemporaryFile()
763            assert os.path.exists(real_temp_file.name)
764        assert not os.path.exists(real_temp_file.name)
765        assert os.path.exists(fake_temp_file.name)
766
767Simulating other file systems
768~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
769``Pyfakefs`` supports Linux, MacOS and Windows operating systems. By default,
770the file system of the OS where the tests run is assumed, but it is possible
771to simulate other file systems to some extent. To set a specific file
772system, you can change ``pyfakefs.FakeFilesystem.os`` to one of
773``OSType.LINUX``, ``OSType.MACOS`` and ``OSType.WINDOWS``. On doing so, the
774behavior of ``pyfakefs`` is adapted to the respective file system. Note that
775setting this causes the fake file system to be reset, so you should call it
776before adding any files.
777
778Setting the ``os`` attributes changes a number of ``pyfakefs.FakeFilesystem``
779attributes, which can also be set separately if needed:
780
781  - ``is_windows_fs`` -  if ``True`` a Windows file system (NTFS) is assumed
782  - ``is_macos`` - if ``True`` and ``is_windows_fs`` is ``False``, the
783    standard MacOS file system (HFS+) is assumed
784  - if ``is_windows_fs`` and ``is_macos`` are ``False``, a Linux file system
785    (something like ext3) is assumed
786  - ``is_case_sensitive`` is set to ``True`` under Linux and to ``False``
787    under Windows and MacOS by default - you can change it to change the
788    respective behavior
789  - ``path_separator`` is set to ``\`` under Windows and to ``/`` under Posix,
790    ``alternative_path_separator`` is set to ``/`` under Windows and to
791    ``None`` under Posix--these can also be adapted if needed
792
793The following test works both under Windows and Linux:
794
795.. code:: python
796
797  from pyfakefs.fake_filesystem import OSType
798
799  def test_windows_paths(fs):
800      fs.os = OSType.WINDOWS
801      assert r"C:\foo\bar" == os.path.join('C:\\', 'foo', 'bar'))
802      assert os.path.splitdrive(r"C:\foo\bar") == ("C:", r"\foo\bar")
803      assert os.path.ismount("C:")
804
805Troubleshooting
806---------------
807
808Modules not working with pyfakefs
809~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
810
811Modules may not work with ``pyfakefs`` for several reasons. ``pyfakefs``
812works by patching some file system related modules and functions, specifically:
813
814- most file system related functions in the ``os`` and ``os.path`` modules
815- the ``pathlib`` module
816- the build-in ``open`` function and ``io.open``
817- ``shutil.disk_usage``
818
819Other file system related modules work with ``pyfakefs``, because they use
820exclusively these patched functions, specifically ``shutil`` (except for
821``disk_usage``), ``tempfile``, ``glob`` and ``zipfile``.
822
823A module may not work with ``pyfakefs`` because of one of the following
824reasons:
825
826- It uses a file system related function of the mentioned modules that is
827  not or not correctly patched. Mostly these are functions that are seldom
828  used, but may be used in Python libraries (this has happened for example
829  with a changed implementation of ``shutil`` in Python 3.7). Generally,
830  these shall be handled in issues and we are happy to fix them.
831- It uses file system related functions in a way that will not be patched
832  automatically. This is the case for functions that are executed while
833  reading a module. This case and a possibility to make them work is
834  documented above under ``modules_to_reload``.
835- It uses OS specific file system functions not contained in the Python
836  libraries. These will not work out of the box, and we generally will not
837  support them in ``pyfakefs``. If these functions are used in isolated
838  functions or classes, they may be patched by using the ``modules_to_patch``
839  parameter (see the example for file locks in Django above), or by using
840  ``unittest.patch`` if you don't need to simulate the functions. We
841  added some of these patches to ``pyfakefs``, so that they are applied
842  automatically (currently done for some ``pandas`` and ``Django``
843  functionality).
844- It uses C libraries to access the file system. There is no way no make
845  such a module work with ``pyfakefs``--if you want to use it, you
846  have to patch the whole module. In some cases, a library implemented in
847  Python with a similar interface already exists. An example is ``lxml``,
848  which can be substituted with ``ElementTree`` in most cases for testing.
849
850A list of Python modules that are known to not work correctly with
851``pyfakefs`` will be collected here:
852
853- `multiprocessing`_ has several issues (related to points 1 and 3 above).
854  Currently there are no plans to fix this, but this may change in case of
855  sufficient demand.
856- `subprocess`_ has very similar problems and cannot be used with
857  ``pyfakefs`` to start a process. ``subprocess`` can either be mocked, if
858  the process is not needed for the test, or patching can be paused to start
859  a process if needed, and resumed afterwards
860  (see `this issue <https://github.com/jmcgeheeiv/pyfakefs/issues/447>`__).
861- Modules that rely on ``subprocess`` or ``multiprocessing`` to work
862  correctly, e.g. need to start other executables. Examples that have shown
863  this problem include `GitPython`_ and `plumbum`_.
864- the `Pillow`_ image library does not work with pyfakefs at least if writing
865  JPEG files (see `this issue <https://github.com/jmcgeheeiv/pyfakefs/issues/529>`__)
866- `pandas`_ (the Python data analysis library) uses its own internal file
867  system access written in C. Thus much of ``pandas`` will not work with
868  ``pyfakefs``. Having said that, ``pyfakefs`` patches ``pandas`` so that many
869  of the ``read_xxx`` functions, including ``read_csv`` and ``read_excel``,
870  as well as some writer functions, do work with the fake file system. If
871  you use only these functions, ``pyfakefs`` will work with ``pandas``.
872
873If you are not sure if a module can be handled, or how to do it, you can
874always write a new issue, of course!
875
876Pyfakefs behaves differently than the real filesystem
877~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
878There are basically two kinds of deviations from the actual behavior:
879
880- unwanted deviations that we didn't notice--if you find any of these, please
881  write an issue and will try to fix it
882- behavior that depends on different OS versions and editions--as mentioned
883  in :ref:`limitations`, ``pyfakefs`` uses the TravisCI systems as reference
884  system and will not replicate all system-specific behavior
885
886OS temporary directories
887~~~~~~~~~~~~~~~~~~~~~~~~
888
889Tests relying on a completely empty file system on test start will fail.
890As ``pyfakefs`` does not fake the ``tempfile`` module (as described above),
891a temporary directory is required to ensure ``tempfile`` works correctly,
892e.g., that ``tempfile.gettempdir()`` will return a valid value. This
893means that any newly created fake file system will always have either a
894directory named ``/tmp`` when running on Linux or Unix systems,
895``/var/folders/<hash>/T`` when running on MacOs, or
896``C:\Users\<user>\AppData\Local\Temp`` on Windows.
897
898User rights
899~~~~~~~~~~~
900
901If you run ``pyfakefs`` tests as root (this happens by default if run in a
902docker container), ``pyfakefs`` also behaves as a root user, for example can
903write to write-protected files. This may not be the expected behavior, and
904can be changed.
905``Pyfakefs`` has a rudimentary concept of user rights, which differentiates
906between root user (with the user id 0) and any other user. By default,
907``pyfakefs`` assumes the user id of the current user, but you can change
908that using ``fake_filesystem.set_uid()`` in your setup. This allows to run
909tests as non-root user in a root user environment and vice verse.
910Another possibility to run tests as non-root user in a root user environment
911is the convenience argument :ref:`allow_root_user`.
912
913.. _usage_with_mock_open:
914
915Pyfakefs and mock_open
916~~~~~~~~~~~~~~~~~~~~~~
917If you patch ``open`` using ``mock_open`` before the initialization of
918``pyfakefs``, it will not work properly, because the ``pyfakefs``
919initialization relies on ``open`` working correctly.
920Generally, you should not need ``mock_open`` if using ``pyfakefs``, because you
921always can create the files with the needed content using ``create_file``.
922This is true for patching any filesystem functions - avoid patching them
923while working with ``pyfakefs``.
924If you still want to use ``mock_open``, make sure it is only used while
925patching is in progress. For example, if you are using ``pytest`` with the
926``mocker`` fixture used to patch ``open``, make sure that the ``fs`` fixture is
927passed before the ``mocker`` fixture to ensure this.
928
929.. _`example.py`: https://github.com/jmcgeheeiv/pyfakefs/blob/master/pyfakefs/tests/example.py
930.. _`example_test.py`: https://github.com/jmcgeheeiv/pyfakefs/blob/master/pyfakefs/tests/example_test.py
931.. _`pytest`: https://doc.pytest.org
932.. _`nose`: https://docs.nose2.io/en/latest/
933.. _`all Patcher arguments`: https://jmcgeheeiv.github.io/pyfakefs/master/modules.html#pyfakefs.fake_filesystem_unittest.Patcher
934.. _`multiprocessing`: https://docs.python.org/3/library/multiprocessing.html
935.. _`subprocess`: https://docs.python.org/3/library/subprocess.html
936.. _`GitPython`: https://pypi.org/project/GitPython/
937.. _`plumbum`: https://pypi.org/project/plumbum/
938.. _`Pillow`: https://pypi.org/project/Pillow/
939.. _`pandas`: https://pypi.org/project/pandas/