before = 0 if depth else 1
else:
before = 1 if depth else 2
- is_decorator = current_line.is_decorator
- if is_decorator or current_line.is_def or current_line.is_class:
- if not is_decorator:
- self.previous_defs.append(depth)
- if self.previous_line is None:
- # Don't insert empty lines before the first line in the file.
- return 0, 0
-
- if self.previous_line.is_decorator:
- return 0, 0
-
- if self.previous_line.depth < current_line.depth and (
- self.previous_line.is_class or self.previous_line.is_def
- ):
- return 0, 0
-
- if (
- self.previous_line.is_comment
- and self.previous_line.depth == current_line.depth
- and before == 0
- ):
- return 0, 0
-
- if self.is_pyi:
- if self.previous_line.depth > current_line.depth:
- newlines = 1
- elif current_line.is_class or self.previous_line.is_class:
- if current_line.is_stub_class and self.previous_line.is_stub_class:
- newlines = 0
- else:
- newlines = 1
- else:
- newlines = 0
- else:
- newlines = 2
- if current_line.depth and newlines:
- newlines -= 1
- return newlines, 0
+ if current_line.is_decorator or current_line.is_def or current_line.is_class:
+ return self._maybe_empty_lines_for_class_or_def(current_line, before)
if (
self.previous_line
return before, 0
+ def _maybe_empty_lines_for_class_or_def(
+ self, current_line: Line, before: int
+ ) -> Tuple[int, int]:
+ if not current_line.is_decorator:
+ self.previous_defs.append(current_line.depth)
+ if self.previous_line is None:
+ # Don't insert empty lines before the first line in the file.
+ return 0, 0
+
+ if self.previous_line.is_decorator:
+ return 0, 0
+
+ if self.previous_line.depth < current_line.depth and (
+ self.previous_line.is_class or self.previous_line.is_def
+ ):
+ return 0, 0
+
+ if (
+ self.previous_line.is_comment
+ and self.previous_line.depth == current_line.depth
+ and before == 0
+ ):
+ return 0, 0
+
+ if self.is_pyi:
+ if self.previous_line.depth > current_line.depth:
+ newlines = 1
+ elif current_line.is_class or self.previous_line.is_class:
+ if current_line.is_stub_class and self.previous_line.is_stub_class:
+ # No blank line between classes with an emty body
+ newlines = 0
+ else:
+ newlines = 1
+ elif current_line.is_def and not self.previous_line.is_def:
+ # Blank line between a block of functions and a block of non-functions
+ newlines = 1
+ else:
+ newlines = 0
+ else:
+ newlines = 2
+ if current_line.depth and newlines:
+ newlines -= 1
+ return newlines, 0
+
@dataclass
class LineGenerator(Visitor[Line]):
"""Generate all files under `path` whose paths are not excluded by the
`exclude` regex, but are included by the `include` regex.
+ Symbolic links pointing outside of the root directory are ignored.
+
`report` is where output about exclusions goes.
"""
assert root.is_absolute(), f"INTERNAL ERROR: `root` must be absolute but is {root}"
for child in path.iterdir():
- normalized_path = "/" + child.resolve().relative_to(root).as_posix()
+ try:
+ normalized_path = "/" + child.resolve().relative_to(root).as_posix()
+ except ValueError:
+ if child.is_symlink():
+ report.path_ignored(
+ child,
+ "is a symbolic link that points outside of the root directory",
+ )
+ continue
+
+ raise
+
if child.is_dir():
normalized_path += "/"
exclude_match = exclude.search(normalized_path)