1"""
2frozen (immutable) data structures to support MultiIndexing
3
4These are used for:
5
6- .names (FrozenList)
7
8"""
9
10from __future__ import annotations
11
12from typing import (
13 TYPE_CHECKING,
14 Any,
15 NoReturn,
16 Self,
17)
18
19if TYPE_CHECKING:
20 from collections.abc import Iterable
21 from typing import SupportsIndex
22
23from pandas.util._decorators import set_module
24
25from pandas.core.base import PandasObject
26
27from pandas.io.formats.printing import pprint_thing
28
29
30@set_module("pandas.api.typing")
31class FrozenList(PandasObject, list):
32 """
33 Container that doesn't allow setting item *but*
34 because it's technically hashable, will be used
35 for lookups, appropriately, etc.
36 """
37
38 # Side note: This has to be of type list. Otherwise,
39 # it messes up PyTables type checks.
40
41 def union(self, other: list | tuple) -> FrozenList:
42 """
43 Returns a FrozenList with other concatenated to the end of self.
44
45 Parameters
46 ----------
47 other : list or tuple
48 The list or tuple whose elements we are concatenating.
49
50 Returns
51 -------
52 FrozenList
53 The concatenation of self and other.
54 """
55 if isinstance(other, tuple):
56 other = list(other)
57 return type(self)(super().__add__(other))
58
59 def difference(self, other: Iterable) -> FrozenList:
60 """
61 Returns a FrozenList with elements from other removed from self.
62
63 Parameters
64 ----------
65 other : array-like
66 The array-like whose elements we are removing self.
67
68 Returns
69 -------
70 FrozenList
71 The collection difference between self and other.
72 """
73 other = set(other)
74 temp = [x for x in self if x not in other]
75 return type(self)(temp)
76
77 # TODO: Consider deprecating these in favor of `union` (xref gh-15506)
78
79 __add__ = __iadd__ = union # type: ignore[assignment] # pyright: ignore[reportAssignmentType]
80
81 def __getitem__(self, n: int | slice) -> Any: # type: ignore[override]
82 if isinstance(n, slice):
83 return type(self)(super().__getitem__(n))
84 return super().__getitem__(n)
85
86 def __radd__(self, other: list | tuple) -> Self:
87 if isinstance(other, tuple):
88 other = list(other)
89 return type(self)(other + list(self))
90
91 def __eq__(self, other: object) -> bool:
92 if isinstance(other, (tuple, FrozenList)):
93 other = list(other)
94 return super().__eq__(other)
95
96 __req__ = __eq__
97
98 def __mul__(self, other: SupportsIndex) -> Self:
99 return type(self)(super().__mul__(other))
100
101 __imul__ = __mul__
102
103 def __reduce__(self) -> tuple[type[FrozenList], tuple[list[Any]]]:
104 return type(self), (list(self),)
105
106 # error: Signature of "__hash__" incompatible with supertype "list"
107 def __hash__(self) -> int: # type: ignore[override]
108 return hash(tuple(self))
109
110 def _disabled(self, *args: Any, **kwargs: Any) -> NoReturn:
111 """
112 This method will not function because object is immutable.
113 """
114 raise TypeError(f"'{type(self).__name__}' does not support mutable operations.")
115
116 def __str__(self) -> str:
117 return pprint_thing(
118 self, quote_strings=True, escape_chars=("\t", "\r", "\n", "'")
119 )
120
121 def __repr__(self) -> str:
122 return f"{type(self).__name__}({self!s})"
123
124 __setitem__ = __setslice__ = _disabled
125 __delitem__ = __delslice__ = _disabled
126 pop = append = extend = _disabled
127 remove = sort = insert = _disabled # pyright: ignore[reportAssignmentType]