1Troubleshooting 2=============== 3This is a collection of problems with ``pyfakefs`` and possible solutions. 4It will be expanded continuously based on issues and problems found by users. 5 6Modules not working with pyfakefs 7--------------------------------- 8 9Modules may not work with ``pyfakefs`` for several reasons. ``pyfakefs`` 10works by patching some file system related modules and functions, specifically: 11 12- most file system related functions in the ``os`` and ``os.path`` modules 13- the ``pathlib`` module 14- the built-in ``open`` function and ``io.open`` 15- ``shutil.disk_usage`` 16 17Other file system related modules work with ``pyfakefs``, because they use 18exclusively these patched functions, specifically ``shutil`` (except for 19``disk_usage``), ``tempfile``, ``glob`` and ``zipfile``. 20 21A module may not work with ``pyfakefs`` because of one of the following 22reasons: 23 24- It uses a file system related function of the mentioned modules that is 25 not or not correctly patched. Mostly these are functions that are seldom 26 used, but may be used in Python libraries (this has happened for example 27 with a changed implementation of ``shutil`` in Python 3.7). Generally, 28 these shall be handled in issues and we are happy to fix them. 29- It uses file system related functions in a way that will not be patched 30 automatically. This is the case for functions that are executed while 31 reading a module. This case and a possibility to make them work is 32 documented above under ``modules_to_reload``. 33- It uses OS specific file system functions not contained in the Python 34 libraries. These will not work out of the box, and we generally will not 35 support them in ``pyfakefs``. If these functions are used in isolated 36 functions or classes, they may be patched by using the ``modules_to_patch`` 37 parameter (see the example for file locks in Django above), or by using 38 ``unittest.patch`` if you don't need to simulate the functions. We 39 added some of these patches to ``pyfakefs``, so that they are applied 40 automatically (currently done for some ``pandas`` and ``Django`` 41 functionality). 42- It uses C libraries to access the file system. There is no way no make 43 such a module work with ``pyfakefs``--if you want to use it, you 44 have to patch the whole module. In some cases, a library implemented in 45 Python with a similar interface already exists. An example is ``lxml``, 46 which can be substituted with ``ElementTree`` in most cases for testing. 47 48A list of Python modules that are known to not work correctly with 49``pyfakefs`` will be collected here: 50 51`multiprocessing`_ (built-in) 52~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 53This module has several issues (related to points 1 and 3 above). 54Currently there are no plans to fix this, but this may change in case of 55sufficient demand. 56 57`subprocess`_ (built-in) 58~~~~~~~~~~~~~~~~~~~~~~~~ 59This has very similar problems to ``multiprocessing`` and cannot be used with 60``pyfakefs`` to start a process. ``subprocess`` can either be mocked, if 61the process is not needed for the test, or patching can be paused to start 62a process if needed, and resumed afterwards 63(see `this issue <https://github.com/pytest-dev/pyfakefs/issues/447>`__). 64 65Modules that rely on ``subprocess`` or ``multiprocessing`` 66~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 67This includes a number of modules that need to start other executables to 68function correctly. Examples that have shown this problem include `GitPython`_ 69and `plumbum`_. Calling ``find_library`` also uses ``subprocess`` and does not work in 70the fake filesystem. 71 72`sqlite3`_ (built-in) 73~~~~~~~~~~~~~~~~~~~~~~~~ 74This is a database adapter written in C, which uses the database C API to access files. 75This (and similar database adapters) will not work with ``pyfakefs``, as it will always 76access the real filesystem. 77 78The `Pillow`_ Imaging Library 79~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 80This library partly works with ``pyfakefs``, but it is known to not work at 81least if writing JPEG files 82(see `this issue <https://github.com/pytest-dev/pyfakefs/issues/529>`__) 83 84The `pandas`_ data analysis toolkit 85~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 86This uses its own internal file system access written in C, thus much of 87``pandas`` will not work with ``pyfakefs`` out of the box. Having said that, 88``pyfakefs`` patches ``pandas`` to use standard file-system access instead, 89so that many of the ``read_xxx`` functions, including ``read_csv`` and 90``read_excel``, as well as some writer functions, do work with the fake file 91system. If you use only these functions, ``pyfakefs`` should work fine with 92``pandas``. 93 94`xlrd`_ 95~~~~~~~ 96This library is used by ``pandas`` to read Excel files in the `.xls` format, 97and can also be used stand-alone. Similar to ``pandas``, it is by default 98patched by ``pyfakefs`` to use normal file system functions that can be 99patched. 100 101`openpyxl`_ 102~~~~~~~~~~~ 103This is another library that reads and writes Excel files, and is also 104used by ``pandas`` if installed. ``openpyxl`` uses ``lxml`` for some file-system 105access if it is installed--in this case ``pyfakefs`` will not be able to patch 106it correctly (``lxml`` uses C functions for file system access). It will `not` 107use ``lxml`` however, if the environment variable ``OPENPYXL_LXML`` is set to 108"False" (or anything other than "True"), so if you set this variable `before` 109running the tests, it can work fine with ``pyfakefs``. 110 111If you encounter a module not working with ``pyfakefs``, and you are not sure 112if the module can be handled or how to do it, please write a new issue. We 113will check if it can be made to work, and at least add it to this list. 114 115Pyfakefs behaves differently than the real filesystem 116----------------------------------------------------- 117There are at least the following kinds of deviations from the actual behavior: 118 119- unwanted deviations that we didn't notice--if you find any of these, please 120 write an issue and we will try to fix it 121- behavior that depends on different OS versions and editions--as mentioned 122 in :ref:`limitations`, ``pyfakefs`` uses the systems used for CI tests in 123 GitHub Actions as reference system and will not replicate all system-specific behavior 124- behavior that depends on low-level OS functionality that ``pyfakefs`` is not 125 able to emulate; examples are the ``fcntl.ioctl`` and ``fcntl.fcntl`` 126 functions that are patched to do nothing 127 128The test code tries to access files in the real filesystem 129---------------------------------------------------------- 130The loading of the actual Python code from the real filesystem does not use 131the filesystem functions that ``pyfakefs`` patches, but in some cases it may 132access other files in the packages. An example is loading timezone information 133from configuration files. In these cases, you have to map the respective files 134or directories from the real into the fake filesystem as described in 135:ref:`real_fs_access`. 136 137If you are using Django, various dependencies may expect both the project 138directory and the ``site-packages`` installation to exist in the fake filesystem. 139 140Here's an example of how to add these using pytest:: 141 142 143 import os 144 import django 145 import pytest 146 147 @pytest.fixture 148 def fake_fs(fs): 149 PROJECT_BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 150 fs.add_real_paths( 151 [ 152 PROJECT_BASE_DIR, 153 os.path.dirname(django.__file__), 154 ] 155 ) 156 return fs 157 158OS temporary directories 159------------------------ 160Tests relying on a completely empty file system on test start will fail. 161As ``pyfakefs`` does not fake the ``tempfile`` module (as described above), 162a temporary directory is required to ensure that ``tempfile`` works correctly, 163e.g., that ``tempfile.gettempdir()`` will return a valid value. This 164means that any newly created fake file system will always have either a 165directory named ``/tmp`` when running on Linux or Unix systems, 166``/var/folders/<hash>/T`` when running on macOS, or 167``C:\Users\<user>\AppData\Local\Temp`` on Windows: 168 169.. code:: python 170 171 import os 172 173 174 def test_something(fs): 175 # the temp directory is always present at test start 176 assert len(os.listdir("/")) == 1 177 178Under macOS and linux, if the actual temp path is not `/tmp` (which is always the case 179under macOS), a symlink to the actual temp directory is additionally created as `/tmp` 180in the fake filesystem. Note that the file size of this link is ignored while 181calculating the fake filesystem size, so that the used size with an otherwise empty 182fake filesystem can always be assumed to be 0. 183 184 185User rights 186----------- 187If you run ``pyfakefs`` tests as root (this happens by default if run in a 188docker container), ``pyfakefs`` also behaves as a root user, for example can 189write to write-protected files. This may not be the expected behavior, and 190can be changed. 191``Pyfakefs`` has a rudimentary concept of user rights, which differentiates 192between root user (with the user id 0) and any other user. By default, 193``pyfakefs`` assumes the user id of the current user, but you can change 194that using ``pyfakefs.helpers.set_uid()`` in your setup. This allows to run 195tests as non-root user in a root user environment and vice verse. 196Another possibility to run tests as non-root user in a root user environment 197is the convenience argument :ref:`allow_root_user`: 198 199.. code:: python 200 201 from pyfakefs.fake_filesystem_unittest import TestCase 202 203 204 class SomeTest(TestCase): 205 def setUp(self): 206 self.setUpPyfakefs(allow_root_user=False) 207 208 209.. _usage_with_mock_open: 210 211Pyfakefs and mock_open 212---------------------- 213If you patch ``open`` using ``mock_open`` before the initialization of 214``pyfakefs``, it will not work properly, because the ``pyfakefs`` 215initialization relies on ``open`` working correctly. 216Generally, you should not need ``mock_open`` if using ``pyfakefs``, because you 217always can create the files with the needed content using ``create_file``. 218This is true for patching any filesystem functions--avoid patching them 219while working with ``pyfakefs``. 220If you still want to use ``mock_open``, make sure it is only used while 221patching is in progress. For example, if you are using ``pytest`` with the 222``mocker`` fixture used to patch ``open``, make sure that the ``fs`` fixture is 223passed before the ``mocker`` fixture to ensure this: 224 225.. code:: python 226 227 def test_mock_open_incorrect(mocker, fs): 228 # causes a recursion error 229 mocker.patch("builtins.open", mocker.mock_open(read_data="content")) 230 231 232 def test_mock_open_correct(fs, mocker): 233 # works correctly 234 mocker.patch("builtins.open", mocker.mock_open(read_data="content")) 235 236 237.. _`multiprocessing`: https://docs.python.org/3/library/multiprocessing.html 238.. _`subprocess`: https://docs.python.org/3/library/subprocess.html 239.. _`sqlite3`: https://docs.python.org/3/library/sqlite3.html 240.. _`GitPython`: https://pypi.org/project/GitPython/ 241.. _`plumbum`: https://pypi.org/project/plumbum/ 242.. _`Pillow`: https://pypi.org/project/Pillow/ 243.. _`pandas`: https://pypi.org/project/pandas/ 244.. _`xlrd`: https://pypi.org/project/xlrd/ 245.. _`openpyxl`: https://pypi.org/project/openpyxl/ 246