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