Repository: ambv/black
Pull request #202 (2018-05-10 21:57:03)

Check for broken symlinks before checking file data
New unit test fails without the check in the code, passed afterwards.

coveralls: ## Pull Request Test Coverage Report for [Build 347](https://coveralls.io/builds/16930123)

* **5** of **5**  **(100.0%)** changed or added relevant lines in **2** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.01%**) to **95.452%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/16930123/badge)](https://coveralls.io/builds/16930123) |
| :-- | --: |
| Change from base [Build 346](https://coveralls.io/builds/16912629): |  0.01% |
| Covered Lines: | 1931 |
| Relevant Lines: | 2023 |

---
##### 💛  - [Coveralls](https://coveralls.io)

coveralls: ## Pull Request Test Coverage Report for [Build 347](https://coveralls.io/builds/16930123)

* **5** of **5**  **(100.0%)** changed or added relevant lines in **2** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.01%**) to **95.452%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/16930123/badge)](https://coveralls.io/builds/16930123) |
| :-- | --: |
| Change from base [Build 346](https://coveralls.io/builds/16912629): |  0.01% |
| Covered Lines: | 1931 |
| Relevant Lines: | 2023 |

---
##### 💛  - [Coveralls](https://coveralls.io)

miggaiowski: @zsol: That would require passing the report object down to that function, or passing the quiet param. Do you think it's that necessary?
ambv: Thanks for the new test! For the actual fix, instead of adding an `exists()` in a hidden place in cache handling, we should fix even attempting to add this broken symlink to the list of files.

You can change line 2497 to just say `elif child.is_file() and child.suffix in PYTHON_EXTENSIONS:`. `is_file()` returns False for broken symlinks.

Patch:
diff --git a/README.md b/README.md
index 0571a97..3f62eec 100644
--- a/README.md
+++ b/README.md
@@ -74,7 +74,7 @@ Options:
 * it will read from standard input and write to standard output if `-`
   is used as the filename;
 * it only outputs messages to users on standard error;
-* exits with code 0 unless an internal error occured (or `--check` was
+* exits with code 0 unless an internal error occurred (or `--check` was
   used).
 
 
diff --git a/black.py b/black.py
index 913fe8d..a113169 100644
--- a/black.py
+++ b/black.py
@@ -2494,7 +2494,7 @@ def gen_python_files_in_dir(path: Path) -> Iterator[Path]:
 
             yield from gen_python_files_in_dir(child)
 
-        elif child.suffix in PYTHON_EXTENSIONS:
+        elif child.is_file() and child.suffix in PYTHON_EXTENSIONS:
             yield child
 
 


Test patch:
diff --git a/tests/test_black.py b/tests/test_black.py
index cf20945..bc133ca 100644
--- a/tests/test_black.py
+++ b/tests/test_black.py
@@ -695,6 +695,13 @@ def test_no_files(self) -> None:
             result = CliRunner().invoke(black.main, [])
             self.assertEqual(result.exit_code, 0)
 
+    def test_broken_symlink(self) -> None:
+        with cache_dir() as workspace:
+            symlink = workspace / "broken_link.py"
+            symlink.symlink_to("nonexistent.py")
+            result = CliRunner().invoke(black.main, [str(workspace.resolve())])
+            self.assertEqual(result.exit_code, 0)
+
     def test_read_cache_line_lengths(self) -> None:
         with cache_dir() as workspace:
             path = (workspace / "file.py").resolve()