Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/core/internals/api.py: 34%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

59 statements  

1""" 

2This is a pseudo-public API for downstream libraries. We ask that downstream 

3authors 

4 

51) Try to avoid using internals directly altogether, and failing that, 

62) Use only functions exposed here (or in core.internals) 

7 

8""" 

9 

10from __future__ import annotations 

11 

12from typing import TYPE_CHECKING 

13import warnings 

14 

15import numpy as np 

16 

17from pandas._libs.internals import BlockPlacement 

18from pandas.errors import Pandas4Warning 

19 

20from pandas.core.dtypes.common import pandas_dtype 

21from pandas.core.dtypes.dtypes import ( 

22 DatetimeTZDtype, 

23 ExtensionDtype, 

24 PeriodDtype, 

25) 

26 

27from pandas.core.arrays import ( 

28 DatetimeArray, 

29 TimedeltaArray, 

30) 

31from pandas.core.construction import extract_array 

32from pandas.core.internals.blocks import ( 

33 DatetimeLikeBlock, 

34 check_ndim, 

35 ensure_block_shape, 

36 extract_pandas_array, 

37 get_block_type, 

38 maybe_coerce_values, 

39) 

40 

41if TYPE_CHECKING: 

42 from pandas._typing import ( 

43 ArrayLike, 

44 Dtype, 

45 ) 

46 

47 from pandas.core.internals.blocks import Block 

48 

49 

50def _make_block(values: ArrayLike, placement: np.ndarray) -> Block: 

51 """ 

52 This is an analogue to blocks.new_block(_2d) that ensures: 

53 1) correct dimension for EAs that support 2D (`ensure_block_shape`), and 

54 2) correct EA class for datetime64/timedelta64 (`maybe_coerce_values`). 

55 

56 The input `values` is assumed to be either numpy array or ExtensionArray: 

57 - In case of a numpy array, it is assumed to already be in the expected 

58 shape for Blocks (2D, (cols, rows)). 

59 - In case of an ExtensionArray the input can be 1D, also for EAs that are 

60 internally stored as 2D. 

61 

62 For the rest no preprocessing or validation is done, except for those dtypes 

63 that are internally stored as EAs but have an exact numpy equivalent (and at 

64 the moment use that numpy dtype), i.e. datetime64/timedelta64. 

65 """ 

66 dtype = values.dtype 

67 klass = get_block_type(dtype) 

68 placement_obj = BlockPlacement(placement) 

69 

70 if (isinstance(dtype, ExtensionDtype) and dtype._supports_2d) or isinstance( 

71 values, (DatetimeArray, TimedeltaArray) 

72 ): 

73 values = ensure_block_shape(values, ndim=2) 

74 

75 values = maybe_coerce_values(values) 

76 return klass(values, ndim=2, placement=placement_obj) 

77 

78 

79class _DatetimeTZBlock(DatetimeLikeBlock): 

80 """implement a datetime64 block with a tz attribute""" 

81 

82 values: DatetimeArray 

83 

84 __slots__ = () 

85 

86 

87def make_block( 

88 values: ArrayLike, 

89 placement: BlockPlacement | np.ndarray, 

90 klass: type[Block] | None = None, 

91 ndim: int | None = None, 

92 dtype: Dtype | None = None, 

93) -> Block: 

94 """ 

95 This is a pseudo-public analogue to blocks.new_block. 

96 

97 We ask that downstream libraries use this rather than any fully-internal 

98 APIs, including but not limited to: 

99 

100 - core.internals.blocks.make_block 

101 - Block.make_block 

102 - Block.make_block_same_class 

103 - Block.__init__ 

104 """ 

105 warnings.warn( 

106 # GH#56815 

107 "make_block is deprecated and will be removed in a future version. " 

108 "Use pd.api.internals.create_dataframe_from_blocks or " 

109 "(recommended) higher-level public APIs instead.", 

110 Pandas4Warning, 

111 stacklevel=2, 

112 ) 

113 

114 if dtype is not None: 

115 dtype = pandas_dtype(dtype) 

116 

117 values, dtype = extract_pandas_array(values, dtype, ndim) 

118 

119 from pandas.core.internals.blocks import ExtensionBlock 

120 

121 if klass is ExtensionBlock and isinstance(values.dtype, PeriodDtype): 

122 # GH-44681 changed PeriodArray to be stored in the 2D 

123 # NDArrayBackedExtensionBlock instead of ExtensionBlock 

124 # -> still allow ExtensionBlock to be passed in this case for back compat 

125 klass = None 

126 

127 if klass is None: 

128 dtype = dtype or values.dtype 

129 klass = get_block_type(dtype) 

130 

131 elif klass is _DatetimeTZBlock and not isinstance(values.dtype, DatetimeTZDtype): 

132 # pyarrow calls get here (pyarrow<15) 

133 values = DatetimeArray._simple_new( 

134 # error: Argument 1 to "_simple_new" of "DatetimeArray" has 

135 # incompatible type "ExtensionArray | ndarray[tuple[Any, ...], 

136 # dtype[Any]]"; expected 

137 # "ndarray[tuple[Any, ...], dtype[datetime64[date | int | None]]]" 

138 values, # type: ignore[arg-type] 

139 # error: Argument "dtype" to "_simple_new" of "DatetimeArray" has 

140 # incompatible type "Union[ExtensionDtype, dtype[Any], None]"; 

141 # expected "Union[dtype[datetime64], DatetimeTZDtype]" 

142 dtype=dtype, # type: ignore[arg-type] 

143 ) 

144 

145 if not isinstance(placement, BlockPlacement): 

146 placement = BlockPlacement(placement) 

147 

148 ndim = _maybe_infer_ndim(values, placement, ndim) 

149 if isinstance(values.dtype, (PeriodDtype, DatetimeTZDtype)): 

150 # GH#41168 ensure we can pass 1D dt64tz values 

151 # More generally, any EA dtype that isn't is_1d_only_ea_dtype 

152 values = extract_array(values, extract_numpy=True) 

153 values = ensure_block_shape(values, ndim) 

154 

155 check_ndim(values, placement, ndim) 

156 values = maybe_coerce_values(values) 

157 return klass(values, ndim=ndim, placement=placement) 

158 

159 

160def _maybe_infer_ndim( 

161 values: ArrayLike, placement: BlockPlacement, ndim: int | None 

162) -> int: 

163 """ 

164 If `ndim` is not provided, infer it from placement and values. 

165 """ 

166 if ndim is None: 

167 # GH#38134 Block constructor now assumes ndim is not None 

168 if not isinstance(values.dtype, np.dtype): 

169 if len(placement) != 1: 

170 ndim = 1 

171 else: 

172 ndim = 2 

173 else: 

174 ndim = values.ndim 

175 return ndim 

176 

177 

178def maybe_infer_ndim( 

179 values: ArrayLike, placement: BlockPlacement, ndim: int | None 

180) -> int: 

181 """ 

182 If `ndim` is not provided, infer it from placement and values. 

183 """ 

184 warnings.warn( 

185 "maybe_infer_ndim is deprecated and will be removed in a future version.", 

186 Pandas4Warning, 

187 stacklevel=2, 

188 ) 

189 return _maybe_infer_ndim(values, placement, ndim)