Switch from attrs to dataclasses (#1116)

The main motivation here is that mypyc is going to have custom support
for dataclasses but probably not attrs.
This commit is contained in:
Michael J. Sullivan 2019-10-29 21:06:34 -07:00 committed by Jelle Zijlstra
parent 6bedb5c58a
commit 31f4105731
4 changed files with 26 additions and 16 deletions

View File

@ -5,7 +5,6 @@ name = "pypi"
[packages] [packages]
aiohttp = ">=3.3.2" aiohttp = ">=3.3.2"
attrs = ">=18.1.0"
click = ">=6.5" click = ">=6.5"
appdirs = "*" appdirs = "*"
toml = ">=0.9.4" toml = ">=0.9.4"
@ -14,6 +13,7 @@ aiohttp-cors = "*"
typed-ast = "==1.4.0" typed-ast = "==1.4.0"
regex = ">=2019.8" regex = ">=2019.8"
pathspec = ">=0.6" pathspec = ">=0.6"
dataclasses = {version = ">=0.6", python_version = "< 3.7"}
[dev-packages] [dev-packages]
pre-commit = "*" pre-commit = "*"

10
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "0ae3ab3331dc4448fc4def999af38d91c13a566a482a6935c4a880f6bd9a6614" "sha256": "ad54dbd29085bc14caf655456b93d9f09e8556406ef956a5a05c20e30363ffa1"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": {}, "requires": {},
@ -85,6 +85,14 @@
"index": "pypi", "index": "pypi",
"version": "==7.0" "version": "==7.0"
}, },
"dataclasses": {
"hashes": [
"sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f",
"sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84"
],
"index": "pypi",
"version": "==0.6"
},
"idna": { "idna": {
"hashes": [ "hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407", "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",

View File

@ -39,7 +39,7 @@
) )
from appdirs import user_cache_dir from appdirs import user_cache_dir
from attr import dataclass, evolve, Factory from dataclasses import dataclass, field, replace
import click import click
import toml import toml
from typed_ast import ast3, ast27 from typed_ast import ast3, ast27
@ -185,7 +185,7 @@ class Feature(Enum):
@dataclass @dataclass
class FileMode: class FileMode:
target_versions: Set[TargetVersion] = Factory(set) target_versions: Set[TargetVersion] = field(default_factory=set)
line_length: int = DEFAULT_LINE_LENGTH line_length: int = DEFAULT_LINE_LENGTH
string_normalization: bool = True string_normalization: bool = True
is_pyi: bool = False is_pyi: bool = False
@ -629,7 +629,7 @@ def format_file_in_place(
`mode` and `fast` options are passed to :func:`format_file_contents`. `mode` and `fast` options are passed to :func:`format_file_contents`.
""" """
if src.suffix == ".pyi": if src.suffix == ".pyi":
mode = evolve(mode, is_pyi=True) mode = replace(mode, is_pyi=True)
then = datetime.utcfromtimestamp(src.stat().st_mtime) then = datetime.utcfromtimestamp(src.stat().st_mtime)
with open(src, "rb") as buf: with open(src, "rb") as buf:
@ -1028,11 +1028,11 @@ class BracketTracker:
"""Keeps track of brackets on a line.""" """Keeps track of brackets on a line."""
depth: int = 0 depth: int = 0
bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = Factory(dict) bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = field(default_factory=dict)
delimiters: Dict[LeafID, Priority] = Factory(dict) delimiters: Dict[LeafID, Priority] = field(default_factory=dict)
previous: Optional[Leaf] = None previous: Optional[Leaf] = None
_for_loop_depths: List[int] = Factory(list) _for_loop_depths: List[int] = field(default_factory=list)
_lambda_argument_depths: List[int] = Factory(list) _lambda_argument_depths: List[int] = field(default_factory=list)
def mark(self, leaf: Leaf) -> None: def mark(self, leaf: Leaf) -> None:
"""Mark `leaf` with bracket-related metadata. Keep track of delimiters. """Mark `leaf` with bracket-related metadata. Keep track of delimiters.
@ -1160,9 +1160,10 @@ class Line:
"""Holds leaves and comments. Can be printed with `str(line)`.""" """Holds leaves and comments. Can be printed with `str(line)`."""
depth: int = 0 depth: int = 0
leaves: List[Leaf] = Factory(list) leaves: List[Leaf] = field(default_factory=list)
comments: Dict[LeafID, List[Leaf]] = Factory(dict) # keys ordered like `leaves` # keys ordered like `leaves`
bracket_tracker: BracketTracker = Factory(BracketTracker) comments: Dict[LeafID, List[Leaf]] = field(default_factory=dict)
bracket_tracker: BracketTracker = field(default_factory=BracketTracker)
inside_brackets: bool = False inside_brackets: bool = False
should_explode: bool = False should_explode: bool = False
@ -1565,7 +1566,7 @@ class EmptyLineTracker:
is_pyi: bool = False is_pyi: bool = False
previous_line: Optional[Line] = None previous_line: Optional[Line] = None
previous_after: int = 0 previous_after: int = 0
previous_defs: List[int] = Factory(list) previous_defs: List[int] = field(default_factory=list)
def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
"""Return the number of extra empty lines before and after the `current_line`. """Return the number of extra empty lines before and after the `current_line`.
@ -1679,7 +1680,7 @@ class LineGenerator(Visitor[Line]):
is_pyi: bool = False is_pyi: bool = False
normalize_strings: bool = True normalize_strings: bool = True
current_line: Line = Factory(Line) current_line: Line = field(default_factory=Line)
remove_u_prefix: bool = False remove_u_prefix: bool = False
def line(self, indent: int = 0) -> Iterator[Line]: def line(self, indent: int = 0) -> Iterator[Line]:
@ -1844,7 +1845,7 @@ def visit_factor(self, node: Node) -> Iterator[Line]:
node.insert_child(index, Node(syms.atom, [lpar, operand, rpar])) node.insert_child(index, Node(syms.atom, [lpar, operand, rpar]))
yield from self.visit_default(node) yield from self.visit_default(node)
def __attrs_post_init__(self) -> None: def __post_init__(self) -> None:
"""You are in a twisty little maze of passages.""" """You are in a twisty little maze of passages."""
v = self.visit_stmt v = self.visit_stmt
Ø: Set[str] = set() Ø: Set[str] = set()
@ -3712,7 +3713,7 @@ def _v(node: Union[ast.AST, ast3.AST, ast27.AST], depth: int = 0) -> Iterator[st
yield f"{' ' * depth}{node.__class__.__name__}(" yield f"{' ' * depth}{node.__class__.__name__}("
for field in sorted(node._fields): for field in sorted(node._fields): # noqa: F402
# TypeIgnore has only one field 'lineno' which breaks this comparison # TypeIgnore has only one field 'lineno' which breaks this comparison
type_ignore_classes = (ast3.TypeIgnore, ast27.TypeIgnore) type_ignore_classes = (ast3.TypeIgnore, ast27.TypeIgnore)
if sys.version_info >= (3, 8): if sys.version_info >= (3, 8):

View File

@ -42,6 +42,7 @@ def get_long_description() -> str:
"typed-ast>=1.4.0", "typed-ast>=1.4.0",
"regex", "regex",
"pathspec>=0.6, <1", "pathspec>=0.6, <1",
"dataclasses>=0.6; python_version < '3.7'",
], ],
extras_require={"d": ["aiohttp>=3.3.2", "aiohttp-cors"]}, extras_require={"d": ["aiohttp>=3.3.2", "aiohttp-cors"]},
test_suite="tests.test_black", test_suite="tests.test_black",