From a3cf7be27552be44d45ef0ce17ca5b84a8119797 Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Wed, 24 May 2017 21:40:02 +0200 Subject: [PATCH] Corrected handling of byte/unicode paths in several functions - added FakeOsModule.getcwdb() for Python 3 - see #187 --- CHANGES.md | 1 + fake_filesystem_test.py | 81 ++++++++++--- pyfakefs/fake_filesystem.py | 222 +++++++++++++++++++++++------------- 3 files changed, 206 insertions(+), 98 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 353a45f1..2326388e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ The release versions are PyPi releases. * `mox3` is no longer required - the relevant part has been integrated into pyfakefs ([#182](../../issues/182)) #### Fixes + * Corrected handling of byte/unicode paths in several functions ([#187](../../issues/187)) * `FakeShutilModule.rmtree` failed for directory ending with path separator ([#177](../../issues/177)) * Case incorrectly handled for added Windows drives * `pathlib.glob()` incorrectly handled case under MacOS ([#167](../../issues/167)) diff --git a/fake_filesystem_test.py b/fake_filesystem_test.py index 344bf2c7..00337250 100755 --- a/fake_filesystem_test.py +++ b/fake_filesystem_test.py @@ -2548,14 +2548,38 @@ def setUp(self): def tearDown(self): time.time = self.orig_time - def testAbspath(self): + def checkAbspath(self, is_windows): + # the implementation differs in Windows and Posix, so test both + self.filesystem.is_windows_fs = is_windows + filename = u'foo' + abspath = u'!%s' % filename + self.filesystem.CreateFile(abspath) + self.assertEqual(abspath, self.path.abspath(abspath)) + self.assertEqual(abspath, self.path.abspath(filename)) + self.assertEqual(abspath, self.path.abspath(u'..!%s' % filename)) + + def testAbspathWindows(self): + self.checkAbspath(is_windows=True) + + def testAbspathPosix(self): """abspath should return a consistent representation of a file.""" - filename = 'foo' - abspath = '!%s' % filename + self.checkAbspath(is_windows=False) + + def checkAbspathBytes(self, is_windows): + """abspath should return a consistent representation of a file.""" + self.filesystem.is_windows_fs = is_windows + filename = b'foo' + abspath = b'!' + filename self.filesystem.CreateFile(abspath) self.assertEqual(abspath, self.path.abspath(abspath)) self.assertEqual(abspath, self.path.abspath(filename)) - self.assertEqual(abspath, self.path.abspath('..!%s' % filename)) + self.assertEqual(abspath, self.path.abspath(b'..!' + filename)) + + def testAbspathBytesWindows(self): + self.checkAbspathBytes(is_windows=True) + + def testAbspathBytesPosix(self): + self.checkAbspathBytes(is_windows=False) def testAbspathDealsWithRelativeNonRootPath(self): """abspath should correctly handle relative paths from a non-! directory. @@ -2640,9 +2664,13 @@ def testDirname(self): dirname = 'foo!bar' self.assertEqual(dirname, self.path.dirname('%s!baz' % dirname)) - def testJoin(self): - components = ['foo', 'bar', 'baz'] - self.assertEqual('foo!bar!baz', self.path.join(*components)) + def testJoinStrings(self): + components = [u'foo', u'bar', u'baz'] + self.assertEqual(u'foo!bar!baz', self.path.join(*components)) + + def testJoinBytes(self): + components = [b'foo', b'bar', b'baz'] + self.assertEqual(b'foo!bar!baz', self.path.join(*components)) def testExpandUser(self): if self.is_windows: @@ -4232,14 +4260,25 @@ def testCollapsePath(self): def testCollapseUncPath(self): self.assertEqual('!!foo!bar!baz', self.filesystem.CollapsePath('!!foo!bar!!baz!!')) - def testNormalizePath(self): - self.assertEqual('c:!foo!bar', self.filesystem.NormalizePath('c:!foo!!bar')) - self.filesystem.cwd = 'c:!foo' - self.assertEqual('c:!foo!bar', self.filesystem.NormalizePath('bar')) + def testNormalizePathStr(self): + self.filesystem.cwd = u'' + self.assertEqual(u'c:!foo!bar', self.filesystem.NormalizePath(u'c:!foo!!bar')) + self.filesystem.cwd = u'c:!foo' + self.assertEqual(u'c:!foo!bar', self.filesystem.NormalizePath(u'bar')) - def testSplitPath(self): - self.assertEqual(('c:!foo', 'bar'), self.filesystem.SplitPath('c:!foo!bar')) - self.assertEqual(('c:', 'foo'), self.filesystem.SplitPath('c:!foo')) + def testNormalizePathBytes(self): + self.filesystem.cwd = b'' + self.assertEqual(b'c:!foo!bar', self.filesystem.NormalizePath(b'c:!foo!!bar')) + self.filesystem.cwd = b'c:!foo' + self.assertEqual(b'c:!foo!bar', self.filesystem.NormalizePath(b'bar')) + + def testSplitPathStr(self): + self.assertEqual((u'c:!foo', u'bar'), self.filesystem.SplitPath(u'c:!foo!bar')) + self.assertEqual((u'c:', u'foo'), self.filesystem.SplitPath(u'c:!foo')) + + def testSplitPathBytes(self): + self.assertEqual((b'c:!foo', b'bar'), self.filesystem.SplitPath(b'c:!foo!bar')) + self.assertEqual((b'c:', b'foo'), self.filesystem.SplitPath(b'c:!foo')) def testCharactersBeforeRootIgnoredInJoinPaths(self): self.assertEqual('c:d', self.filesystem.JoinPaths('b', 'c:', 'd')) @@ -4251,11 +4290,15 @@ def testGetPathComponents(self): self.assertEqual(['c:', 'foo', 'bar'], self.filesystem.GetPathComponents('c:!foo!bar')) self.assertEqual(['c:'], self.filesystem.GetPathComponents('c:')) - def testSplitDrive(self): - self.assertEqual(('c:', '!foo!bar'), self.filesystem.SplitDrive('c:!foo!bar')) - self.assertEqual(('', '!foo!bar'), self.filesystem.SplitDrive('!foo!bar')) - self.assertEqual(('c:', 'foo!bar'), self.filesystem.SplitDrive('c:foo!bar')) - self.assertEqual(('', 'foo!bar'), self.filesystem.SplitDrive('foo!bar')) + def testSplitDriveStr(self): + self.assertEqual((u'c:', u'!foo!bar'), self.filesystem.SplitDrive(u'c:!foo!bar')) + self.assertEqual((u'', u'!foo!bar'), self.filesystem.SplitDrive(u'!foo!bar')) + self.assertEqual((u'c:', u'foo!bar'), self.filesystem.SplitDrive(u'c:foo!bar')) + self.assertEqual((u'', u'foo!bar'), self.filesystem.SplitDrive(u'foo!bar')) + + def testSplitDriveBytes(self): + self.assertEqual((b'c:', b'!foo!bar'), self.filesystem.SplitDrive(b'c:!foo!bar')) + self.assertEqual((b'', b'!foo!bar'), self.filesystem.SplitDrive(b'!foo!bar')) @unittest.skipIf(sys.version_info < (2, 7, 8), 'UNC path support since Python 2.7.8') def testSplitDriveWithUncPath(self): diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index f5cd09ec..88bc4dc8 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -486,7 +486,8 @@ def contents(self): @property def ordered_dirs(self): """Return the list of contained directory entry names ordered by creation order.""" - return [item[0] for item in sorted(self.byte_contents.items(), key=lambda entry: entry[1].st_ino)] + return [item[0] for item in sorted( + self.byte_contents.items(), key=lambda entry: entry[1].st_ino)] def AddEntry(self, path_object): """Adds a child FakeFile to this directory. @@ -656,6 +657,32 @@ def __init__(self, path_separator=os.path.sep, total_size=None): self.mount_points = {} self.AddMountPoint(self.root.name, total_size) + @staticmethod + def _matching_string(matched, string): + """Return the string as byte or unicode depending + on the type of matched, assuming string is an ASCII string. + """ + if string is None: + return string + if sys.version_info < (3, ): + if isinstance(matched, unicode): + return unicode(string) + else: + return string + else: + if isinstance(matched, bytes): + return bytes(string, 'ascii') + else: + return string + + def _path_separator(self, path): + """Return the path separator as the same type as path""" + return self._matching_string(path, self.path_separator) + + def _alternative_path_separator(self, path): + """Return the alternative path separator as the same type as path""" + return self._matching_string(path, self.alternative_path_separator) + def _IsLinkSupported(self): # Python 3.2 supports links in Windows return not self.is_windows_fs or sys.version_info >= (3, 2) @@ -696,18 +723,28 @@ def _AutoMountDriveIfNeeded(self, path, force=False): return self.AddMountPoint(path=drive) def _MountPointForPath(self, path): + def to_str(string): + """Convert the str, unicode or byte object to a str using the default encoding.""" + if string is None or isinstance(string, str): + return string + if sys.version_info < (3, 0): + return string.encode(locale.getpreferredencoding(False)) + else: + return string.decode(locale.getpreferredencoding(False)) + path = self.NormalizePath(self.NormalizeCase(path)) if path in self.mount_points: return self.mount_points[path] - mount_path = '' - drive = self.SplitDrive(path)[0] + mount_path = self._matching_string(path, '') + drive = self.SplitDrive(path)[:1] for root_path in self.mount_points: + root_path = self._matching_string(path, root_path) if drive and not root_path.startswith(drive): continue if path.startswith(root_path) and len(root_path) > len(mount_path): mount_path = root_path if mount_path: - return self.mount_points[mount_path] + return self.mount_points[to_str(mount_path)] mount_point = self._AutoMountDriveIfNeeded(path, force=True) assert mount_point return mount_point @@ -957,7 +994,7 @@ def NormalizePathSeparator(self, path): path = os.fspath(path) if self.alternative_path_separator is None or not path: return path - return path.replace(self.alternative_path_separator, self.path_separator) + return path.replace(self._alternative_path_separator(path), self._path_separator(path)) def CollapsePath(self, path): """Mimic os.path.normpath using the specified path_separator. @@ -981,15 +1018,18 @@ def CollapsePath(self, path): """ path = self.NormalizePathSeparator(path) drive, path = self.SplitDrive(path) - is_absolute_path = path.startswith(self.path_separator) - path_components = path.split(self.path_separator) + sep = self._path_separator(path) + is_absolute_path = path.startswith(sep) + path_components = path.split(sep) collapsed_path_components = [] + dot = self._matching_string(path, '.') + dotdot = self._matching_string(path, '..') for component in path_components: - if (not component) or (component == '.'): + if (not component) or (component == dot): continue - if component == '..': + if component == dotdot: if collapsed_path_components and ( - collapsed_path_components[-1] != '..'): + collapsed_path_components[-1] != dotdot): # Remove an up-reference: directory/.. collapsed_path_components.pop() continue @@ -997,10 +1037,10 @@ def CollapsePath(self, path): # Ignore leading .. components if starting from the root directory. continue collapsed_path_components.append(component) - collapsed_path = self.path_separator.join(collapsed_path_components) + collapsed_path = sep.join(collapsed_path_components) if is_absolute_path: - collapsed_path = self.path_separator + collapsed_path - return drive + collapsed_path or '.' + collapsed_path = sep + collapsed_path + return drive + collapsed_path or dot def NormalizeCase(self, path): """Return a normalized case version of the given path for case-insensitive @@ -1028,10 +1068,10 @@ def NormalizeCase(self, path): current_dir.st_size == 0): return path normalized_components.append(dir_name) - normalized_path = self.path_separator.join(normalized_components) - if path.startswith(self.path_separator) and not normalized_path.startswith( - self.path_separator): - normalized_path = self.path_separator + normalized_path + sep = self._path_separator(path) + normalized_path = sep.join(normalized_components) + if path.startswith(sep) and not normalized_path.startswith(sep): + normalized_path = sep + normalized_path return normalized_path def NormalizePath(self, path): @@ -1052,10 +1092,11 @@ def NormalizePath(self, path): path = self.path_separator elif not self._StartsWithRootPath(path): # Prefix relative paths with cwd, if cwd is not root. - path = self.path_separator.join( - (self.cwd != self.root.name and self.cwd or '', - path)) - if path == '.': + root_name = self._matching_string(path, self.root.name) + empty = self._matching_string(path, '') + path = self._path_separator(path).join( + (self.cwd != root_name and self.cwd or empty, path)) + if path == self._matching_string(path, '.'): path = self.cwd return self.CollapsePath(path) @@ -1074,7 +1115,8 @@ def SplitPath(self, path): """ drive, path = self.SplitDrive(path) path = self.NormalizePathSeparator(path) - path_components = path.split(self.path_separator) + sep = self._path_separator(path) + path_components = path.split(sep) if not path_components: return ('', '') basename = path_components.pop() @@ -1086,9 +1128,9 @@ def SplitPath(self, path): # Strip all trailing separators. while not path_components[-1]: path_components.pop() - return (drive + self.path_separator.join(path_components), basename) + return (drive + sep.join(path_components), basename) # Root path. Collapse all leading separators. - return (drive or self.path_separator, basename) + return (drive or sep, basename) def SplitDrive(self, path): """Splits the path into the drive part and the rest of the path. @@ -1107,21 +1149,22 @@ def SplitDrive(self, path): if self.is_windows_fs: if len(path) >= 2: path = self.NormalizePathSeparator(path) + sep = self._path_separator(path) # UNC path handling is here since Python 2.7.8, back-ported from Python 3 if sys.version_info >= (2, 7, 8): - if (path[0:2] == self.path_separator * 2) and ( - path[2:3] != self.path_separator): + if (path[0:2] == sep * 2) and ( + path[2:3] != sep): # UNC path handling - splits off the mount point instead of the drive - sep_index = path.find(self.path_separator, 2) + sep_index = path.find(sep, 2) if sep_index == -1: return path[:0], path - sep_index2 = path.find(self.path_separator, sep_index + 1) + sep_index2 = path.find(sep, sep_index + 1) if sep_index2 == sep_index + 1: return path[:0], path if sep_index2 == -1: sep_index2 = len(path) return path[:sep_index2], path[sep_index2:] - if path[1] == ':': + if path[1:2] == self._matching_string(path, ':'): return path[:2], path[2:] return path[:0], path @@ -1129,11 +1172,12 @@ def _JoinPathsWithDriveSupport(self, *all_paths): """Taken from Python 3.5 os.path.join() code in ntpath.py and slightly adapted""" base_path = all_paths[0] paths_to_add = all_paths[1:] - seps = [self.path_separator, self.alternative_path_separator] + sep = self._path_separator(base_path) + seps = [sep, self._alternative_path_separator(base_path)] result_drive, result_path = self.SplitDrive(base_path) for path in paths_to_add: drive_part, path_part = self.SplitDrive(path) - if path_part and path_part[0] in seps: + if path_part and path_part[:1] in seps: # Second path is absolute if drive_part or not result_drive: result_drive = drive_part @@ -1148,13 +1192,14 @@ def _JoinPathsWithDriveSupport(self, *all_paths): # Same drive in different case result_drive = drive_part # Second path is relative to the first - if result_path and result_path[-1] not in seps: - result_path = result_path + self.path_separator + if result_path and result_path[-1:] not in seps: + result_path = result_path + sep result_path = result_path + path_part # add separator between UNC and non-absolute path - if (result_path and result_path[0] not in seps and - result_drive and result_drive[-1:] != ':'): - return result_drive + self.path_separator + result_path + colon = self._matching_string(base_path, ':') + if (result_path and result_path[:1] not in seps and + result_drive and result_drive[-1:] != colon): + return result_drive + sep + result_path return result_drive + result_path def JoinPaths(self, *paths): @@ -1174,17 +1219,18 @@ def JoinPaths(self, *paths): if self.is_windows_fs: return self._JoinPathsWithDriveSupport(*paths) joined_path_segments = [] + sep = self._path_separator(paths[0]) for path_segment in paths: if self._StartsWithRootPath(path_segment): # An absolute path joined_path_segments = [path_segment] else: if (joined_path_segments and - not joined_path_segments[-1].endswith(self.path_separator)): - joined_path_segments.append(self.path_separator) + not joined_path_segments[-1].endswith(sep)): + joined_path_segments.append(sep) if path_segment: joined_path_segments.append(path_segment) - return ''.join(joined_path_segments) + return self._matching_string(paths[0], '').join(joined_path_segments) def GetPathComponents(self, path): """Breaks the path into a list of component names. @@ -1208,10 +1254,10 @@ def GetPathComponents(self, path): Returns: The list of names split from path """ - if not path or path == self.path_separator: + if not path or path == self._path_separator(path): return [] drive, path = self.SplitDrive(path) - path_components = path.split(self.path_separator) + path_components = path.split(self._path_separator(path)) assert drive or path_components if not path_components[0]: # This is an absolute path. @@ -1231,24 +1277,27 @@ def StartsWithDriveLetter(self, file_path): True if drive letter support is enabled in the filesystem and the path starts with a drive letter. """ + colon = self._matching_string(file_path, ':') return (self.is_windows_fs and len(file_path) >= 2 and - file_path[0].isalpha and file_path[1] == ':') + file_path[:1].isalpha and (file_path[1:2]) == colon) def _StartsWithRootPath(self, file_path): - return (file_path.startswith(self.root.name) or + root_name = self._matching_string(file_path, self.root.name) + return (file_path.startswith(root_name) or not self.is_case_sensitive and file_path.lower().startswith( - self.root.name.lower()) or + root_name.lower()) or self.StartsWithDriveLetter(file_path)) def _IsRootPath(self, file_path): - return (file_path == self.root.name or - not self.is_case_sensitive and file_path.lower() == self.root.name.lower() or + root_name = self._matching_string(file_path, self.root.name) + return (file_path == root_name or + not self.is_case_sensitive and file_path.lower() == root_name.lower() or len(file_path) == 2 and self.StartsWithDriveLetter(file_path)) def _EndsWithPathSeparator(self, file_path): - return file_path and (file_path.endswith(self.path_separator) + return file_path and (file_path.endswith(self._path_separator(file_path)) or self.alternative_path_separator is not None - and file_path.endswith(self.alternative_path_separator)) + and file_path.endswith(self._alternative_path_separator(file_path))) def _DirectoryContent(self, directory, component): if component in directory.contents: @@ -1331,14 +1380,17 @@ def ResolvePath(self, file_path): """ def _ComponentsToPath(component_folders): - path = self.path_separator.join(component_folders) + sep = self._path_separator( + component_folders[0]) if component_folders else self.path_separator + path = sep.join(component_folders) if not self._StartsWithRootPath(path): - path = self.path_separator + path + path = sep + path return path def _ValidRelativePath(file_path): - while file_path and '/..' in file_path: - file_path = file_path[:file_path.rfind('/..')] + slash_dotdot = self._matching_string(file_path, '/..') + while file_path and slash_dotdot in file_path: + file_path = file_path[:file_path.rfind(slash_dotdot)] if not self.Exists(self.NormalizePath(file_path)): return False return True @@ -1365,17 +1417,18 @@ def _FollowLink(link_path_components, link): IOError: if there are too many levels of symbolic link """ link_path = link.contents + sep = self._path_separator(link_path) # For links to absolute paths, we want to throw out everything in the # path built so far and replace with the link. For relative links, we # have to append the link to what we have so far, - if not link_path.startswith(self.path_separator): + if not link_path.startswith(sep): # Relative path. Append remainder of path to what we have processed # so far, excluding the name of the link itself. # /a/b => ../c should yield /a/../c (which will normalize to /c) # /a/b => d should yield a/d components = link_path_components[:-1] components.append(link_path) - link_path = self.path_separator.join(components) + link_path = sep.join(components) # Don't call self.NormalizePath(), as we don't want to prepend self.cwd. return self.CollapsePath(link_path) @@ -1979,8 +2032,9 @@ def MakeDirectory(self, dir_name, mode=PERM_DEF): parent_dir, _ = self.SplitPath(dir_name) if parent_dir: base_dir = self.CollapsePath(parent_dir) - if parent_dir.endswith(self.path_separator + '..'): - base_dir, dummy_dotdot, _ = parent_dir.partition(self.path_separator + '..') + ellipsis = self._matching_string(parent_dir, self.path_separator + '..') + if parent_dir.endswith(ellipsis): + base_dir, dummy_dotdot, _ = parent_dir.partition(ellipsis) if not self.Exists(base_dir): raise OSError(errno.ENOENT, 'No such fake directory', base_dir) @@ -2174,7 +2228,7 @@ def RemoveDirectory(self, target_directory): OSError: if target_directory does not point to a directory. OSError: if removal failed per FakeFilesystem.RemoveObject. Cannot remove '.'. """ - if target_directory == '.': + if target_directory in (b'.', u'.'): raise OSError(errno.EINVAL, 'Invalid argument: \'.\'') target_directory = self.NormalizePath(target_directory) if self.ConfirmDir(target_directory): @@ -2421,11 +2475,12 @@ def isabs(self, path): path = self.splitdrive(path)[1] if sys.version_info >= (3, 6): path = os.fspath(path) + sep = self.filesystem._path_separator(path) + altsep = self.filesystem._alternative_path_separator(path) if self.filesystem.is_windows_fs: - return len(path) > 0 and path[0] in (self.sep, self.altsep) + return len(path) > 0 and path[:1] in (sep, altsep) else: - return path.startswith(self.sep) or self.altsep is not None and path.startswith( - self.altsep) + return path.startswith(sep) or altsep is not None and path.startswith(altsep) def isdir(self, path): """Determine if path identifies a directory.""" @@ -2512,18 +2567,23 @@ def abspath(self, path): def getcwd(): """Return the current working directory.""" # pylint: disable=undefined-variable - if sys.version_info < (3, 0) and isinstance(path, unicode): + if sys.version_info < (3, ) and isinstance(path, unicode): return self.os.getcwdu() + elif sys.version_info >= (3, ) and isinstance(path, bytes): + return self.os.getcwdb() else: return self.os.getcwd() if sys.version_info >= (3, 6): path = os.fspath(path) + + sep = self.filesystem._path_separator(path) + altsep = self.filesystem._alternative_path_separator(path) if not self.isabs(path): path = self.join(getcwd(), path) elif (self.filesystem.is_windows_fs and - path.startswith(self.sep) or self.altsep is not None and - path.startswith(self.altsep)): + path.startswith(sep) or altsep is not None and + path.startswith(altsep)): cwd = getcwd() if self.filesystem.StartsWithDriveLetter(cwd): path = self.join(cwd[:2], path) @@ -2593,15 +2653,16 @@ def _joinrealpath(self, path, rest, seen): encountered in the second path. Taken from Python source and adapted. """ - curdir = '.' - pardir = '..' + curdir = self.filesystem._matching_string(path, '.') + pardir = self.filesystem._matching_string(path, '..') + sep = self.filesystem._path_separator(path) if self.isabs(rest): rest = rest[1:] - path = self.sep + path = sep while rest: - name, _, rest = rest.partition(self.sep) + name, _, rest = rest.partition(sep) if not name or name == curdir: # current dir continue @@ -2663,22 +2724,21 @@ def ismount(self, path): if not path: return False normed_path = self.filesystem.NormalizePath(path) + sep = self.filesystem._path_separator(path) if self.filesystem.is_windows_fs: if self.filesystem.alternative_path_separator is not None: path_seps = ( - self.filesystem.path_separator, - self.filesystem.alternative_path_separator + sep, self.filesystem._alternative_path_separator(path) ) else: - path_seps = (self.filesystem.path_separator,) + path_seps = (sep,) drive, rest = self.filesystem.SplitDrive(normed_path) - if drive and drive[0] in path_seps: + if drive and drive[:1] in path_seps: return (not rest) or (rest in path_seps) if rest in path_seps: return True for mount_point in self.filesystem.mount_points: - if (normed_path.rstrip(self.filesystem.path_separator) == - mount_point.rstrip(self.filesystem.path_separator)): + if (normed_path.rstrip(sep) == mount_point.rstrip(sep)): return True return False @@ -2946,11 +3006,15 @@ def getcwd(self): """Return current working directory.""" return self.filesystem.cwd - def getcwdu(self): - """Return current working directory as unicode. Python 2 only.""" - if sys.version_info >= (3, 0): - raise AttributeError('no attribute getcwdu') - return unicode(self.filesystem.cwd) # pylint: disable=undefined-variable + if sys.version_info < (3, ): + def getcwdu(self): + """Return current working directory as unicode. Python 2 only.""" + return unicode(self.filesystem.cwd) # pylint: disable=undefined-variable + + else: + def getcwdb(self): + """Return current working directory as bytes. Python 3 only.""" + return bytes(self.filesystem.cwd, locale.getpreferredencoding(False)) def listdir(self, target_directory): """Return a list of file names in target_directory. @@ -3369,7 +3433,7 @@ def mknod(self, filename, mode=None, device=None): os.strerror(errno.EEXIST), filename)) raise OSError(errno.ENOENT, 'Fake filesystem: %s: %s' % ( os.strerror(errno.ENOENT), filename)) - if tail == '.' or tail == '..' or self.filesystem.Exists(filename): + if tail in (b'.', u'.', b'..', u'..') or self.filesystem.Exists(filename): raise OSError(errno.EEXIST, 'Fake fileystem: %s: %s' % ( os.strerror(errno.EEXIST), filename)) try: