import dataclasses
import inspect
from dataclasses import dataclass, field
from pprint import pprint

import attr


class ManualComment:
    def __init__(self, id: int, text: str):
        self.id: int = id
        self.text: str = text

    def __repr__(self):
        return "{}(id={}, text={})".format(self.__class__.__name__, self.id, self.text)

    def __eq__(self, other):
        if other.__class__ is self.__class__:
            return (self.id, self.text) == (other.id, other.text)
        else:
            return NotImplemented

    def __ne__(self, other):
        result = self.__eq__(other)
        if result is NotImplemented:
            return NotImplemented
        else:
            return not result

    def __hash__(self):
        return hash((self.__class__, self.id, self.text))

    def __lt__(self, other):
        if other.__class__ is self.__class__:
            return (self.id, self.text) < (other.id, other.text)
        else:
            return NotImplemented

    def __le__(self, other):
        if other.__class__ is self.__class__:
            return (self.id, self.text) <= (other.id, other.text)
        else:
            return NotImplemented

    def __gt__(self, other):
        if other.__class__ is self.__class__:
            return (self.id, self.text) > (other.id, other.text)
        else:
            return NotImplemented

    def __ge__(self, other):
        if other.__class__ is self.__class__:
            return (self.id, self.text) >= (other.id, other.text)
        else:
            return NotImplemented


@dataclass(frozen=True, order=True)
class Comment:
    id: int
    text: str = ""
    replies: list[int] = field(default_factory=list, repr=False, compare=False)


@attr.s(frozen=True, order=True, slots=True)
class AttrComment:
    id: int = 0
    text: str = ""


def main():
    comment = Comment(1, "I just subscribed!")
    # comment.id = 3  # can't immutable
    print(comment)
    print(dataclasses.astuple(comment))
    print(dataclasses.asdict(comment))
    copy = dataclasses.replace(comment, id=3)
    print(copy)

    pprint(inspect.getmembers(Comment, inspect.isfunction))


if __name__ == '__main__':
    main()

[((1565, 1599), 'dataclasses.dataclass', 'dataclass', ([], {'frozen': '(True)', 'order': '(True)'}), '(frozen=True, order=True)\n', (1574, 1599), False, 'from dataclasses import dataclass, field\n'), ((1729, 1772), 'attr.s', 'attr.s', ([], {'frozen': '(True)', 'order': '(True)', 'slots': '(True)'}), '(frozen=True, order=True, slots=True)\n', (1735, 1772), False, 'import attr\n'), ((1671, 1725), 'dataclasses.field', 'field', ([], {'default_factory': 'list', 'repr': '(False)', 'compare': '(False)'}), '(default_factory=list, repr=False, compare=False)\n', (1676, 1725), False, 'from dataclasses import dataclass, field\n'), ((2037, 2071), 'dataclasses.replace', 'dataclasses.replace', (['comment'], {'id': '(3)'}), '(comment, id=3)\n', (2056, 2071), False, 'import dataclasses\n'), ((1957, 1985), 'dataclasses.astuple', 'dataclasses.astuple', (['comment'], {}), '(comment)\n', (1976, 1985), False, 'import dataclasses\n'), ((1997, 2024), 'dataclasses.asdict', 'dataclasses.asdict', (['comment'], {}), '(comment)\n', (2015, 2024), False, 'import dataclasses\n'), ((2100, 2147), 'inspect.getmembers', 'inspect.getmembers', (['Comment', 'inspect.isfunction'], {}), '(Comment, inspect.isfunction)\n', (2118, 2147), False, 'import inspect\n')]