8181True
8282"""
8383
84+ import contextlib
85+ import dataclasses
8486import errno
8587import heapq
8688import os
122124 matching_string ,
123125 AnyPath ,
124126 AnyString ,
127+ WINDOWS_PROPERTIES ,
128+ POSIX_PROPERTIES ,
129+ FSType ,
125130)
126131
127132if sys .platform .startswith ("linux" ):
@@ -179,10 +184,6 @@ class FakeFilesystem:
179184 """Provides the appearance of a real directory tree for unit testing.
180185
181186 Attributes:
182- path_separator: The path separator, corresponds to `os.path.sep`.
183- alternative_path_separator: Corresponds to `os.path.altsep`.
184- is_windows_fs: `True` in a real or faked Windows file system.
185- is_macos: `True` under MacOS, or if we are faking it.
186187 is_case_sensitive: `True` if a case-sensitive file system is assumed.
187188 root: The root :py:class:`FakeDirectory<pyfakefs.fake_file.FakeDirectory>` entry
188189 of the file system.
@@ -217,12 +218,8 @@ def __init__(
217218 >>> filesystem = FakeFilesystem(path_separator='/')
218219
219220 """
220- self .path_separator : str = path_separator
221- self .alternative_path_separator : Optional [str ] = os .path .altsep
222221 self .patcher = patcher
223222 self .create_temp_dir = create_temp_dir
224- if path_separator != os .sep :
225- self .alternative_path_separator = None
226223
227224 # is_windows_fs can be used to test the behavior of pyfakefs under
228225 # Windows fs on non-Windows systems and vice verse;
@@ -235,7 +232,19 @@ def __init__(
235232
236233 # is_case_sensitive can be used to test pyfakefs for case-sensitive
237234 # file systems on non-case-sensitive systems and vice verse
238- self .is_case_sensitive : bool = not (self .is_windows_fs or self ._is_macos )
235+ self .is_case_sensitive : bool = not (self ._is_windows_fs or self ._is_macos )
236+
237+ # by default, we use the configured filesystem
238+ self .fs_type = FSType .DEFAULT
239+ base_properties = (
240+ WINDOWS_PROPERTIES if self ._is_windows_fs else POSIX_PROPERTIES
241+ )
242+ self .fs_properties = [
243+ dataclasses .replace (base_properties ),
244+ POSIX_PROPERTIES ,
245+ WINDOWS_PROPERTIES ,
246+ ]
247+ self .path_separator = path_separator
239248
240249 self .root : FakeDirectory
241250 self ._cwd = ""
@@ -262,21 +271,28 @@ def __init__(
262271
263272 @property
264273 def is_linux (self ) -> bool :
274+ """Returns `True` in a real or faked Linux file system."""
265275 return not self .is_windows_fs and not self .is_macos
266276
267277 @property
268278 def is_windows_fs (self ) -> bool :
269- return self ._is_windows_fs
279+ """Returns `True` in a real or faked Windows file system."""
280+ return self .fs_type == FSType .WINDOWS or (
281+ self .fs_type == FSType .DEFAULT and self ._is_windows_fs
282+ )
270283
271284 @is_windows_fs .setter
272285 def is_windows_fs (self , value : bool ) -> None :
273286 if self ._is_windows_fs != value :
274287 self ._is_windows_fs = value
288+ if value :
289+ self ._is_macos = False
275290 self .reset ()
276291 FakePathModule .reset (self )
277292
278293 @property
279294 def is_macos (self ) -> bool :
295+ """Returns `True` in a real or faked macOS file system."""
280296 return self ._is_macos
281297
282298 @is_macos .setter
@@ -286,6 +302,38 @@ def is_macos(self, value: bool) -> None:
286302 self .reset ()
287303 FakePathModule .reset (self )
288304
305+ @property
306+ def path_separator (self ) -> str :
307+ """Returns the path separator, corresponds to `os.path.sep`."""
308+ return self .fs_properties [self .fs_type .value ].sep
309+
310+ @path_separator .setter
311+ def path_separator (self , value : str ) -> None :
312+ self .fs_properties [0 ].sep = value
313+ if value != os .sep :
314+ self .alternative_path_separator = None
315+
316+ @property
317+ def alternative_path_separator (self ) -> Optional [str ]:
318+ """Returns the alternative path separator, corresponds to `os.path.altsep`."""
319+ return self .fs_properties [self .fs_type .value ].altsep
320+
321+ @alternative_path_separator .setter
322+ def alternative_path_separator (self , value : Optional [str ]) -> None :
323+ self .fs_properties [0 ].altsep = value
324+
325+ @property
326+ def devnull (self ) -> str :
327+ return self .fs_properties [self .fs_type .value ].devnull
328+
329+ @property
330+ def pathsep (self ) -> str :
331+ return self .fs_properties [self .fs_type .value ].pathsep
332+
333+ @property
334+ def line_separator (self ) -> str :
335+ return self .fs_properties [self .fs_type .value ].linesep
336+
289337 @property
290338 def cwd (self ) -> str :
291339 """Return the current working directory of the fake filesystem."""
@@ -334,8 +382,11 @@ def os(self, value: OSType) -> None:
334382 self ._is_windows_fs = value == OSType .WINDOWS
335383 self ._is_macos = value == OSType .MACOS
336384 self .is_case_sensitive = value == OSType .LINUX
337- self .path_separator = "\\ " if value == OSType .WINDOWS else "/"
338- self .alternative_path_separator = "/" if value == OSType .WINDOWS else None
385+ self .fs_type = FSType .DEFAULT
386+ base_properties = (
387+ WINDOWS_PROPERTIES if self ._is_windows_fs else POSIX_PROPERTIES
388+ )
389+ self .fs_properties [0 ] = base_properties
339390 self .reset ()
340391 FakePathModule .reset (self )
341392
@@ -358,6 +409,15 @@ def reset(self, total_size: Optional[int] = None, init_pathlib: bool = True):
358409
359410 fake_pathlib .init_module (self )
360411
412+ @contextlib .contextmanager
413+ def use_fs_type (self , fs_type : FSType ):
414+ old_fs_type = self .fs_type
415+ try :
416+ self .fs_type = fs_type
417+ yield
418+ finally :
419+ self .fs_type = old_fs_type
420+
361421 def _add_root_mount_point (self , total_size ):
362422 mount_point = "C:" if self .is_windows_fs else self .path_separator
363423 self ._cwd = mount_point
@@ -403,9 +463,6 @@ def clear_cache(self) -> None:
403463 if self .patcher :
404464 self .patcher .clear_cache ()
405465
406- def line_separator (self ) -> str :
407- return "\r \n " if self .is_windows_fs else "\n "
408-
409466 def raise_os_error (
410467 self ,
411468 err_no : int ,
@@ -1144,8 +1201,8 @@ def splitroot(self, path: AnyStr):
11441201 if isinstance (p , bytes ):
11451202 sep = self .path_separator .encode ()
11461203 altsep = None
1147- if self .alternative_path_separator :
1148- altsep = self .alternative_path_separator .encode ()
1204+ if self .alternative_path_separator is not None :
1205+ altsep = self .alternative_path_separator .encode () # type: ignore[attribute-error]
11491206 colon = b":"
11501207 unc_prefix = b"\\ \\ ?\\ UNC\\ "
11511208 empty = b""
@@ -1438,7 +1495,7 @@ def exists(self, file_path: AnyPath, check_link: bool = False) -> bool:
14381495 raise TypeError
14391496 if not path :
14401497 return False
1441- if path == self .dev_null . name :
1498+ if path == self .devnull :
14421499 return not self .is_windows_fs or sys .version_info >= (3 , 8 )
14431500 try :
14441501 if self .is_filepath_ending_with_separator (path ):
@@ -1515,7 +1572,7 @@ def resolve_path(self, file_path: AnyStr, allow_fd: bool = False) -> AnyStr:
15151572 path = self .replace_windows_root (path )
15161573 if self ._is_root_path (path ):
15171574 return path
1518- if path == matching_string (path , self .dev_null . name ):
1575+ if path == matching_string (path , self .devnull ):
15191576 return path
15201577 path_components = self ._path_components (path )
15211578 resolved_components = self ._resolve_components (path_components )
@@ -1661,7 +1718,7 @@ def get_object_from_normpath(
16611718 path = make_string_path (file_path )
16621719 if path == matching_string (path , self .root .name ):
16631720 return self .root
1664- if path == matching_string (path , self .dev_null . name ):
1721+ if path == matching_string (path , self .devnull ):
16651722 return self .dev_null
16661723
16671724 path = self ._original_path (path )
0 commit comments