Repository: jmcgeheeiv/pyfakefs
Pull request #349 (2018-02-22 05:44:41)

Add flake8 to testing
* FileNotFoundError, FileExistsError, NotADirectoryError exist in Python 3 but [not in Python 2](https://travis-ci.org/jmcgeheeiv/pyfakefs/jobs/344658535#L479-L512).
* file(), long, unicode exist in Python 2 but [not in Python 3](https://travis-ci.org/jmcgeheeiv/pyfakefs/jobs/344658538#L475-L502).

mrbean-bremen: Thanks for the contribution! I had planned to add pylint sometime (there is still an old pylint.rc lying around in the root dir), but never got to it.
I haven't used flake much (more used to pep8 and pylint) - are there any options to disable warnings in the code at specific places like for pylint? I don't want to have these warnings about `long` etc there, as they are expected, and in some places there are already pylint directives in the code.
Also, it would be nice to exclude the `pathlib` stuff from Python 2 builds, as it is Python 3 only, to exclude these warnings too.
As for line length - I personally am used to something like 120 characters per line, but lately tried to change it to the standard 79 characters, as this is enforced in another project I'm working on. 

So, basically, I like the PR, but to be more helpful it would make sense to exclude the unwanted warnings and errors and fix the rest (otherwise it will just be ignored). WDYT?
cclauss: * Pylint does not find undefined names.
* Put `# noqa` on lines you want ignored.
* —exclude directories or individual files
mrbean-bremen: Ok, thanks.
That pylint does not find undefined names is strange - it should. 
The rest seems to be like in pep8 - I still like pylint better because you have better control - #noqa disables checks for the line at all.
I may have another look in the evening - can't promise, though, after that, I will have access to a computer only somewhere next week.

cclauss: flake8 is PEP8 (now called pycodestyle) + pyflakes + McCabe cyclomatic complexity so it is a complete superset of PEP8.  All of these tools (including pylint) live at https://github.com/pycqa
cclauss: You can also write `# noqa: F821` to only suppress one particular alert
mrbean-bremen: Ah, ok - thanks, didn't know that. 
I will check if I can get this to build without errors first, remove the --exit-zero flag, and merge it back afterwards. As I said, I will have time for this not before next week, but thanks for the reminder - something that is on my ToDo list for some time now...

Patch:
diff --git a/CHANGES.md b/CHANGES.md
index aec1bf4..ed39d0e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -26,6 +26,7 @@ must use pyfakefs 3.3 or earlier.
   * Removed Python 2.6 support [#293](../../issues/293)
 
 #### Fixes
+  * Links in base path in `os.scandir` shall not be resolved ([#350](../../issues/350))
   * Correctly handle newline parameter in `open()` for Python 3, added support for universal newline mode in Python 2 ([#339](../../issues/339))
   * Creating a file with a path ending with path separator did not raise ([#320](../../issues/320))
   * Fixed more problems related to `flush` ([#302](../../issues/302), [#300](../../issues/300))
diff --git a/pyfakefs/fake_scandir.py b/pyfakefs/fake_scandir.py
index 66c0ccf..98b7140 100644
--- a/pyfakefs/fake_scandir.py
+++ b/pyfakefs/fake_scandir.py
@@ -83,14 +83,14 @@ class DirEntry(object):
         """
         if follow_symlinks:
             if self._statresult_symlink is None:
-                file_object = self._filesystem.ResolveObject(self.path)
+                file_object = self._filesystem.resolve(self.path)
                 if self._filesystem.is_windows_fs:
                     file_object.st_nlink = 0
                 self._statresult_symlink = file_object.stat_result.copy()
             return self._statresult_symlink
 
         if self._statresult is None:
-            file_object = self._filesystem.LResolveObject(self.path)
+            file_object = self._filesystem.lresolve(self.path)
             self._inode = file_object.st_ino
             if self._filesystem.is_windows_fs:
                 file_object.st_nlink = 0
@@ -106,14 +106,15 @@ class ScanDirIter:
         self.filesystem = filesystem
         if isinstance(path, int):
             if sys.version_info < (3, 7) or self.filesystem.is_windows_fs:
-                raise NotImplementedError('scandir does not support file descriptor'
-                                          'path argument')
+                raise NotImplementedError(
+                    'scandir does not support file descriptor '
+                    'path argument')
             path = self.filesystem.get_open_file(path).get_object().path
 
-        self.path = self.filesystem.ResolvePath(path)
+        self.path = self.filesystem.absnormpath(path)
         contents = {}
         try:
-            contents = self.filesystem.ConfirmDir(path).contents
+            contents = self.filesystem.confirmdir(path).contents
         except OSError:
             pass
         self.contents_iter = iter(contents)
@@ -128,9 +129,10 @@ class ScanDirIter:
             entry = self.contents_iter.__next__()
         dir_entry = DirEntry(self.filesystem)
         dir_entry.name = entry
-        dir_entry.path = self.filesystem.JoinPaths(self.path, dir_entry.name)
-        dir_entry._isdir = self.filesystem.IsDir(dir_entry.path)
-        dir_entry._islink = self.filesystem.IsLink(dir_entry.path)
+        dir_entry.path = self.filesystem.joinpaths(self.path,
+                                                   dir_entry.name)
+        dir_entry._isdir = self.filesystem.isdir(dir_entry.path)
+        dir_entry._islink = self.filesystem.islink(dir_entry.path)
         return dir_entry
 
     # satisfy both Python 2 and 3
@@ -184,8 +186,8 @@ def _classify_directory_contents(filesystem, root):
     """
     dirs = []
     files = []
-    for entry in filesystem.ListDir(root):
-        if filesystem.IsDir(filesystem.JoinPaths(root, entry)):
+    for entry in filesystem.listdir(root):
+        if filesystem.isdir(filesystem.joinpaths(root, entry)):
             dirs.append(entry)
         else:
             files.append(entry)
@@ -213,7 +215,7 @@ def walk(filesystem, top, topdown=True, onerror=None, followlinks=False):
 
     def do_walk(top_dir, top_most=False):
         top_dir = filesystem.CollapsePath(top_dir)
-        if not top_most and not followlinks and filesystem.IsLink(top_dir):
+        if not top_most and not followlinks and filesystem.islink(top_dir):
             return
         try:
             top_contents = _classify_directory_contents(filesystem, top_dir)
@@ -227,9 +229,10 @@ def walk(filesystem, top, topdown=True, onerror=None, followlinks=False):
                 yield top_contents
 
             for directory in top_contents[1]:
-                if not followlinks and filesystem.IsLink(directory):
+                if not followlinks and filesystem.islink(directory):
                     continue
-                for contents in do_walk(filesystem.JoinPaths(top_dir, directory)):
+                for contents in do_walk(filesystem.joinpaths(top_dir,
+                                                             directory)):
                     yield contents
 
             if not topdown:


Test patch:
diff --git a/.travis/run_tests.sh b/.travis/run_tests.sh
index 1b4b0e0..80df982 100755
--- a/.travis/run_tests.sh
+++ b/.travis/run_tests.sh
@@ -5,4 +5,10 @@ if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
 fi
 
 python --version
+pip --version
+pip install flake8
+# stop the build if there are Python syntax errors or undefined names
+flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics
+# exit-zero treats all errors as warnings.  The GitHub editor is 127 chars wide
+flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
 python -m tests.all_tests
diff --git a/tests/fake_os_test.py b/tests/fake_os_test.py
index 35e0efe..9713403 100644
--- a/tests/fake_os_test.py
+++ b/tests/fake_os_test.py
@@ -4087,6 +4087,16 @@ class FakeScandirTest(FakeOsModuleTestBase):
             self.assertTrue(self.dir_entries[2].is_symlink())
             self.assertTrue(self.dir_entries[3].is_symlink())
 
+    def test_path_links_not_resolved(self):
+        # regression test for #350
+        self.skip_if_symlink_not_supported()
+        dir_path = self.make_path('A', 'B', 'C')
+        self.os.makedirs(self.os.path.join(dir_path, 'D'))
+        link_path = self.make_path('A', 'C')
+        self.os.symlink(dir_path, link_path)
+        self.assertEqual([self.os.path.join(link_path, 'D')],
+                         [f.path for f in self.os.scandir(link_path)])
+
     def test_inode(self):
         if has_scandir and self.is_windows and self.use_real_fs():
             self.skipTest('inode seems not to work in scandir module under Windows')