diff --git a/black.py b/black.py index aff6fb2dd34..cfc1b4d5f69 100644 --- a/black.py +++ b/black.py @@ -40,7 +40,6 @@ from typing_extensions import Final from appdirs import user_cache_dir -from attr import dataclass, evolve, Factory import click import toml from typed_ast import ast3, ast27 @@ -189,12 +188,23 @@ class Feature(Enum): } -@dataclass class FileMode: - target_versions: Set[TargetVersion] = Factory(set) - line_length: int = DEFAULT_LINE_LENGTH - string_normalization: bool = True - is_pyi: bool = False + target_versions: Set[TargetVersion] + line_length: int + string_normalization: bool + is_pyi: bool + + def __init__( + self, + target_versions: Optional[Set[TargetVersion]] = None, + line_length: int = DEFAULT_LINE_LENGTH, + string_normalization: bool = True, + is_pyi: bool = False, + ) -> None: + self.target_versions = target_versions if target_versions is not None else set() + self.line_length = line_length + self.string_normalization = string_normalization + self.is_pyi = is_pyi def get_cache_key(self) -> str: if self.target_versions: @@ -646,7 +656,9 @@ def format_file_in_place( `mode` and `fast` options are passed to :func:`format_file_contents`. """ if src.suffix == ".pyi": - mode = evolve(mode, is_pyi=True) + mode = FileMode( + mode.target_versions, mode.line_length, mode.string_normalization, True + ) then = datetime.utcfromtimestamp(src.stat().st_mtime) with open(src, "rb") as buf: @@ -899,9 +911,11 @@ def visit_default(self, node: LN) -> Iterator[T]: yield from self.visit(child) -@dataclass class DebugVisitor(Visitor[T]): - tree_depth: int = 0 + tree_depth: int + + def __init__(self) -> None: + self.tree_depth = 0 def visit_default(self, node: LN) -> Iterator[T]: indent = " " * (2 * self.tree_depth) @@ -1047,16 +1061,22 @@ def show(cls, code: Union[str, Leaf, Node]) -> None: DOT_PRIORITY: Final = 1 -@dataclass class BracketTracker: """Keeps track of brackets on a line.""" depth: int = 0 - bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = Factory(dict) - delimiters: Dict[LeafID, Priority] = Factory(dict) - previous: Optional[Leaf] = None - _for_loop_depths: List[int] = Factory(list) - _lambda_argument_depths: List[int] = Factory(list) + bracket_match: Dict[Tuple[Depth, NodeType], Leaf] + delimiters: Dict[LeafID, Priority] + previous: Optional[Leaf] + _for_loop_depths: List[int] + _lambda_argument_depths: List[int] + + def __init__(self) -> None: + self.bracket_match = {} + self.delimiters = {} + self.previous = None + self._for_loop_depths = [] + self._lambda_argument_depths = [] def mark(self, leaf: Leaf) -> None: """Mark `leaf` with bracket-related metadata. Keep track of delimiters. @@ -1179,17 +1199,23 @@ def get_open_lsqb(self) -> Optional[Leaf]: return self.bracket_match.get((self.depth - 1, token.RSQB)) -@dataclass class Line: """Holds leaves and comments. Can be printed with `str(line)`.""" - depth: int = 0 - leaves: List[Leaf] = Factory(list) - comments: Dict[LeafID, List[Leaf]] = Factory(dict) # keys ordered like `leaves` - bracket_tracker: BracketTracker = Factory(BracketTracker) - inside_brackets: bool = False + depth: int + leaves: List[Leaf] + comments: Dict[LeafID, List[Leaf]] # keys ordered like `leaves` + bracket_tracker: BracketTracker + inside_brackets: bool should_explode: bool = False + def __init__(self, *, depth: int = 0, inside_brackets: bool = False) -> None: + self.depth = depth + self.inside_brackets = inside_brackets + self.leaves = [] + self.comments = {} + self.bracket_tracker = BracketTracker() + def append(self, leaf: Leaf, preformatted: bool = False) -> None: """Add a new `leaf` to the end of the line. @@ -1495,7 +1521,6 @@ def __bool__(self) -> bool: return bool(self.leaves or self.comments) -@dataclass class EmptyLineTracker: """Provides a stateful method that returns the number of potential extra empty lines needed before and after the currently processed line. @@ -1505,10 +1530,14 @@ class EmptyLineTracker: are consumed by `maybe_empty_lines()` and included in the computation. """ - is_pyi: bool = False + is_pyi: bool previous_line: Optional[Line] = None previous_after: int = 0 - previous_defs: List[int] = Factory(list) + previous_defs: List[int] + + def __init__(self, *, is_pyi: bool = False) -> None: + self.is_pyi = is_pyi + self.previous_defs = [] def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: """Return the number of extra empty lines before and after the `current_line`. @@ -1612,7 +1641,6 @@ def _maybe_empty_lines_for_class_or_def( return newlines, 0 -@dataclass class LineGenerator(Visitor[Line]): """Generates reformatted Line objects. Empty lines are not emitted. @@ -1620,10 +1648,18 @@ class LineGenerator(Visitor[Line]): in ways that will no longer stringify to valid Python code on the tree. """ - is_pyi: bool = False - normalize_strings: bool = True - current_line: Line = Factory(Line) - remove_u_prefix: bool = False + def __init__( + self, + is_pyi: bool = False, + normalize_strings: bool = True, + current_line: Optional[Line] = None, + remove_u_prefix: bool = False, + ) -> None: + self.is_pyi = is_pyi + self.normalize_strings = normalize_strings + self.current_line = current_line if current_line is not None else Line() + self.remove_u_prefix = remove_u_prefix + self._setup_visit_methods() def line(self, indent: int = 0) -> Iterator[Line]: """Generate a line. @@ -1803,7 +1839,7 @@ def visit_STANDALONE_COMMENT(self, leaf: Leaf) -> Iterator[Line]: yield from self.line() yield from self.visit_default(leaf) - def __attrs_post_init__(self) -> None: + def _setup_visit_methods(self) -> None: """You are in a twisty little maze of passages.""" v = self.visit_stmt Ø: Set[str] = set() @@ -2254,8 +2290,7 @@ def generate_comments(leaf: LN) -> Iterator[Leaf]: yield Leaf(pc.type, pc.value, prefix="\n" * pc.newlines) -@dataclass -class ProtoComment: +class ProtoComment: # noqa # flake8 wants this to use __slots__ but mypyc will """Describes a piece of syntax that is a comment. It's not a :class:`blib2to3.pytree.Leaf` so that: @@ -2271,6 +2306,12 @@ class ProtoComment: newlines: int # how many newlines before the comment consumed: int # how many characters of the original leaf's prefix did we consume + def __init__(self, type: int, value: str, newlines: int, consumed: int) -> None: + self.type = type + self.value = value + self.newlines = newlines + self.consumed = consumed + @lru_cache(maxsize=4096) def list_comments(prefix: str, *, is_endmarker: bool) -> List[ProtoComment]: @@ -3499,7 +3540,6 @@ def find_project_root(srcs: Iterable[str]) -> Path: return directory -@dataclass class Report: """Provides a reformatting counter. Can be rendered with `str(report)`.""" @@ -3510,6 +3550,13 @@ class Report: same_count: int = 0 failure_count: int = 0 + def __init__( + self, *, check: bool = False, quiet: bool = False, verbose: bool = False + ) -> None: + self.check = check + self.quiet = quiet + self.verbose = verbose + def done(self, src: Path, changed: Changed) -> None: """Increment the counter for successful reformatting. Write out a message.""" if changed is Changed.YES: