Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/pandas/core/internals/base.py: 45%

86 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2Base class for the internal managers. Both BlockManager and ArrayManager 

3inherit from this class. 

4""" 

5from __future__ import annotations 

6 

7from typing import ( 

8 Literal, 

9 TypeVar, 

10 final, 

11) 

12 

13import numpy as np 

14 

15from pandas._typing import ( 

16 ArrayLike, 

17 DtypeObj, 

18 Shape, 

19) 

20from pandas.errors import AbstractMethodError 

21 

22from pandas.core.dtypes.cast import ( 

23 find_common_type, 

24 np_can_hold_element, 

25) 

26 

27from pandas.core.base import PandasObject 

28from pandas.core.indexes.api import ( 

29 Index, 

30 default_index, 

31) 

32 

33T = TypeVar("T", bound="DataManager") 

34 

35 

36class DataManager(PandasObject): 

37 

38 # TODO share more methods/attributes 

39 

40 axes: list[Index] 

41 

42 @property 

43 def items(self) -> Index: 

44 raise AbstractMethodError(self) 

45 

46 @final 

47 def __len__(self) -> int: 

48 return len(self.items) 

49 

50 @property 

51 def ndim(self) -> int: 

52 return len(self.axes) 

53 

54 @property 

55 def shape(self) -> Shape: 

56 return tuple(len(ax) for ax in self.axes) 

57 

58 @final 

59 def _validate_set_axis(self, axis: int, new_labels: Index) -> None: 

60 # Caller is responsible for ensuring we have an Index object. 

61 old_len = len(self.axes[axis]) 

62 new_len = len(new_labels) 

63 

64 if axis == 1 and len(self.items) == 0: 

65 # If we are setting the index on a DataFrame with no columns, 

66 # it is OK to change the length. 

67 pass 

68 

69 elif new_len != old_len: 

70 raise ValueError( 

71 f"Length mismatch: Expected axis has {old_len} elements, new " 

72 f"values have {new_len} elements" 

73 ) 

74 

75 def reindex_indexer( 

76 self: T, 

77 new_axis, 

78 indexer, 

79 axis: int, 

80 fill_value=None, 

81 allow_dups: bool = False, 

82 copy: bool = True, 

83 only_slice: bool = False, 

84 ) -> T: 

85 raise AbstractMethodError(self) 

86 

87 @final 

88 def reindex_axis( 

89 self: T, 

90 new_index: Index, 

91 axis: int, 

92 fill_value=None, 

93 only_slice: bool = False, 

94 ) -> T: 

95 """ 

96 Conform data manager to new index. 

97 """ 

98 new_index, indexer = self.axes[axis].reindex(new_index) 

99 

100 return self.reindex_indexer( 

101 new_index, 

102 indexer, 

103 axis=axis, 

104 fill_value=fill_value, 

105 copy=False, 

106 only_slice=only_slice, 

107 ) 

108 

109 def _equal_values(self: T, other: T) -> bool: 

110 """ 

111 To be implemented by the subclasses. Only check the column values 

112 assuming shape and indexes have already been checked. 

113 """ 

114 raise AbstractMethodError(self) 

115 

116 @final 

117 def equals(self, other: object) -> bool: 

118 """ 

119 Implementation for DataFrame.equals 

120 """ 

121 if not isinstance(other, DataManager): 

122 return False 

123 

124 self_axes, other_axes = self.axes, other.axes 

125 if len(self_axes) != len(other_axes): 

126 return False 

127 if not all(ax1.equals(ax2) for ax1, ax2 in zip(self_axes, other_axes)): 

128 return False 

129 

130 return self._equal_values(other) 

131 

132 def apply( 

133 self: T, 

134 f, 

135 align_keys: list[str] | None = None, 

136 ignore_failures: bool = False, 

137 **kwargs, 

138 ) -> T: 

139 raise AbstractMethodError(self) 

140 

141 @final 

142 def isna(self: T, func) -> T: 

143 return self.apply("apply", func=func) 

144 

145 # -------------------------------------------------------------------- 

146 # Consolidation: No-ops for all but BlockManager 

147 

148 def is_consolidated(self) -> bool: 

149 return True 

150 

151 def consolidate(self: T) -> T: 

152 return self 

153 

154 def _consolidate_inplace(self) -> None: 

155 return 

156 

157 

158class SingleDataManager(DataManager): 

159 @property 

160 def ndim(self) -> Literal[1]: 

161 return 1 

162 

163 @final 

164 @property 

165 def array(self) -> ArrayLike: 

166 """ 

167 Quick access to the backing array of the Block or SingleArrayManager. 

168 """ 

169 # error: "SingleDataManager" has no attribute "arrays"; maybe "array" 

170 return self.arrays[0] # type: ignore[attr-defined] 

171 

172 def setitem_inplace(self, indexer, value) -> None: 

173 """ 

174 Set values with indexer. 

175 

176 For Single[Block/Array]Manager, this backs s[indexer] = value 

177 

178 This is an inplace version of `setitem()`, mutating the manager/values 

179 in place, not returning a new Manager (and Block), and thus never changing 

180 the dtype. 

181 """ 

182 arr = self.array 

183 

184 # EAs will do this validation in their own __setitem__ methods. 

185 if isinstance(arr, np.ndarray): 

186 # Note: checking for ndarray instead of np.dtype means we exclude 

187 # dt64/td64, which do their own validation. 

188 value = np_can_hold_element(arr.dtype, value) 

189 

190 arr[indexer] = value 

191 

192 def grouped_reduce(self, func, ignore_failures: bool = False): 

193 """ 

194 ignore_failures : bool, default False 

195 Not used; for compatibility with ArrayManager/BlockManager. 

196 """ 

197 

198 arr = self.array 

199 res = func(arr) 

200 index = default_index(len(res)) 

201 

202 mgr = type(self).from_array(res, index) 

203 return mgr 

204 

205 @classmethod 

206 def from_array(cls, arr: ArrayLike, index: Index): 

207 raise AbstractMethodError(cls) 

208 

209 

210def interleaved_dtype(dtypes: list[DtypeObj]) -> DtypeObj | None: 

211 """ 

212 Find the common dtype for `blocks`. 

213 

214 Parameters 

215 ---------- 

216 blocks : List[DtypeObj] 

217 

218 Returns 

219 ------- 

220 dtype : np.dtype, ExtensionDtype, or None 

221 None is returned when `blocks` is empty. 

222 """ 

223 if not len(dtypes): 

224 return None 

225 

226 return find_common_type(dtypes)