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