Skip to content

Commit

Permalink
Add some API links to the usage documentation
Browse files Browse the repository at this point in the history
- mention the return value of create_x methods more prominently
- add a note about global pathlib.Path objects to the troubleshooting section
  • Loading branch information
mrbean-bremen committed Aug 26, 2023
1 parent 979a878 commit e7ccd8c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 53 deletions.
4 changes: 2 additions & 2 deletions docs/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ Fake filesystem classes
-----------------------
.. autoclass:: pyfakefs.fake_filesystem.FakeFilesystem
:members: add_mount_point,
get_disk_usage, set_disk_usage,
get_disk_usage, set_disk_usage, change_disk_usage,
add_real_directory, add_real_file, add_real_symlink, add_real_paths,
create_dir, create_file, create_symlink,
create_dir, create_file, create_symlink, create_link,
get_object, pause, resume

.. autoclass:: pyfakefs.fake_file.FakeFile
Expand Down
24 changes: 24 additions & 0 deletions docs/troubleshooting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,30 @@ passed before the ``mocker`` fixture to ensure this:
# works correctly
mocker.patch("builtins.open", mocker.mock_open(read_data="content"))
Pathlib.Path objects created outside of tests
---------------------------------------------
An pattern which is more often seen with the increased usage of `pathlib` is the
creation of global `pathlib.Path` objects (instead of string paths) that are used
in the tests. As these objects are created in the real filesystem, they are not of the same
type as faked `pathlib.Path` objects, and both will always compare as not equal,
regardless of the path they point to:

.. code:: python
import pathlib
FOLDER = pathlib.Path(__file__).parent
FILE = FOLDER / "file.csv"
def test_one(fs):
fake_file = pathlib.Path(fs.create_file(FILE).path)
assert FILE == fake_file # fails, compares different objects
assert str(FILE) == str(fake_file) # succeeds, compares the actual paths
Generally, mixing objects in the real filesystem and the fake filesystem
is problematic and better avoided.


.. _`multiprocessing`: https://docs.python.org/3/library/multiprocessing.html
.. _`subprocess`: https://docs.python.org/3/library/subprocess.html
Expand Down
18 changes: 11 additions & 7 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -675,8 +675,10 @@ for the ``patchfs`` decorator.
File creation helpers
~~~~~~~~~~~~~~~~~~~~~
To create files, directories or symlinks together with all the directories
in the path, you may use ``create_file()``, ``create_dir()``,
``create_symlink()`` and ``create_link()``, respectively.
in the path, you may use :py:meth:`create_file()<pyfakefs.fake_filesystem.FakeFilesystem.create_file>`,
:py:meth:`create_dir()<pyfakefs.fake_filesystem.FakeFilesystem.create_dir>`,
:py:meth:`create_symlink()<pyfakefs.fake_filesystem.FakeFilesystem.create_symlink>` and
:py:meth:`create_link()<pyfakefs.fake_filesystem.FakeFilesystem.create_link>`, respectively.

``create_file()`` also allows you to set the file mode and the file contents
together with the encoding if needed. Alternatively, you can define a file
Expand Down Expand Up @@ -713,8 +715,10 @@ automatically.
Access to files in the real file system
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to have read access to real files or directories, you can map
them into the fake file system using ``add_real_file()``,
``add_real_directory()``, ``add_real_symlink()`` and ``add_real_paths()``.
them into the fake file system using :py:meth:`add_real_file()<pyfakefs.fake_filesystem.FakeFilesystem.add_real_file>`,
:py:meth:`add_real_directory()<pyfakefs.fake_filesystem.FakeFilesystem.add_real_directory>`,
:py:meth:`add_real_symlink()<pyfakefs.fake_filesystem.FakeFilesystem.add_real_symlink>` and
:py:meth:`add_real_paths()<pyfakefs.fake_filesystem.FakeFilesystem.add_real_paths>`.
They take a file path, a directory path, a symlink path, or a list of paths,
respectively, and make them accessible from the fake file system. By
default, the contents of the mapped files and directories are read only on
Expand Down Expand Up @@ -800,7 +804,7 @@ Handling mount points
~~~~~~~~~~~~~~~~~~~~~
Under Linux and macOS, the root path (``/``) is the only mount point created
in the fake file system. If you need support for more mount points, you can add
them using ``add_mount_point()``.
them using :py:meth:`add_mount_point()<pyfakefs.fake_filesystem.FakeFilesystem.add_mount_point>`.

Under Windows, drives and UNC paths are internally handled as mount points.
Adding a file or directory on another drive or UNC path automatically
Expand All @@ -818,7 +822,7 @@ Setting the file system size
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you need to know the file system size in your tests (for example for
testing cleanup scripts), you can set the fake file system size using
``set_disk_usage()``. By default, this sets the total size in bytes of the
:py:meth:`set_disk_usage()<pyfakefs.fake_filesystem.FakeFilesystem.set_disk_usage>`. By default, this sets the total size in bytes of the
root partition; if you add a path as parameter, the size will be related to
the mount point (see above) the path is related to.

Expand All @@ -843,7 +847,7 @@ and you may fail to create new files if the fake file system is full.
f.write("a" * 200)
f.flush()
To get the file system size, you may use ``get_disk_usage()``, which is
To get the file system size, you may use :py:meth:`get_disk_usage()<pyfakefs.fake_filesystem.FakeFilesystem.get_disk_usage>`, which is
modeled after ``shutil.disk_usage()``.

Suspending patching
Expand Down
104 changes: 60 additions & 44 deletions pyfakefs/fake_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ class FakeFilesystem:
is_windows_fs: `True` in a real or faked Windows file system.
is_macos: `True` under MacOS, or if we are faking it.
is_case_sensitive: `True` if a case-sensitive file system is assumed.
root: The root :py:class:`FakeDirectory` entry of the file system.
root: The root :py:class:`FakeDirectory<pyfakefs.fake_file.FakeDirectory>` entry
of the file system.
umask: The umask used for newly created files, see `os.umask`.
patcher: Holds the Patcher object if created from it. Allows access
to the patcher object if using the pytest fs fixture.
Expand Down Expand Up @@ -364,15 +365,15 @@ def _add_root_mount_point(self, total_size):
self.add_mount_point(mount_point, total_size)

def pause(self) -> None:
"""Pause the patching of the file system modules until `resume` is
"""Pause the patching of the file system modules until :py:meth:`resume` is
called. After that call, all file system calls are executed in the
real file system.
Calling pause() twice is silently ignored.
Calling `pause()` twice is silently ignored.
Only allowed if the file system object was created by a
Patcher object. This is also the case for the pytest `fs` fixture.
`Patcher` object. This is also the case for the pytest `fs` fixture.
Raises:
RuntimeError: if the file system was not created by a Patcher.
RuntimeError: if the file system was not created by a `Patcher`.
"""
if self.patcher is None:
raise RuntimeError(
Expand All @@ -382,7 +383,7 @@ def pause(self) -> None:
self.patcher.pause()

def resume(self) -> None:
"""Resume the patching of the file system modules if `pause` has
"""Resume the patching of the file system modules if :py:meth:`pause` has
been called before. After that call, all file system calls are
executed in the fake file system.
Does nothing if patching is not paused.
Expand Down Expand Up @@ -456,8 +457,8 @@ def add_mount_point(
total_size: The new total size of the added filesystem device
in bytes. Defaults to infinite size.
can_exist: If True, no error is raised if the mount point
already exists
can_exist: If `True`, no error is raised if the mount point
already exists.
Returns:
The newly created mount point dict.
Expand Down Expand Up @@ -581,7 +582,7 @@ def get_disk_usage(self, path: Optional[AnyStr] = None) -> Tuple[int, int, int]:
"""Return the total, used and free disk space in bytes as named tuple,
or placeholder values simulating unlimited space if not set.
.. note:: This matches the return value of shutil.disk_usage().
.. note:: This matches the return value of ``shutil.disk_usage()``.
Args:
path: The disk space is returned for the file system device where
Expand Down Expand Up @@ -642,7 +643,7 @@ def change_disk_usage(
st_dev: The device ID for the respective file system.
Raises:
OSError: if usage_change exceeds the free file system space
OSError: if `usage_change` exceeds the free file system space
"""
mount_point = self._mount_point_for_device(st_dev)
if mount_point:
Expand Down Expand Up @@ -1656,12 +1657,14 @@ def get_object(self, file_path: AnyPath, check_read_perm: bool = True) -> FakeFi
filesystem.
Args:
file_path: Specifies the target FakeFile object to retrieve.
file_path: Specifies the target
:py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object to retrieve.
check_read_perm: If True, raises OSError if a parent directory
does not have read permission
Returns:
The FakeFile object corresponding to `file_path`.
The :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object corresponding
to `file_path`.
Raises:
OSError: if the object is not found.
Expand Down Expand Up @@ -2034,16 +2037,18 @@ def make_string_path(self, path: AnyPath) -> AnyStr:
def create_dir(
self, directory_path: AnyPath, perm_bits: int = helpers.PERM_DEF
) -> FakeDirectory:
"""Create `directory_path`, and all the parent directories.
"""Create `directory_path` and all the parent directories, and return
the created :py:class:`FakeDirectory<pyfakefs.fake_file.FakeDirectory>` object.
Helper method to set up your test faster.
Args:
directory_path: The full directory path to create.
perm_bits: The permission bits as set by `chmod`.
perm_bits: The permission bits as set by ``chmod``.
Returns:
The newly created FakeDirectory object.
The newly created
:py:class:`FakeDirectory<pyfakefs.fake_file.FakeDirectory>` object.
Raises:
OSError: if the directory already exists.
Expand Down Expand Up @@ -2095,29 +2100,30 @@ def create_file(
side_effect: Optional[Callable] = None,
) -> FakeFile:
"""Create `file_path`, including all the parent directories along
the way.
the way, and return the created
:py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
This helper method can be used to set up tests more easily.
Args:
file_path: The path to the file to create.
st_mode: The stat constant representing the file type.
contents: the contents of the file. If not given and st_size is
None, an empty file is assumed.
st_mode: The `stat` constant representing the file type.
contents: the contents of the file. If not given and `st_size` is
`None`, an empty file is assumed.
st_size: file size; only valid if contents not given. If given,
the file is considered to be in "large file mode" and trying
to read from or write to the file will result in an exception.
create_missing_dirs: If `True`, auto create missing directories.
apply_umask: `True` if the current umask must be applied
on `st_mode`.
encoding: If `contents` is a unicode string, the encoding used
encoding: If `contents` is of type `str`, the encoding used
for serialization.
errors: The error mode used for encoding/decoding errors.
side_effect: function handle that is executed when file is written,
side_effect: function handle that is executed when the file is written,
must accept the file object as an argument.
Returns:
The newly created FakeFile object.
The newly created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
Raises:
OSError: if the file already exists.
Expand All @@ -2142,8 +2148,9 @@ def add_real_file(
target_path: Optional[AnyPath] = None,
) -> FakeFile:
"""Create `file_path`, including all the parent directories along the
way, for an existing real file. The contents of the real file are read
only on demand.
way, for an existing real file, and return the created
:py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
The contents of the real file are read only on demand.
Args:
source_path: Path to an existing file in the real file system
Expand All @@ -2154,7 +2161,7 @@ def add_real_file(
otherwise it is equal to `source_path`.
Returns:
the newly created FakeFile object.
the newly created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
Raises:
OSError: if the file does not exist in the real file system.
Expand All @@ -2181,9 +2188,10 @@ def add_real_file(
def add_real_symlink(
self, source_path: AnyPath, target_path: Optional[AnyPath] = None
) -> FakeFile:
"""Create a symlink at source_path (or target_path, if given). It will
point to the same path as the symlink on the real filesystem. Relative
symlinks will point relative to their new location. Absolute symlinks
"""Create a symlink at `source_path` (or `target_path`, if given) and return
the created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
It will point to the same path as the symlink on the real filesystem.
Relative symlinks will point relative to their new location. Absolute symlinks
will point to the same, absolute path as on the real filesystem.
Args:
Expand All @@ -2192,7 +2200,7 @@ def add_real_symlink(
filesystem, otherwise, the same as `source_path`.
Returns:
the newly created FakeFile object.
the newly created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
Raises:
OSError: if the directory does not exist in the real file system.
Expand Down Expand Up @@ -2220,7 +2228,9 @@ def add_real_directory(
target_path: Optional[AnyPath] = None,
) -> FakeDirectory:
"""Create a fake directory corresponding to the real directory at the
specified path. Add entries in the fake directory corresponding to
specified path, and return the created
:py:class:`FakeDirectory<pyfakefs.fake_file.FakeDirectory>` object.
Add entries in the fake directory corresponding to
the entries in the real directory. Symlinks are supported.
Args:
Expand All @@ -2240,7 +2250,8 @@ def add_real_directory(
the target directory is the same as `source_path`.
Returns:
the newly created FakeDirectory object.
the newly created
:py:class:`FakeDirectory<pyfakefs.fake_file.FakeDirectory>` object.
Raises:
OSError: if the directory does not exist in the real file system.
Expand Down Expand Up @@ -2295,18 +2306,18 @@ def add_real_paths(
lazy_dir_read: bool = True,
) -> None:
"""This convenience method adds multiple files and/or directories from
the real file system to the fake file system. See `add_real_file()` and
`add_real_directory()`.
the real file system to the fake file system. See :py:meth:`add_real_file` and
:py:meth:`add_real_directory`.
Args:
path_list: List of file and directory paths in the real file
system.
read_only: If set, all files and files under under the directories
read_only: If set, all files and files under the directories
are treated as read-only, e.g. a write access raises an
exception; otherwise, writing to the files changes the fake
files only as usually.
lazy_dir_read: Uses lazy reading of directory contents if set
(see `add_real_directory`)
(see :py:meth:`add_real_directory`)
Raises:
OSError: if any of the files and directories in the list
Expand Down Expand Up @@ -2415,16 +2426,18 @@ def create_symlink(
link_target: AnyPath,
create_missing_dirs: bool = True,
) -> FakeFile:
"""Create the specified symlink, pointed at the specified link target.
"""Create the specified symlink, pointed at the specified link target,
and return the created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object
representing the link.
Args:
file_path: path to the symlink to create
link_target: the target of the symlink
create_missing_dirs: If `True`, any missing parent directories of
file_path will be created
`file_path` will be created
Returns:
The newly created FakeFile object.
The newly created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object.
Raises:
OSError: if the symlink could not be created
Expand Down Expand Up @@ -2473,22 +2486,25 @@ def create_link(
follow_symlinks: bool = True,
create_missing_dirs: bool = True,
) -> FakeFile:
"""Create a hard link at new_path, pointing at old_path.
"""Create a hard link at `new_path`, pointing at `old_path`,
and return the created :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object
representing the link.
Args:
old_path: An existing link to the target file.
new_path: The destination path to create a new link at.
follow_symlinks: If False and old_path is a symlink, link the
follow_symlinks: If `False` and `old_path` is a symlink, link the
symlink instead of the object it points to.
create_missing_dirs: If `True`, any missing parent directories of
file_path will be created
`file_path` will be created
Returns:
The FakeFile object referred to by old_path.
The :py:class:`FakeFile<pyfakefs.fake_file.FakeFile>` object referred to
by `old_path`.
Raises:
OSError: if something already exists at new_path.
OSError: if old_path is a directory.
OSError: if something already exists at `new_path`.
OSError: if `old_path` is a directory.
OSError: if the parent directory doesn't exist.
"""
old_path_str = make_string_path(old_path)
Expand Down

0 comments on commit e7ccd8c

Please sign in to comment.