@@ -119,30 +119,42 @@ class ScopeType(enum.StrEnum):
119
119
# docstub: on
120
120
121
121
122
+ # TODO use `libcst.metadata.ScopeProvider` instead
122
123
@dataclass (slots = True , frozen = True )
123
124
class _Scope :
124
125
""""""
125
126
126
127
type : ScopeType
127
- node : cst .CSTNode = None
128
+ node : cst .CSTNode | None = None
128
129
129
130
@property
130
- def has_self_or_cls (self ):
131
+ def has_self_or_cls (self ) -> bool :
131
132
return self .type in {ScopeType .METHOD , ScopeType .CLASSMETHOD }
132
133
133
134
@property
134
- def is_method (self ):
135
+ def is_method (self ) -> bool :
135
136
return self .type in {
136
137
ScopeType .METHOD ,
137
138
ScopeType .CLASSMETHOD ,
138
139
ScopeType .STATICMETHOD ,
139
140
}
140
141
141
142
@property
142
- def is_class_init (self ):
143
+ def is_class_init (self ) -> bool :
143
144
out = self .is_method and self .node .name .value == "__init__"
144
145
return out
145
146
147
+ @property
148
+ def is_dataclass (self ) -> bool :
149
+ if cstm .matches (self .node , cstm .ClassDef ()):
150
+ # Determine if dataclass
151
+ decorators = cstm .findall (self .node , cstm .Decorator ())
152
+ is_dataclass = any (
153
+ cstm .findall (d , cstm .Name ("dataclass" )) for d in decorators
154
+ )
155
+ return is_dataclass
156
+ return False
157
+
146
158
147
159
def _get_docstring_node (node ):
148
160
"""Extract the node with the docstring from a definition.
@@ -672,16 +684,27 @@ def leave_AnnAssign(self, original_node, updated_node):
672
684
updated_node : cst.AnnAssign
673
685
"""
674
686
name = updated_node .target .value
675
- is_type_alias = cstm .matches (
676
- updated_node .annotation , cstm .Annotation (cstm .Name ("TypeAlias" ))
677
- )
678
- is__all__ = cstm .matches (updated_node .target , cstm .Name ("__all__" ))
679
687
680
- # Remove value if not type alias or __all__
681
- if updated_node .value is not None and not is_type_alias and not is__all__ :
682
- updated_node = updated_node .with_changes (
683
- value = None , equal = cst .MaybeSentinel .DEFAULT
688
+ if updated_node .value is not None :
689
+ is_type_alias = cstm .matches (
690
+ updated_node .annotation , cstm .Annotation (cstm .Name ("TypeAlias" ))
684
691
)
692
+ is__all__ = cstm .matches (updated_node .target , cstm .Name ("__all__" ))
693
+ is_dataclass = self ._scope_stack [- 1 ].is_dataclass
694
+ is_classvar = any (
695
+ cstm .findall (updated_node .annotation , cstm .Name ("ClassVar" ))
696
+ )
697
+
698
+ # Replace with ellipses if dataclass
699
+ if is_dataclass and not is_classvar :
700
+ updated_node = updated_node .with_changes (
701
+ value = cst .Ellipsis (), equal = cst .MaybeSentinel .DEFAULT
702
+ )
703
+ # Remove value if not type alias or __all__
704
+ elif not is_type_alias and not is__all__ :
705
+ updated_node = updated_node .with_changes (
706
+ value = None , equal = cst .MaybeSentinel .DEFAULT
707
+ )
685
708
686
709
# Replace with type annotation from docstring, if available
687
710
pytypes = self ._pytypes_stack [- 1 ]
0 commit comments