From 2feb8ea1982c763a423ded1284477e666c4e5dfe Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Sun, 3 Mar 2024 10:57:41 +0000 Subject: [PATCH] Replace custom _add_slots decorator with dataclasses slots=True Dataclasses has a built-in slots generation feature since Python 3.10. --- libcst/_add_slots.py | 65 -------- libcst/_nodes/expression.py | 163 ++++++------------- libcst/_nodes/internal.py | 4 +- libcst/_nodes/module.py | 4 +- libcst/_nodes/op.py | 145 ++++++----------- libcst/_nodes/statement.py | 172 +++++++------------- libcst/_nodes/whitespace.py | 19 +-- libcst/_parser/types/config.py | 4 +- libcst/_parser/types/partials.py | 52 ++---- libcst/_parser/types/py_token.py | 4 +- libcst/_parser/types/py_whitespace_state.py | 4 +- libcst/_parser/wrapped_tokenize.py | 4 +- libcst/_position.py | 8 +- libcst/metadata/position_provider.py | 7 +- libcst/metadata/reentrant_codegen.py | 4 +- libcst/metadata/scope_provider.py | 7 +- libcst/tests/test_add_slots.py | 46 ------ 17 files changed, 195 insertions(+), 517 deletions(-) delete mode 100644 libcst/_add_slots.py delete mode 100644 libcst/tests/test_add_slots.py diff --git a/libcst/_add_slots.py b/libcst/_add_slots.py deleted file mode 100644 index 7012ce1ad..000000000 --- a/libcst/_add_slots.py +++ /dev/null @@ -1,65 +0,0 @@ -# This file is derived from github.com/ericvsmith/dataclasses, and is Apache 2 licensed. -# https://github.com/ericvsmith/dataclasses/blob/ae712dd993420d43444f188f452/LICENSE.txt -# https://github.com/ericvsmith/dataclasses/blob/ae712dd993420d43444f/dataclass_tools.py -# Changed: takes slots in base classes into account when creating slots - -import dataclasses -from itertools import chain, filterfalse -from typing import Any, Mapping, Type, TypeVar - -_T = TypeVar("_T") - - -def add_slots(cls: Type[_T]) -> Type[_T]: - # Need to create a new class, since we can't set __slots__ - # after a class has been created. - - # Make sure __slots__ isn't already set. - if "__slots__" in cls.__dict__: - raise TypeError(f"{cls.__name__} already specifies __slots__") - - # Create a new dict for our new class. - cls_dict = dict(cls.__dict__) - field_names = tuple(f.name for f in dataclasses.fields(cls)) - inherited_slots = set( - chain.from_iterable( - superclass.__dict__.get("__slots__", ()) for superclass in cls.mro() - ) - ) - cls_dict["__slots__"] = tuple( - filterfalse(inherited_slots.__contains__, field_names) - ) - for field_name in field_names: - # Remove our attributes, if present. They'll still be - # available in _MARKER. - cls_dict.pop(field_name, None) - # Remove __dict__ itself. - cls_dict.pop("__dict__", None) - - # Create the class. - qualname = getattr(cls, "__qualname__", None) - - # pyre-fixme[9]: cls has type `Type[Variable[_T]]`; used as `_T`. - # pyre-fixme[19]: Expected 0 positional arguments. - cls = type(cls)(cls.__name__, cls.__bases__, cls_dict) - if qualname is not None: - cls.__qualname__ = qualname - - # Set __getstate__ and __setstate__ to workaround a bug with pickling frozen - # dataclasses with slots. See https://bugs.python.org/issue36424 - - def __getstate__(self: object) -> Mapping[str, Any]: - return { - field.name: getattr(self, field.name) - for field in dataclasses.fields(self) - if hasattr(self, field.name) - } - - def __setstate__(self: object, state: Mapping[str, Any]) -> None: - for fieldname, value in state.items(): - object.__setattr__(self, fieldname, value) - - cls.__getstate__ = __getstate__ - cls.__setstate__ = __setstate__ - - return cls diff --git a/libcst/_nodes/expression.py b/libcst/_nodes/expression.py index 074fc71f5..e3039e270 100644 --- a/libcst/_nodes/expression.py +++ b/libcst/_nodes/expression.py @@ -19,7 +19,6 @@ from typing_extensions import Literal -from libcst._add_slots import add_slots from libcst._maybe_sentinel import MaybeSentinel from libcst._nodes.base import CSTCodegenError, CSTNode, CSTValidationError from libcst._nodes.internal import ( @@ -48,8 +47,7 @@ from libcst._visitors import CSTVisitorT -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LeftSquareBracket(CSTNode): """ Used by various nodes to denote a subscript or list section. This doesn't own @@ -71,8 +69,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.whitespace_after._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class RightSquareBracket(CSTNode): """ Used by various nodes to denote a subscript or list section. This doesn't own @@ -94,8 +91,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token("]") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LeftCurlyBrace(CSTNode): """ Used by various nodes to denote a dict or set. This doesn't own the whitespace to @@ -117,8 +113,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.whitespace_after._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class RightCurlyBrace(CSTNode): """ Used by various nodes to denote a dict or set. This doesn't own the whitespace to @@ -140,8 +135,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token("}") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LeftParen(CSTNode): """ Used by various nodes to denote a parenthesized section. This doesn't own @@ -163,8 +157,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.whitespace_after._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class RightParen(CSTNode): """ Used by various nodes to denote a parenthesized section. This doesn't own @@ -186,8 +179,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(")") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Asynchronous(CSTNode): """ Used by asynchronous function definitions, as well as ``async for`` and @@ -323,8 +315,7 @@ class BaseDelTargetExpression(BaseExpression, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Name(BaseAssignTargetExpression, BaseDelTargetExpression): """ A simple variable name. Names are typically used in the context of a variable @@ -361,8 +352,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(self.value) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Ellipsis(BaseExpression): """ An ellipsis ``...``. When used as an expression, it evaluates to the @@ -410,8 +400,7 @@ def _safe_to_use_with_word_operator(self, position: ExpressionPosition) -> bool: return super(BaseNumber, self)._safe_to_use_with_word_operator(position) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Integer(BaseNumber): #: A string representation of the integer, such as ``"100000"`` or ``100_000``. #: @@ -447,8 +436,7 @@ def evaluated_value(self) -> int: return literal_eval(self.value) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Float(BaseNumber): #: A string representation of the floating point number, such as ``"0.05"``, #: ``".050"``, or ``"5e-2"``. @@ -485,8 +473,7 @@ def evaluated_value(self) -> float: return literal_eval(self.value) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Imaginary(BaseNumber): #: A string representation of the imaginary (complex) number, such as ``"2j"``. #: @@ -572,8 +559,7 @@ def _safe_to_use_with_word_operator(self, position: ExpressionPosition) -> bool: ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SimpleString(_BasePrefixedString): """ Any sort of literal string expression that is not a :class:`FormattedString` @@ -716,8 +702,7 @@ class BaseFormattedStringContent(CSTNode, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FormattedStringText(BaseFormattedStringContent): """ Part of a :class:`FormattedString` that is not inside curly braces (``{`` or ``}``). @@ -742,8 +727,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(self.value) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FormattedStringExpression(BaseFormattedStringContent): """ Part of a :class:`FormattedString` that is inside curly braces (``{`` or ``}``), @@ -839,8 +823,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token("}") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FormattedString(_BasePrefixedString): """ An "f-string". These formatted strings are string literals prefixed by the letter @@ -958,8 +941,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(self.end) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ConcatenatedString(BaseString): """ Represents an implicitly concatenated string, such as:: @@ -1055,8 +1037,7 @@ def evaluated_value(self) -> Union[str, bytes, None]: return None -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ComparisonTarget(CSTNode): """ A target for a :class:`Comparison`. Owns the comparison operator and the value to @@ -1094,8 +1075,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.comparator._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Comparison(BaseExpression): """ A comparison between multiple values such as ``x < y``, ``x < y < z``, or @@ -1183,8 +1163,7 @@ def _codegen_impl(self, state: CodegenState) -> None: comp._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class UnaryOperation(BaseExpression): """ Any generic unary expression, such as ``not x`` or ``-x``. :class:`UnaryOperation` @@ -1245,8 +1224,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.expression._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BinaryOperation(BaseExpression): """ An operation that combines two expression such as ``x << y`` or ``y + z``. @@ -1298,8 +1276,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.right._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BooleanOperation(BaseExpression): """ An operation that combines two booleans such as ``x or y`` or ``z and w`` @@ -1370,8 +1347,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.right._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Attribute(BaseAssignTargetExpression, BaseDelTargetExpression): """ An attribute reference, such as ``x.y``. @@ -1436,8 +1412,7 @@ class BaseSlice(CSTNode, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Index(BaseSlice): """ Any index as passed to a :class:`Subscript`. In ``x[2]``, this would be the ``2`` @@ -1473,8 +1448,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.value._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Slice(BaseSlice): """ Any slice operation in a :class:`Subscript`, such as ``1:``, ``2:3:4``, etc. @@ -1527,8 +1501,7 @@ def _codegen_impl(self, state: CodegenState) -> None: step._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SubscriptElement(CSTNode): """ Part of a sequence of slices in a :class:`Subscript`, such as ``1:2, 3``. This is @@ -1561,8 +1534,7 @@ def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> Non comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Subscript(BaseAssignTargetExpression, BaseDelTargetExpression): """ A indexed subscript reference (:class:`Index`) such as ``x[2]``, a :class:`Slice` @@ -1626,8 +1598,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.rbracket._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Annotation(CSTNode): """ An annotation for a function (`PEP 3107`_) or on a variable (`PEP 526`_). Typically @@ -1700,8 +1671,7 @@ def _codegen_impl( self.annotation._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ParamStar(CSTNode): """ A sentinel indicator on a :class:`Parameters` list to denote that the subsequent @@ -1723,8 +1693,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ParamSlash(CSTNode): """ A sentinel indicator on a :class:`Parameters` list to denote that the previous @@ -1762,8 +1731,7 @@ def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> Non comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Param(CSTNode): """ A positional or keyword argument in a :class:`Parameters` list. May contain an @@ -1861,8 +1829,7 @@ def _codegen_impl( self.whitespace_after_param._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Parameters(CSTNode): """ A function or lambda parameter list. @@ -2067,8 +2034,7 @@ def _codegen_impl(self, state: CodegenState) -> None: # noqa: C901 star_kwarg._codegen(state, default_star="**", default_comma=False) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Lambda(BaseExpression): """ A lambda expression that creates an anonymous function. @@ -2180,8 +2146,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.body._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Arg(CSTNode): """ A single argument to a :class:`Call`. @@ -2364,8 +2329,7 @@ def _validate(self) -> None: validator = validator(arg) or validator -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Call(_BaseExpressionWithArgs): """ An expression representing a function call, such as ``do_math(1, 2)`` or @@ -2436,8 +2400,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(")") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Await(BaseExpression): """ An await expression. Await expressions are only valid inside the body of an @@ -2485,8 +2448,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.expression._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class IfExp(BaseExpression): """ An if expression of the form ``body if test else orelse``. @@ -2592,8 +2554,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.orelse._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class From(CSTNode): """ A ``from x`` stanza in a :class:`Yield` or :class:`Raise`. @@ -2644,8 +2605,7 @@ def _codegen_impl(self, state: CodegenState, default_space: str = "") -> None: self.item._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Yield(BaseExpression): """ A yield expression similar to ``yield x`` or ``yield from fun()``. @@ -2772,8 +2732,7 @@ class BaseDictElement(_BaseElementImpl, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Element(BaseElement): """ A simple value in a literal :class:`List`, :class:`Tuple`, or :class:`Set`. @@ -2804,8 +2763,7 @@ def _codegen_impl( self._codegen_comma(state, default_comma, default_comma_whitespace) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class DictElement(BaseDictElement): """ A simple ``key: value`` pair that represents a single entry in a literal @@ -2855,8 +2813,7 @@ def _codegen_impl( self._codegen_comma(state, default_comma, default_comma_whitespace) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class StarredElement(BaseElement, BaseExpression, _BaseParenthesizedNode): """ A starred ``*value`` element that expands to represent multiple values in a literal @@ -2916,8 +2873,7 @@ def _codegen_impl( self._codegen_comma(state, default_comma, default_comma_whitespace) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class StarredDictElement(BaseDictElement): """ A starred ``**value`` element that expands to represent multiple values in a literal @@ -2961,8 +2917,7 @@ def _codegen_impl( self._codegen_comma(state, default_comma, default_comma_whitespace) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Tuple(BaseAssignTargetExpression, BaseDelTargetExpression): """ An immutable literal tuple. Tuples are often (but not always) parenthesized. @@ -3073,8 +3028,7 @@ def _bracketize(self, state: CodegenState) -> Generator[None, None, None]: self.rbracket._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class List(BaseList, BaseAssignTargetExpression, BaseDelTargetExpression): """ A mutable literal list. @@ -3165,8 +3119,7 @@ class BaseSet(_BaseSetOrDict, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Set(BaseSet): """ A mutable literal set. @@ -3236,8 +3189,7 @@ class BaseDict(_BaseSetOrDict, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Dict(BaseDict): """ A literal dictionary. Key-value pairs are stored in ``elements`` using @@ -3285,8 +3237,7 @@ def _codegen_impl(self, state: CodegenState) -> None: ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class CompFor(CSTNode): """ One ``for`` clause in a :class:`BaseComp`, or a nested hierarchy of @@ -3461,8 +3412,7 @@ def _codegen_impl(self, state: CodegenState) -> None: inner_for_in._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class CompIf(CSTNode): """ A conditional clause in a :class:`CompFor`, used as part of a generator or @@ -3549,8 +3499,7 @@ def _validate(self) -> None: ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class GeneratorExp(BaseSimpleComp): """ A generator expression. ``elt`` represents the value yielded for each item in @@ -3600,8 +3549,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.for_in._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ListComp(BaseList, BaseSimpleComp): """ A list comprehension. ``elt`` represents the value stored for each item in @@ -3642,8 +3590,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.for_in._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SetComp(BaseSet, BaseSimpleComp): """ A set comprehension. ``elt`` represents the value stored for each item in @@ -3684,8 +3631,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.for_in._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class DictComp(BaseDict, BaseComp): """ A dictionary comprehension. ``key`` and ``value`` represent the dictionary entry @@ -3759,8 +3705,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.for_in._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class NamedExpr(BaseExpression): """ An expression that is also an assignment, such as ``x := y + z``. Affectionately diff --git a/libcst/_nodes/internal.py b/libcst/_nodes/internal.py index 35d897435..f72a75ee1 100644 --- a/libcst/_nodes/internal.py +++ b/libcst/_nodes/internal.py @@ -8,7 +8,6 @@ from dataclasses import dataclass, field from typing import Iterable, Iterator, List, Optional, Sequence, TYPE_CHECKING, Union -from libcst._add_slots import add_slots from libcst._flatten_sentinel import FlattenSentinel from libcst._maybe_sentinel import MaybeSentinel from libcst._removal_sentinel import RemovalSentinel @@ -20,8 +19,7 @@ from libcst._visitors import CSTVisitorT -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class CodegenState: # These are derived from a Module default_indent: str diff --git a/libcst/_nodes/module.py b/libcst/_nodes/module.py index 9ed45716a..470c78f23 100644 --- a/libcst/_nodes/module.py +++ b/libcst/_nodes/module.py @@ -6,7 +6,6 @@ from dataclasses import dataclass from typing import cast, Optional, Sequence, TYPE_CHECKING, TypeVar, Union -from libcst._add_slots import add_slots from libcst._nodes.base import CSTNode from libcst._nodes.internal import CodegenState, visit_body_sequence, visit_sequence from libcst._nodes.statement import ( @@ -29,8 +28,7 @@ builtin_bytes = bytes -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Module(CSTNode): """ Contains some top-level information inferred from the file letting us set correct diff --git a/libcst/_nodes/op.py b/libcst/_nodes/op.py index e19d24d34..de7c1471d 100644 --- a/libcst/_nodes/op.py +++ b/libcst/_nodes/op.py @@ -7,7 +7,6 @@ from dataclasses import dataclass from typing import Tuple -from libcst._add_slots import add_slots from libcst._nodes.base import BaseLeaf, CSTNode, CSTValidationError from libcst._nodes.internal import CodegenState, visit_required from libcst._nodes.whitespace import BaseParenthesizableWhitespace, SimpleWhitespace @@ -155,8 +154,7 @@ class BaseAugOp(CSTNode, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Semicolon(_BaseOneTokenOp): """ Used by any small statement (any subclass of :class:`BaseSmallStatement` @@ -174,8 +172,7 @@ def _get_token(self) -> str: return ";" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Colon(_BaseOneTokenOp): """ Used by :class:`Slice` as a separator between subsequent expressions, @@ -192,8 +189,7 @@ def _get_token(self) -> str: return ":" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Comma(_BaseOneTokenOp): """ Syntactic trivia used as a separator between subsequent items in various @@ -216,8 +212,7 @@ def _get_token(self) -> str: return "," -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Dot(_BaseOneTokenOp): """ Used by :class:`Attribute` as a separator between subsequent :class:`Name` nodes. @@ -233,8 +228,7 @@ def _get_token(self) -> str: return "." -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ImportStar(BaseLeaf): """ Used by :class:`ImportFrom` to denote a star import instead of a list @@ -245,8 +239,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token("*") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AssignEqual(_BaseOneTokenOp): """ Used by :class:`AnnAssign` to denote a single equal character when doing an @@ -266,8 +259,7 @@ def _get_token(self) -> str: return "=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Plus(BaseUnaryOp): """ A unary operator that can be used in a :class:`UnaryOperation` @@ -281,8 +273,7 @@ def _get_token(self) -> str: return "+" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Minus(BaseUnaryOp): """ A unary operator that can be used in a :class:`UnaryOperation` @@ -296,8 +287,7 @@ def _get_token(self) -> str: return "-" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitInvert(BaseUnaryOp): """ A unary operator that can be used in a :class:`UnaryOperation` @@ -311,8 +301,7 @@ def _get_token(self) -> str: return "~" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Not(BaseUnaryOp): """ A unary operator that can be used in a :class:`UnaryOperation` @@ -326,8 +315,7 @@ def _get_token(self) -> str: return "not" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class And(BaseBooleanOp): """ A boolean operator that can be used in a :class:`BooleanOperation` @@ -344,8 +332,7 @@ def _get_token(self) -> str: return "and" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Or(BaseBooleanOp): """ A boolean operator that can be used in a :class:`BooleanOperation` @@ -362,8 +349,7 @@ def _get_token(self) -> str: return "or" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Add(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -380,8 +366,7 @@ def _get_token(self) -> str: return "+" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Subtract(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -398,8 +383,7 @@ def _get_token(self) -> str: return "-" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Multiply(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -416,8 +400,7 @@ def _get_token(self) -> str: return "*" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Divide(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -434,8 +417,7 @@ def _get_token(self) -> str: return "/" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FloorDivide(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -452,8 +434,7 @@ def _get_token(self) -> str: return "//" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Modulo(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -470,8 +451,7 @@ def _get_token(self) -> str: return "%" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Power(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -488,8 +468,7 @@ def _get_token(self) -> str: return "**" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LeftShift(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -506,8 +485,7 @@ def _get_token(self) -> str: return "<<" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class RightShift(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -524,8 +502,7 @@ def _get_token(self) -> str: return ">>" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitOr(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -542,8 +519,7 @@ def _get_token(self) -> str: return "|" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitAnd(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -560,8 +536,7 @@ def _get_token(self) -> str: return "&" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitXor(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -578,8 +553,7 @@ def _get_token(self) -> str: return "^" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatrixMultiply(BaseBinaryOp, _BaseOneTokenOp): """ A binary operator that can be used in a :class:`BinaryOperation` @@ -596,8 +570,7 @@ def _get_token(self) -> str: return "@" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LessThan(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -613,8 +586,7 @@ def _get_token(self) -> str: return "<" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class GreaterThan(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -630,8 +602,7 @@ def _get_token(self) -> str: return ">" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Equal(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -647,8 +618,7 @@ def _get_token(self) -> str: return "==" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LessThanEqual(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -664,8 +634,7 @@ def _get_token(self) -> str: return "<=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class GreaterThanEqual(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -681,8 +650,7 @@ def _get_token(self) -> str: return ">=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class NotEqual(BaseCompOp, _BaseOneTokenOp): """ A comparison operator that can be used in a :class:`Comparison` expression. @@ -720,8 +688,7 @@ def _get_token(self) -> str: return self.value -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class In(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -737,8 +704,7 @@ def _get_token(self) -> str: return "in" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class NotIn(BaseCompOp, _BaseTwoTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -760,8 +726,7 @@ def _get_tokens(self) -> Tuple[str, str]: return ("not", "in") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Is(BaseCompOp, _BaseOneTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -777,8 +742,7 @@ def _get_token(self) -> str: return "is" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class IsNot(BaseCompOp, _BaseTwoTokenOp): """ A comparision operator that can be used in a :class:`Comparison` expression. @@ -800,8 +764,7 @@ def _get_tokens(self) -> Tuple[str, str]: return ("is", "not") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AddAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -818,8 +781,7 @@ def _get_token(self) -> str: return "+=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SubtractAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -836,8 +798,7 @@ def _get_token(self) -> str: return "-=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MultiplyAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -854,8 +815,7 @@ def _get_token(self) -> str: return "*=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatrixMultiplyAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -872,8 +832,7 @@ def _get_token(self) -> str: return "@=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class DivideAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -890,8 +849,7 @@ def _get_token(self) -> str: return "/=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ModuloAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -908,8 +866,7 @@ def _get_token(self) -> str: return "%=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitAndAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -926,8 +883,7 @@ def _get_token(self) -> str: return "&=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitOrAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -944,8 +900,7 @@ def _get_token(self) -> str: return "|=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class BitXorAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -962,8 +917,7 @@ def _get_token(self) -> str: return "^=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class LeftShiftAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -980,8 +934,7 @@ def _get_token(self) -> str: return "<<=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class RightShiftAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -998,8 +951,7 @@ def _get_token(self) -> str: return ">>=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class PowerAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` @@ -1016,8 +968,7 @@ def _get_token(self) -> str: return "**=" -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FloorDivideAssign(BaseAugOp, _BaseOneTokenOp): """ An augmented assignment operator that can be used in a :class:`AugAssign` diff --git a/libcst/_nodes/statement.py b/libcst/_nodes/statement.py index bf9e8ecc1..18b7c83e5 100644 --- a/libcst/_nodes/statement.py +++ b/libcst/_nodes/statement.py @@ -9,7 +9,6 @@ from dataclasses import dataclass, field from typing import Optional, Pattern, Sequence, Union -from libcst._add_slots import add_slots from libcst._maybe_sentinel import MaybeSentinel from libcst._nodes.base import CSTNode, CSTValidationError from libcst._nodes.expression import ( @@ -117,8 +116,7 @@ def _codegen_impl( ... -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Del(BaseSmallStatement): """ Represents a ``del`` statement. ``del`` is always followed by a target. @@ -169,8 +167,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Pass(BaseSmallStatement): """ Represents a ``pass`` statement. @@ -199,8 +196,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Break(BaseSmallStatement): """ Represents a ``break`` statement, which is used to break out of a :class:`For` @@ -230,8 +226,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Continue(BaseSmallStatement): """ Represents a ``continue`` statement, which is used to skip to the next iteration @@ -261,8 +256,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Return(BaseSmallStatement): """ Represents a ``return`` or a ``return x`` statement. @@ -326,8 +320,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Expr(BaseSmallStatement): """ An expression used as a statement, where the result is unused and unassigned. @@ -411,8 +404,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.trailing_whitespace._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SimpleStatementLine(_BaseSimpleStatement, BaseStatement): """ A simple statement that's part of an IndentedBlock or Module. A simple statement is @@ -458,8 +450,7 @@ def _codegen_impl(self, state: CodegenState) -> None: _BaseSimpleStatement._codegen_impl(self, state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SimpleStatementSuite(_BaseSimpleStatement, BaseSuite): """ A simple statement that's used as a suite. A simple statement is a series of small @@ -503,8 +494,7 @@ def _codegen_impl(self, state: CodegenState) -> None: _BaseSimpleStatement._codegen_impl(self, state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Else(CSTNode): """ An ``else`` clause that appears optionally after an :class:`If`, :class:`While`, @@ -569,8 +559,7 @@ class BaseCompoundStatement(BaseStatement, ABC): leading_lines: Sequence[EmptyLine] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class If(BaseCompoundStatement): """ An ``if`` statement. ``test`` holds a single test expression. @@ -638,8 +627,7 @@ def _codegen_impl(self, state: CodegenState, is_elif: bool = False) -> None: orelse._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class IndentedBlock(BaseSuite): """ Represents a block of statements beginning with an ``INDENT`` token and ending in a @@ -728,8 +716,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.decrease_indent() -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AsName(CSTNode): """ An ``as name`` clause inside an :class:`ExceptHandler`, :class:`ImportAlias` or @@ -772,8 +759,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.name._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ExceptHandler(CSTNode): """ An ``except`` clause that appears optionally after a :class:`Try` statement. @@ -862,8 +848,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.body._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ExceptStarHandler(CSTNode): """ An ``except*`` clause that appears after a :class:`TryStar` statement. @@ -938,8 +923,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.body._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Finally(CSTNode): """ A ``finally`` clause that appears optionally after a :class:`Try` statement. @@ -978,8 +962,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.body._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Try(BaseCompoundStatement): """ A regular ``try`` statement that cannot contain :class:`ExceptStar` blocks. For @@ -1059,8 +1042,7 @@ def _codegen_impl(self, state: CodegenState) -> None: finalbody._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TryStar(BaseCompoundStatement): """ A ``try`` statement with ``except*`` blocks. @@ -1128,8 +1110,7 @@ def _codegen_impl(self, state: CodegenState) -> None: finalbody._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ImportAlias(CSTNode): """ An import, with an optional :class:`AsName`. Used in both :class:`Import` and @@ -1216,8 +1197,7 @@ def evaluated_alias(self) -> Optional[str]: return None -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Import(BaseSmallStatement): """ An ``import`` statement. @@ -1273,8 +1253,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ImportFrom(BaseSmallStatement): """ A ``from x import y`` statement. @@ -1420,8 +1399,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AssignTarget(CSTNode): """ A target for an :class:`Assign`. Owns the equals sign and the whitespace around it. @@ -1456,8 +1434,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.whitespace_after_equal._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Assign(BaseSmallStatement): """ An assignment statement such as ``x = y`` or ``x = y = z``. Unlike @@ -1504,8 +1481,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AnnAssign(BaseSmallStatement): """ An assignment statement such as ``x: int = 5`` or ``x: int``. This only @@ -1569,8 +1545,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AugAssign(BaseSmallStatement): """ An augmented assignment statement, such as ``x += 5``. @@ -1613,8 +1588,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Decorator(CSTNode): """ A single decorator that decorates a :class:`FunctionDef` or a :class:`ClassDef`. @@ -1698,8 +1672,7 @@ def get_docstring_impl( return evaluated_value -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FunctionDef(BaseCompoundStatement): """ A function definition. @@ -1854,8 +1827,7 @@ def get_docstring(self, clean: bool = True) -> Optional[str]: return get_docstring_impl(self.body, clean) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ClassDef(BaseCompoundStatement): """ A class definition. @@ -2030,8 +2002,7 @@ def get_docstring(self, clean: bool = True) -> Optional[str]: return get_docstring_impl(self.body, clean) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class WithItem(CSTNode): """ A single context manager in a :class:`With` block, with an optional variable name. @@ -2078,8 +2049,7 @@ def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> Non comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class With(BaseCompoundStatement): """ A ``with`` statement. @@ -2200,8 +2170,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.body._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class For(BaseCompoundStatement): """ A ``for target in iter`` statement. @@ -2314,8 +2283,7 @@ def _codegen_impl(self, state: CodegenState) -> None: orelse._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class While(BaseCompoundStatement): """ A ``while`` statement. @@ -2383,8 +2351,7 @@ def _codegen_impl(self, state: CodegenState) -> None: orelse._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Raise(BaseSmallStatement): """ A ``raise exc`` or ``raise exc from cause`` statement. @@ -2475,8 +2442,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Assert(BaseSmallStatement): """ An assert statement such as ``assert x > 5`` or ``assert x > 5, 'Uh oh!'`` @@ -2547,8 +2513,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class NameItem(CSTNode): """ A single identifier name inside a :class:`Global` or :class:`Nonlocal` statement. @@ -2587,8 +2552,7 @@ def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> Non comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Global(BaseSmallStatement): """ A ``global`` statement. @@ -2645,8 +2609,7 @@ def _codegen_impl( semicolon._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Nonlocal(BaseSmallStatement): """ A ``nonlocal`` statement. @@ -2715,8 +2678,7 @@ class MatchPattern(_BaseParenthesizedNode, ABC): __slots__ = () -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) # pyre-fixme[13]: Attribute `body` is never initialized. class Match(BaseCompoundStatement): """ @@ -2813,8 +2775,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.decrease_indent() -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchCase(CSTNode): """ A single ``case`` block of a :class:`Match` statement. @@ -2889,8 +2850,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.body._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchValue(MatchPattern): """ A match literal or value pattern that compares by equality. @@ -2923,8 +2883,7 @@ def rpar(self, value: Sequence[RightParen]) -> None: self.value.rpar = value -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchSingleton(MatchPattern): """ A match literal pattern that compares by identity. @@ -2965,8 +2924,7 @@ def rpar(self, value: Sequence[RightParen]) -> None: self.value.rpar = value -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchSequenceElement(CSTNode): """ An element in a sequence match pattern. @@ -3000,8 +2958,7 @@ def _codegen_impl( comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchStar(CSTNode): """ A starred element in a sequence match pattern. Matches the rest of the sequence. @@ -3059,8 +3016,7 @@ class MatchSequence(MatchPattern, ABC): patterns: Sequence[Union[MatchSequenceElement, MatchStar]] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchList(MatchSequence): """ A list match pattern. It's either an "open sequence pattern" (without brackets) or a @@ -3116,8 +3072,7 @@ def _codegen_impl(self, state: CodegenState) -> None: rbracket._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchTuple(MatchSequence): """ A tuple match pattern. @@ -3158,8 +3113,7 @@ def _codegen_impl(self, state: CodegenState) -> None: ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchMappingElement(CSTNode): """ A ``key: value`` pair in a match mapping pattern. @@ -3208,8 +3162,7 @@ def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> Non comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchMapping(MatchPattern): """ A match mapping pattern. @@ -3280,8 +3233,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.rbrace._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchKeywordElement(CSTNode): """ A key=value pair in a :class:`MatchClass`. @@ -3330,8 +3282,7 @@ def _codegen_impl(self, state: CodegenState, default_comma: bool = False) -> Non comma._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchClass(MatchPattern): """ A match class pattern. @@ -3400,8 +3351,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(")") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchAs(MatchPattern): """ A match "as-pattern", capture pattern, or wildcard pattern. @@ -3475,8 +3425,7 @@ def _codegen_impl(self, state: CodegenState) -> None: name._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchOrElement(CSTNode): """ An element in a :class:`MatchOr` node. @@ -3505,8 +3454,7 @@ def _codegen_impl( sep._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class MatchOr(MatchPattern): """ A match "or-pattern". It matches each of its subpatterns in turn to the subject, @@ -3536,8 +3484,7 @@ def _codegen_impl(self, state: CodegenState) -> None: pat._codegen(state, default_separator=idx + 1 < len(pats)) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TypeVar(CSTNode): """ A simple (non-variadic) type variable. @@ -3578,8 +3525,7 @@ def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVar": ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TypeVarTuple(CSTNode): """ A variadic type variable. @@ -3607,8 +3553,7 @@ def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeVarTuple": ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ParamSpec(CSTNode): """ A parameter specification. @@ -3639,8 +3584,7 @@ def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "ParamSpec": ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TypeParam(CSTNode): """ A single type parameter that is contained in a :class:`TypeParameters` list. @@ -3669,8 +3613,7 @@ def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParam": ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TypeParameters(CSTNode): """ Type parameters when specified with PEP-695 syntax. @@ -3701,8 +3644,7 @@ def _visit_and_replace_children(self, visitor: CSTVisitorT) -> "TypeParameters": ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TypeAlias(BaseSmallStatement): """ A type alias statement. diff --git a/libcst/_nodes/whitespace.py b/libcst/_nodes/whitespace.py index b1332c132..d8356c857 100644 --- a/libcst/_nodes/whitespace.py +++ b/libcst/_nodes/whitespace.py @@ -9,7 +9,6 @@ from dataclasses import dataclass from typing import Optional, Pattern, Sequence -from libcst._add_slots import add_slots from libcst._nodes.base import BaseLeaf, BaseValueToken, CSTNode, CSTValidationError from libcst._nodes.internal import ( CodegenState, @@ -62,8 +61,7 @@ def empty(self) -> bool: ... -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SimpleWhitespace(BaseParenthesizableWhitespace, BaseValueToken): """ This is the kind of whitespace you might see inside the body of a statement or @@ -104,8 +102,7 @@ def empty(self) -> bool: return len(self.value) == 0 -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Newline(BaseLeaf): """ Represents the newline that ends an :class:`EmptyLine` or a statement (as part of @@ -138,8 +135,7 @@ def _codegen_impl(self, state: CodegenState) -> None: state.add_token(state.default_newline if value is None else value) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Comment(BaseValueToken): """ A comment including the leading pound (``#``) character. @@ -165,8 +161,7 @@ def _validate(self) -> None: ) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class TrailingWhitespace(CSTNode): """ The whitespace at the end of a line after a statement. If a line contains only @@ -197,8 +192,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.newline._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class EmptyLine(CSTNode): """ Represents a line with only whitespace/comments. Usually statements will own any @@ -238,8 +232,7 @@ def _codegen_impl(self, state: CodegenState) -> None: self.newline._codegen(state) -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ParenthesizedWhitespace(BaseParenthesizableWhitespace): """ This is the kind of whitespace you might see inside a parenthesized expression diff --git a/libcst/_parser/types/config.py b/libcst/_parser/types/config.py index 1fc32371f..535543bcd 100644 --- a/libcst/_parser/types/config.py +++ b/libcst/_parser/types/config.py @@ -10,7 +10,6 @@ from enum import Enum from typing import Any, Callable, FrozenSet, List, Mapping, Optional, Pattern, Union -from libcst._add_slots import add_slots from libcst._nodes.whitespace import NEWLINE_RE from libcst._parser.parso.utils import parse_version_string, PythonVersionInfo @@ -47,8 +46,7 @@ def __repr__(self) -> str: KNOWN_PYTHON_VERSION_STRINGS = ["3.0", "3.1", "3.3", "3.5", "3.6", "3.7", "3.8"] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class PartialParserConfig: r""" An optional object that can be supplied to the parser entrypoints (e.g. diff --git a/libcst/_parser/types/partials.py b/libcst/_parser/types/partials.py index 4db89fab4..0585e77c1 100644 --- a/libcst/_parser/types/partials.py +++ b/libcst/_parser/types/partials.py @@ -7,7 +7,6 @@ from dataclasses import dataclass from typing import Generic, Optional, Sequence, TypeVar, Union -from libcst._add_slots import add_slots from libcst._nodes.expression import ( Annotation, Arg, @@ -32,51 +31,44 @@ _T = TypeVar("_T") -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class WithLeadingWhitespace(Generic[_T]): value: _T whitespace_before: WhitespaceState -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SimpleStatementPartial: body: Sequence[BaseSmallStatement] whitespace_before: WhitespaceState trailing_whitespace: TrailingWhitespace -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SlicePartial: second_colon: Colon step: Optional[BaseExpression] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AttributePartial: dot: Dot attr: Name -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ArglistPartial: args: Sequence[Arg] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class CallPartial: lpar: WithLeadingWhitespace[LeftParen] args: Sequence[Arg] rpar: RightParen -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class SubscriptPartial: slice: Union[Index, Slice, Sequence[SubscriptElement]] lbracket: LeftSquareBracket @@ -84,23 +76,20 @@ class SubscriptPartial: whitespace_before: WhitespaceState -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AnnAssignPartial: annotation: Annotation equal: Optional[AssignEqual] value: Optional[BaseExpression] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AugAssignPartial: operator: BaseAugOp value: BaseExpression -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class AssignPartial: equal: AssignEqual value: BaseExpression @@ -110,49 +99,42 @@ class ParamStarPartial: pass -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FuncdefPartial: lpar: LeftParen params: Parameters rpar: RightParen -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class DecoratorPartial: decorators: Sequence[Decorator] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ImportPartial: names: Sequence[ImportAlias] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ImportRelativePartial: relative: Sequence[Dot] module: Optional[Union[Attribute, Name]] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FormattedStringConversionPartial: value: str whitespace_before: WhitespaceState -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class FormattedStringFormatSpecPartial: values: Sequence[BaseFormattedStringContent] whitespace_before: WhitespaceState -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class ExceptClausePartial: leading_lines: Sequence[EmptyLine] whitespace_after_except: SimpleWhitespace diff --git a/libcst/_parser/types/py_token.py b/libcst/_parser/types/py_token.py index d2f9b5379..06fb07d55 100644 --- a/libcst/_parser/types/py_token.py +++ b/libcst/_parser/types/py_token.py @@ -7,13 +7,11 @@ from dataclasses import dataclass from typing import Optional, Tuple -from libcst._add_slots import add_slots from libcst._parser.parso.python.token import TokenType from libcst._parser.types.whitespace_state import WhitespaceState -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class Token: type: TokenType string: str diff --git a/libcst/_parser/types/py_whitespace_state.py b/libcst/_parser/types/py_whitespace_state.py index 6359e83eb..2c7025a08 100644 --- a/libcst/_parser/types/py_whitespace_state.py +++ b/libcst/_parser/types/py_whitespace_state.py @@ -5,11 +5,9 @@ from dataclasses import dataclass -from libcst._add_slots import add_slots -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class WhitespaceState: """ A frequently mutated store of the whitespace parser's current state. This object diff --git a/libcst/_parser/wrapped_tokenize.py b/libcst/_parser/wrapped_tokenize.py index 8d6010523..e8f2ec616 100644 --- a/libcst/_parser/wrapped_tokenize.py +++ b/libcst/_parser/wrapped_tokenize.py @@ -24,7 +24,6 @@ from enum import Enum from typing import Generator, Iterator, List, Optional, Sequence -from libcst._add_slots import add_slots from libcst._exceptions import ParserSyntaxError from libcst._parser.parso.python.token import PythonTokenTypes, TokenType from libcst._parser.parso.python.tokenize import ( @@ -61,8 +60,7 @@ class _ParenthesisOrFStringStackEntry(Enum): ) -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class _TokenizeState: lines: Sequence[str] previous_whitespace_state: WhitespaceState = field( diff --git a/libcst/_position.py b/libcst/_position.py index d7ba0d072..339fcfb5a 100644 --- a/libcst/_position.py +++ b/libcst/_position.py @@ -15,13 +15,10 @@ from dataclasses import dataclass from typing import cast, overload, Tuple, Union -from libcst._add_slots import add_slots - _CodePositionT = Union[Tuple[int, int], "CodePosition"] -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class CodePosition: #: Line numbers are 1-indexed. line: int @@ -29,8 +26,7 @@ class CodePosition: column: int -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) # pyre-fixme[13]: Attribute `end` is never initialized. # pyre-fixme[13]: Attribute `start` is never initialized. class CodeRange: diff --git a/libcst/metadata/position_provider.py b/libcst/metadata/position_provider.py index bbc9bb72f..e55f30982 100644 --- a/libcst/metadata/position_provider.py +++ b/libcst/metadata/position_provider.py @@ -9,7 +9,6 @@ from dataclasses import dataclass, field from typing import Iterator, List, Optional, Pattern -from libcst._add_slots import add_slots from libcst._nodes.base import CSTNode from libcst._nodes.internal import CodegenState from libcst._nodes.module import Module @@ -19,8 +18,7 @@ NEWLINE_RE: Pattern[str] = re.compile(r"\r\n?|\n") -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class WhitespaceInclusivePositionProvidingCodegenState(CodegenState): # These are derived from a Module default_indent: str @@ -88,8 +86,7 @@ def _gen_impl(self, module: Module) -> None: module._codegen(state) -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class PositionProvidingCodegenState(WhitespaceInclusivePositionProvidingCodegenState): @contextmanager def record_syntactic_position( diff --git a/libcst/metadata/reentrant_codegen.py b/libcst/metadata/reentrant_codegen.py index 899d2f1fd..304c6357c 100644 --- a/libcst/metadata/reentrant_codegen.py +++ b/libcst/metadata/reentrant_codegen.py @@ -8,7 +8,6 @@ from typing import List, Optional, Sequence from libcst import BaseStatement, CSTNode, Module -from libcst._add_slots import add_slots from libcst._nodes.internal import CodegenState from libcst.metadata import BaseMetadataProvider @@ -98,8 +97,7 @@ def get_modified_module_bytes(self, node: BaseStatement) -> bytes: ) -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class _ReentrantCodegenState(CodegenState): provider: BaseMetadataProvider[CodegenPartial] encoding: str = "utf-8" diff --git a/libcst/metadata/scope_provider.py b/libcst/metadata/scope_provider.py index 75f37a06e..6ac213d34 100644 --- a/libcst/metadata/scope_provider.py +++ b/libcst/metadata/scope_provider.py @@ -26,7 +26,6 @@ import libcst as cst from libcst import ensure_type -from libcst._add_slots import add_slots from libcst.helpers import get_full_name_for_node from libcst.metadata.base_provider import BatchableMetadataProvider from libcst.metadata.expression_context_provider import ( @@ -58,8 +57,7 @@ ) -@add_slots -@dataclass(frozen=False) +@dataclass(slots=True, frozen=False) class Access: """ An Access records an access of an assignment. @@ -140,8 +138,7 @@ class QualifiedNameSource(Enum): LOCAL = auto() -@add_slots -@dataclass(frozen=True) +@dataclass(slots=True, frozen=True) class QualifiedName: #: Qualified name, e.g. ``a.b.c`` or ``fn..var``. name: str diff --git a/libcst/tests/test_add_slots.py b/libcst/tests/test_add_slots.py deleted file mode 100644 index e354f60b6..000000000 --- a/libcst/tests/test_add_slots.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) Meta Platforms, Inc. and affiliates. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -import pickle -from dataclasses import dataclass -from typing import ClassVar - -from libcst._add_slots import add_slots - -from libcst.testing.utils import UnitTest - - -# this test class needs to be defined at module level to test pickling. -@add_slots -@dataclass(frozen=True) -class A: - x: int - y: str - - Z: ClassVar[int] = 5 - - -class AddSlotsTest(UnitTest): - def test_pickle(self) -> None: - a = A(1, "foo") - self.assertEqual(a, pickle.loads(pickle.dumps(a))) - object.__delattr__(a, "y") - self.assertEqual(a.x, pickle.loads(pickle.dumps(a)).x) - - def test_prevents_slots_overlap(self) -> None: - class A: - __slots__ = ("x",) - - class B(A): - __slots__ = ("z",) - - @add_slots - @dataclass - class C(B): - x: int - y: str - z: bool - - self.assertSequenceEqual(C.__slots__, ("y",))