1import os
2import sys
3import types
4from collections.abc import MutableSequence
5from functools import total_ordering
6from typing import Tuple, Type
7
8__version__ = "1.2.0"
9
10__all__ = (
11    "FrozenList", "PyFrozenList"
12)  # type: Tuple[str, ...]
13
14
15NO_EXTENSIONS = bool(os.environ.get("FROZENLIST_NO_EXTENSIONS"))  # type: bool
16
17
18@total_ordering
19class FrozenList(MutableSequence):
20
21    __slots__ = ("_frozen", "_items")
22
23    if sys.version_info >= (3, 9):
24        __class_getitem__ = classmethod(types.GenericAlias)
25    else:
26        @classmethod
27        def __class_getitem__(cls: Type["FrozenList"]) -> Type["FrozenList"]:
28            return cls
29
30    def __init__(self, items=None):
31        self._frozen = False
32        if items is not None:
33            items = list(items)
34        else:
35            items = []
36        self._items = items
37
38    @property
39    def frozen(self):
40        return self._frozen
41
42    def freeze(self):
43        self._frozen = True
44
45    def __getitem__(self, index):
46        return self._items[index]
47
48    def __setitem__(self, index, value):
49        if self._frozen:
50            raise RuntimeError("Cannot modify frozen list.")
51        self._items[index] = value
52
53    def __delitem__(self, index):
54        if self._frozen:
55            raise RuntimeError("Cannot modify frozen list.")
56        del self._items[index]
57
58    def __len__(self):
59        return self._items.__len__()
60
61    def __iter__(self):
62        return self._items.__iter__()
63
64    def __reversed__(self):
65        return self._items.__reversed__()
66
67    def __eq__(self, other):
68        return list(self) == other
69
70    def __le__(self, other):
71        return list(self) <= other
72
73    def insert(self, pos, item):
74        if self._frozen:
75            raise RuntimeError("Cannot modify frozen list.")
76        self._items.insert(pos, item)
77
78    def __repr__(self):
79        return "<FrozenList(frozen={}, {!r})>".format(self._frozen,
80                                                      self._items)
81
82    def __hash__(self):
83        if self._frozen:
84            return hash(tuple(self))
85        else:
86            raise RuntimeError("Cannot hash unfrozen list.")
87
88
89PyFrozenList = FrozenList
90
91
92try:
93    from ._frozenlist import FrozenList as CFrozenList  # type: ignore
94    if not NO_EXTENSIONS:  # pragma: no cover
95        FrozenList = CFrozenList  # type: ignore
96except ImportError:  # pragma: no cover
97    pass
98