maxframe 2.0.0b2__cp37-cp37m-win32.whl → 2.3.0rc1__cp37-cp37m-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of maxframe might be problematic. Click here for more details.

Files changed (443) hide show
  1. maxframe/__init__.py +1 -0
  2. maxframe/_utils.cp37-win32.pyd +0 -0
  3. maxframe/_utils.pyx +14 -1
  4. maxframe/codegen/core.py +9 -8
  5. maxframe/codegen/spe/core.py +1 -1
  6. maxframe/codegen/spe/dataframe/__init__.py +1 -0
  7. maxframe/codegen/spe/dataframe/accessors/base.py +18 -0
  8. maxframe/codegen/spe/dataframe/accessors/dict_.py +25 -130
  9. maxframe/codegen/spe/dataframe/accessors/list_.py +12 -48
  10. maxframe/codegen/spe/dataframe/accessors/struct_.py +28 -0
  11. maxframe/codegen/spe/dataframe/arithmetic.py +7 -2
  12. maxframe/codegen/spe/dataframe/groupby.py +88 -0
  13. maxframe/codegen/spe/dataframe/indexing.py +99 -4
  14. maxframe/codegen/spe/dataframe/merge.py +38 -1
  15. maxframe/codegen/spe/dataframe/misc.py +11 -33
  16. maxframe/codegen/spe/dataframe/reduction.py +32 -9
  17. maxframe/codegen/spe/dataframe/reshape.py +46 -0
  18. maxframe/codegen/spe/dataframe/sort.py +39 -18
  19. maxframe/codegen/spe/dataframe/tests/accessors/test_dict.py +9 -15
  20. maxframe/codegen/spe/dataframe/tests/accessors/test_list.py +4 -7
  21. maxframe/codegen/spe/dataframe/tests/accessors/test_struct.py +75 -0
  22. maxframe/codegen/spe/dataframe/tests/indexing/test_iloc.py +20 -1
  23. maxframe/codegen/spe/dataframe/tests/indexing/test_loc.py +35 -0
  24. maxframe/codegen/spe/dataframe/tests/misc/test_misc.py +0 -32
  25. maxframe/codegen/spe/dataframe/tests/test_groupby.py +81 -18
  26. maxframe/codegen/spe/dataframe/tests/test_merge.py +27 -1
  27. maxframe/codegen/spe/dataframe/tests/test_reduction.py +13 -0
  28. maxframe/codegen/spe/dataframe/tests/test_reshape.py +79 -0
  29. maxframe/codegen/spe/dataframe/tests/test_sort.py +20 -0
  30. maxframe/codegen/spe/dataframe/tseries.py +9 -0
  31. maxframe/codegen/spe/learn/contrib/lightgbm.py +4 -3
  32. maxframe/codegen/spe/learn/contrib/tests/test_xgboost.py +2 -1
  33. maxframe/codegen/spe/learn/metrics/__init__.py +1 -1
  34. maxframe/codegen/spe/learn/metrics/_ranking.py +76 -0
  35. maxframe/codegen/spe/learn/metrics/pairwise.py +51 -0
  36. maxframe/codegen/spe/learn/metrics/tests/test_pairwise.py +36 -0
  37. maxframe/codegen/spe/learn/metrics/tests/test_ranking.py +59 -0
  38. maxframe/codegen/spe/tensor/__init__.py +3 -0
  39. maxframe/codegen/spe/tensor/datasource.py +1 -0
  40. maxframe/codegen/spe/tensor/fft.py +74 -0
  41. maxframe/codegen/spe/tensor/linalg.py +29 -2
  42. maxframe/codegen/spe/tensor/misc.py +79 -25
  43. maxframe/codegen/spe/tensor/spatial.py +45 -0
  44. maxframe/codegen/spe/tensor/statistics.py +44 -0
  45. maxframe/codegen/spe/tensor/tests/test_fft.py +64 -0
  46. maxframe/codegen/spe/tensor/tests/test_linalg.py +15 -1
  47. maxframe/codegen/spe/tensor/tests/test_misc.py +52 -2
  48. maxframe/codegen/spe/tensor/tests/test_spatial.py +33 -0
  49. maxframe/codegen/spe/tensor/tests/test_statistics.py +15 -1
  50. maxframe/codegen/spe/tests/test_spe_codegen.py +6 -12
  51. maxframe/codegen/spe/utils.py +2 -0
  52. maxframe/config/config.py +73 -9
  53. maxframe/config/tests/test_validators.py +13 -1
  54. maxframe/config/validators.py +49 -0
  55. maxframe/conftest.py +54 -17
  56. maxframe/core/accessor.py +2 -2
  57. maxframe/core/base.py +2 -1
  58. maxframe/core/entity/core.py +5 -0
  59. maxframe/core/entity/tileables.py +3 -1
  60. maxframe/core/graph/core.cp37-win32.pyd +0 -0
  61. maxframe/core/graph/entity.py +8 -3
  62. maxframe/core/mode.py +6 -1
  63. maxframe/core/operator/base.py +9 -2
  64. maxframe/core/operator/core.py +10 -2
  65. maxframe/core/operator/utils.py +13 -0
  66. maxframe/dataframe/__init__.py +12 -5
  67. maxframe/dataframe/accessors/__init__.py +1 -1
  68. maxframe/dataframe/accessors/compat.py +45 -0
  69. maxframe/dataframe/accessors/datetime_/__init__.py +4 -1
  70. maxframe/dataframe/accessors/dict_/contains.py +7 -16
  71. maxframe/dataframe/accessors/dict_/core.py +48 -0
  72. maxframe/dataframe/accessors/dict_/getitem.py +17 -21
  73. maxframe/dataframe/accessors/dict_/length.py +7 -16
  74. maxframe/dataframe/accessors/dict_/remove.py +6 -18
  75. maxframe/dataframe/accessors/dict_/setitem.py +8 -18
  76. maxframe/dataframe/accessors/dict_/tests/test_dict_accessor.py +62 -22
  77. maxframe/dataframe/accessors/list_/__init__.py +2 -2
  78. maxframe/dataframe/accessors/list_/core.py +48 -0
  79. maxframe/dataframe/accessors/list_/getitem.py +12 -19
  80. maxframe/dataframe/accessors/list_/length.py +7 -16
  81. maxframe/dataframe/accessors/list_/tests/test_list_accessor.py +11 -9
  82. maxframe/dataframe/accessors/string_/__init__.py +4 -1
  83. maxframe/dataframe/accessors/struct_/__init__.py +37 -0
  84. maxframe/dataframe/accessors/struct_/accessor.py +39 -0
  85. maxframe/dataframe/accessors/struct_/core.py +43 -0
  86. maxframe/dataframe/accessors/struct_/dtypes.py +53 -0
  87. maxframe/dataframe/accessors/struct_/field.py +123 -0
  88. maxframe/dataframe/accessors/struct_/tests/__init__.py +13 -0
  89. maxframe/dataframe/accessors/struct_/tests/test_struct_accessor.py +91 -0
  90. maxframe/dataframe/arithmetic/__init__.py +18 -4
  91. maxframe/dataframe/arithmetic/between.py +106 -0
  92. maxframe/dataframe/arithmetic/dot.py +237 -0
  93. maxframe/dataframe/arithmetic/maximum.py +33 -0
  94. maxframe/dataframe/arithmetic/minimum.py +33 -0
  95. maxframe/dataframe/arithmetic/{around.py → round.py} +11 -7
  96. maxframe/dataframe/core.py +161 -224
  97. maxframe/dataframe/datasource/__init__.py +18 -0
  98. maxframe/dataframe/datasource/core.py +6 -0
  99. maxframe/dataframe/datasource/direct.py +57 -0
  100. maxframe/dataframe/datasource/from_dict.py +124 -0
  101. maxframe/dataframe/datasource/from_index.py +1 -1
  102. maxframe/dataframe/datasource/from_records.py +77 -0
  103. maxframe/dataframe/datasource/from_tensor.py +109 -41
  104. maxframe/dataframe/datasource/read_csv.py +21 -14
  105. maxframe/dataframe/datasource/read_odps_query.py +29 -6
  106. maxframe/dataframe/datasource/read_odps_table.py +32 -10
  107. maxframe/dataframe/datasource/read_parquet.py +38 -39
  108. maxframe/dataframe/datasource/tests/test_datasource.py +37 -0
  109. maxframe/dataframe/datastore/__init__.py +11 -1
  110. maxframe/dataframe/datastore/direct.py +268 -0
  111. maxframe/dataframe/datastore/to_csv.py +29 -41
  112. maxframe/dataframe/datastore/to_odps.py +36 -4
  113. maxframe/dataframe/extensions/__init__.py +20 -4
  114. maxframe/dataframe/extensions/apply_chunk.py +32 -6
  115. maxframe/dataframe/extensions/cartesian_chunk.py +153 -0
  116. maxframe/dataframe/extensions/collect_kv.py +126 -0
  117. maxframe/dataframe/extensions/extract_kv.py +177 -0
  118. maxframe/dataframe/extensions/flatjson.py +2 -1
  119. maxframe/dataframe/extensions/map_reduce.py +263 -0
  120. maxframe/dataframe/extensions/rebalance.py +62 -0
  121. maxframe/dataframe/extensions/tests/test_apply_chunk.py +9 -2
  122. maxframe/dataframe/extensions/tests/test_extensions.py +54 -0
  123. maxframe/dataframe/extensions/tests/test_map_reduce.py +135 -0
  124. maxframe/dataframe/groupby/__init__.py +17 -2
  125. maxframe/dataframe/groupby/aggregation.py +86 -49
  126. maxframe/dataframe/groupby/apply.py +1 -1
  127. maxframe/dataframe/groupby/apply_chunk.py +19 -5
  128. maxframe/dataframe/groupby/core.py +116 -16
  129. maxframe/dataframe/groupby/cum.py +4 -25
  130. maxframe/dataframe/groupby/expanding.py +264 -0
  131. maxframe/dataframe/groupby/fill.py +1 -1
  132. maxframe/dataframe/groupby/getitem.py +12 -5
  133. maxframe/dataframe/groupby/head.py +11 -1
  134. maxframe/dataframe/groupby/rank.py +136 -0
  135. maxframe/dataframe/groupby/rolling.py +206 -0
  136. maxframe/dataframe/groupby/shift.py +114 -0
  137. maxframe/dataframe/groupby/tests/test_groupby.py +0 -5
  138. maxframe/dataframe/indexing/__init__.py +22 -2
  139. maxframe/dataframe/indexing/droplevel.py +195 -0
  140. maxframe/dataframe/indexing/filter.py +169 -0
  141. maxframe/dataframe/indexing/get_level_values.py +76 -0
  142. maxframe/dataframe/indexing/iat.py +45 -0
  143. maxframe/dataframe/indexing/iloc.py +152 -12
  144. maxframe/dataframe/indexing/insert.py +46 -18
  145. maxframe/dataframe/indexing/loc.py +287 -7
  146. maxframe/dataframe/indexing/reindex.py +14 -5
  147. maxframe/dataframe/indexing/rename.py +6 -0
  148. maxframe/dataframe/indexing/rename_axis.py +2 -2
  149. maxframe/dataframe/indexing/reorder_levels.py +143 -0
  150. maxframe/dataframe/indexing/reset_index.py +33 -6
  151. maxframe/dataframe/indexing/sample.py +8 -0
  152. maxframe/dataframe/indexing/setitem.py +3 -3
  153. maxframe/dataframe/indexing/swaplevel.py +185 -0
  154. maxframe/dataframe/indexing/take.py +99 -0
  155. maxframe/dataframe/indexing/truncate.py +140 -0
  156. maxframe/dataframe/indexing/where.py +0 -11
  157. maxframe/dataframe/indexing/xs.py +148 -0
  158. maxframe/dataframe/merge/__init__.py +15 -1
  159. maxframe/dataframe/merge/append.py +97 -98
  160. maxframe/dataframe/merge/combine.py +244 -0
  161. maxframe/dataframe/merge/combine_first.py +120 -0
  162. maxframe/dataframe/merge/compare.py +387 -0
  163. maxframe/dataframe/merge/concat.py +183 -0
  164. maxframe/dataframe/merge/update.py +271 -0
  165. maxframe/dataframe/misc/__init__.py +28 -11
  166. maxframe/dataframe/misc/_duplicate.py +10 -4
  167. maxframe/dataframe/misc/apply.py +1 -1
  168. maxframe/dataframe/misc/check_unique.py +82 -0
  169. maxframe/dataframe/misc/clip.py +145 -0
  170. maxframe/dataframe/misc/describe.py +175 -9
  171. maxframe/dataframe/misc/drop.py +31 -0
  172. maxframe/dataframe/misc/drop_duplicates.py +2 -2
  173. maxframe/dataframe/misc/duplicated.py +2 -2
  174. maxframe/dataframe/misc/get_dummies.py +5 -1
  175. maxframe/dataframe/misc/infer_dtypes.py +251 -0
  176. maxframe/dataframe/misc/isin.py +2 -2
  177. maxframe/dataframe/misc/map.py +125 -18
  178. maxframe/dataframe/misc/repeat.py +159 -0
  179. maxframe/dataframe/misc/tests/test_misc.py +48 -3
  180. maxframe/dataframe/misc/to_numeric.py +3 -0
  181. maxframe/dataframe/misc/transform.py +12 -5
  182. maxframe/dataframe/misc/transpose.py +13 -1
  183. maxframe/dataframe/misc/valid_index.py +115 -0
  184. maxframe/dataframe/misc/value_counts.py +38 -4
  185. maxframe/dataframe/missing/checkna.py +14 -6
  186. maxframe/dataframe/missing/dropna.py +5 -0
  187. maxframe/dataframe/missing/fillna.py +1 -1
  188. maxframe/dataframe/missing/replace.py +7 -4
  189. maxframe/dataframe/reduction/__init__.py +35 -16
  190. maxframe/dataframe/reduction/aggregation.py +43 -14
  191. maxframe/dataframe/reduction/all.py +2 -2
  192. maxframe/dataframe/reduction/any.py +2 -2
  193. maxframe/dataframe/reduction/argmax.py +103 -0
  194. maxframe/dataframe/reduction/argmin.py +103 -0
  195. maxframe/dataframe/reduction/core.py +80 -24
  196. maxframe/dataframe/reduction/count.py +13 -9
  197. maxframe/dataframe/reduction/cov.py +166 -0
  198. maxframe/dataframe/reduction/cummax.py +2 -2
  199. maxframe/dataframe/reduction/cummin.py +2 -2
  200. maxframe/dataframe/reduction/cumprod.py +2 -2
  201. maxframe/dataframe/reduction/cumsum.py +2 -2
  202. maxframe/dataframe/reduction/custom_reduction.py +2 -2
  203. maxframe/dataframe/reduction/idxmax.py +185 -0
  204. maxframe/dataframe/reduction/idxmin.py +185 -0
  205. maxframe/dataframe/reduction/kurtosis.py +37 -30
  206. maxframe/dataframe/reduction/max.py +2 -2
  207. maxframe/dataframe/reduction/mean.py +9 -7
  208. maxframe/dataframe/reduction/median.py +2 -2
  209. maxframe/dataframe/reduction/min.py +2 -2
  210. maxframe/dataframe/reduction/mode.py +144 -0
  211. maxframe/dataframe/reduction/nunique.py +19 -11
  212. maxframe/dataframe/reduction/prod.py +18 -13
  213. maxframe/dataframe/reduction/reduction_size.py +2 -2
  214. maxframe/dataframe/reduction/sem.py +13 -9
  215. maxframe/dataframe/reduction/skew.py +31 -27
  216. maxframe/dataframe/reduction/str_concat.py +10 -7
  217. maxframe/dataframe/reduction/sum.py +18 -14
  218. maxframe/dataframe/reduction/tests/test_reduction.py +12 -0
  219. maxframe/dataframe/reduction/unique.py +20 -3
  220. maxframe/dataframe/reduction/var.py +16 -12
  221. maxframe/dataframe/reshape/__init__.py +38 -0
  222. maxframe/dataframe/{misc → reshape}/pivot.py +1 -0
  223. maxframe/dataframe/{misc → reshape}/pivot_table.py +1 -0
  224. maxframe/dataframe/reshape/unstack.py +114 -0
  225. maxframe/dataframe/sort/__init__.py +16 -1
  226. maxframe/dataframe/sort/argsort.py +68 -0
  227. maxframe/dataframe/sort/core.py +2 -1
  228. maxframe/dataframe/sort/nlargest.py +238 -0
  229. maxframe/dataframe/sort/nsmallest.py +228 -0
  230. maxframe/dataframe/sort/rank.py +147 -0
  231. maxframe/dataframe/statistics/__init__.py +3 -3
  232. maxframe/dataframe/statistics/corr.py +1 -0
  233. maxframe/dataframe/statistics/quantile.py +2 -2
  234. maxframe/dataframe/tests/test_typing.py +104 -0
  235. maxframe/dataframe/tests/test_utils.py +66 -2
  236. maxframe/dataframe/tseries/__init__.py +19 -0
  237. maxframe/dataframe/tseries/at_time.py +61 -0
  238. maxframe/dataframe/tseries/between_time.py +122 -0
  239. maxframe/dataframe/typing_.py +185 -0
  240. maxframe/dataframe/utils.py +125 -52
  241. maxframe/dataframe/window/aggregation.py +8 -4
  242. maxframe/dataframe/window/core.py +14 -1
  243. maxframe/dataframe/window/ewm.py +1 -3
  244. maxframe/dataframe/window/expanding.py +37 -35
  245. maxframe/dataframe/window/rolling.py +49 -39
  246. maxframe/dataframe/window/tests/test_expanding.py +1 -7
  247. maxframe/dataframe/window/tests/test_rolling.py +1 -1
  248. maxframe/env.py +7 -4
  249. maxframe/errors.py +2 -2
  250. maxframe/io/odpsio/schema.py +9 -3
  251. maxframe/io/odpsio/tableio.py +7 -2
  252. maxframe/io/odpsio/tests/test_schema.py +198 -83
  253. maxframe/learn/__init__.py +10 -2
  254. maxframe/learn/cluster/__init__.py +15 -0
  255. maxframe/learn/cluster/_kmeans.py +782 -0
  256. maxframe/learn/contrib/llm/core.py +18 -7
  257. maxframe/learn/contrib/llm/deploy/__init__.py +13 -0
  258. maxframe/learn/contrib/llm/deploy/config.py +221 -0
  259. maxframe/learn/contrib/llm/deploy/core.py +247 -0
  260. maxframe/learn/contrib/llm/deploy/framework.py +35 -0
  261. maxframe/learn/contrib/llm/deploy/loader.py +360 -0
  262. maxframe/learn/contrib/llm/deploy/tests/__init__.py +13 -0
  263. maxframe/learn/contrib/llm/deploy/tests/test_register_models.py +359 -0
  264. maxframe/learn/contrib/llm/models/__init__.py +1 -0
  265. maxframe/learn/contrib/llm/models/dashscope.py +12 -6
  266. maxframe/learn/contrib/llm/models/managed.py +76 -11
  267. maxframe/learn/contrib/llm/models/openai.py +72 -0
  268. maxframe/learn/contrib/llm/tests/__init__.py +13 -0
  269. maxframe/learn/contrib/llm/tests/test_core.py +34 -0
  270. maxframe/learn/contrib/llm/tests/test_openai.py +187 -0
  271. maxframe/learn/contrib/llm/tests/test_text_gen.py +155 -0
  272. maxframe/learn/contrib/llm/text.py +348 -42
  273. maxframe/learn/contrib/models.py +4 -1
  274. maxframe/learn/contrib/xgboost/classifier.py +2 -0
  275. maxframe/learn/contrib/xgboost/core.py +113 -4
  276. maxframe/learn/contrib/xgboost/predict.py +4 -2
  277. maxframe/learn/contrib/xgboost/regressor.py +5 -0
  278. maxframe/learn/contrib/xgboost/train.py +7 -2
  279. maxframe/learn/core.py +66 -0
  280. maxframe/learn/linear_model/_base.py +58 -1
  281. maxframe/learn/linear_model/_lin_reg.py +1 -1
  282. maxframe/learn/metrics/__init__.py +6 -0
  283. maxframe/learn/metrics/_classification.py +145 -0
  284. maxframe/learn/metrics/_ranking.py +477 -0
  285. maxframe/learn/metrics/_scorer.py +60 -0
  286. maxframe/learn/metrics/pairwise/__init__.py +21 -0
  287. maxframe/learn/metrics/pairwise/core.py +77 -0
  288. maxframe/learn/metrics/pairwise/cosine.py +115 -0
  289. maxframe/learn/metrics/pairwise/euclidean.py +176 -0
  290. maxframe/learn/metrics/pairwise/haversine.py +96 -0
  291. maxframe/learn/metrics/pairwise/manhattan.py +80 -0
  292. maxframe/learn/metrics/pairwise/pairwise.py +127 -0
  293. maxframe/learn/metrics/pairwise/pairwise_distances_topk.py +121 -0
  294. maxframe/learn/metrics/pairwise/rbf_kernel.py +51 -0
  295. maxframe/learn/metrics/tests/__init__.py +13 -0
  296. maxframe/learn/metrics/tests/test_scorer.py +26 -0
  297. maxframe/learn/preprocessing/_data/min_max_scaler.py +34 -23
  298. maxframe/learn/preprocessing/_data/standard_scaler.py +34 -25
  299. maxframe/learn/utils/__init__.py +2 -1
  300. maxframe/learn/utils/checks.py +1 -2
  301. maxframe/learn/utils/core.py +59 -0
  302. maxframe/learn/utils/extmath.py +79 -9
  303. maxframe/learn/utils/odpsio.py +262 -0
  304. maxframe/learn/utils/validation.py +2 -2
  305. maxframe/lib/compat.py +40 -0
  306. maxframe/lib/dtypes_extension/__init__.py +16 -1
  307. maxframe/lib/dtypes_extension/_fake_arrow_dtype.py +604 -0
  308. maxframe/lib/dtypes_extension/blob.py +304 -0
  309. maxframe/lib/dtypes_extension/dtypes.py +40 -0
  310. maxframe/lib/dtypes_extension/tests/test_blob.py +88 -0
  311. maxframe/lib/dtypes_extension/tests/test_dtypes.py +16 -1
  312. maxframe/lib/dtypes_extension/tests/test_fake_arrow_dtype.py +75 -0
  313. maxframe/lib/filesystem/_oss_lib/common.py +124 -50
  314. maxframe/lib/filesystem/_oss_lib/glob.py +1 -1
  315. maxframe/lib/filesystem/_oss_lib/handle.py +21 -25
  316. maxframe/lib/filesystem/base.py +1 -1
  317. maxframe/lib/filesystem/core.py +1 -1
  318. maxframe/lib/filesystem/oss.py +115 -46
  319. maxframe/lib/filesystem/tests/test_oss.py +74 -36
  320. maxframe/lib/mmh3.cp37-win32.pyd +0 -0
  321. maxframe/lib/wrapped_pickle.py +10 -0
  322. maxframe/opcodes.py +41 -15
  323. maxframe/protocol.py +12 -0
  324. maxframe/remote/core.py +4 -0
  325. maxframe/serialization/__init__.py +11 -2
  326. maxframe/serialization/arrow.py +38 -13
  327. maxframe/serialization/blob.py +32 -0
  328. maxframe/serialization/core.cp37-win32.pyd +0 -0
  329. maxframe/serialization/core.pyx +39 -1
  330. maxframe/serialization/exception.py +2 -4
  331. maxframe/serialization/numpy.py +11 -0
  332. maxframe/serialization/pandas.py +46 -9
  333. maxframe/serialization/serializables/core.py +2 -2
  334. maxframe/serialization/tests/test_serial.py +31 -4
  335. maxframe/tensor/__init__.py +38 -8
  336. maxframe/tensor/arithmetic/__init__.py +19 -10
  337. maxframe/tensor/arithmetic/core.py +2 -2
  338. maxframe/tensor/arithmetic/iscomplexobj.py +53 -0
  339. maxframe/tensor/arithmetic/tests/test_arithmetic.py +6 -9
  340. maxframe/tensor/core.py +6 -2
  341. maxframe/tensor/datasource/tests/test_datasource.py +2 -1
  342. maxframe/tensor/extensions/__init__.py +2 -0
  343. maxframe/tensor/extensions/apply_chunk.py +3 -3
  344. maxframe/tensor/extensions/rebalance.py +65 -0
  345. maxframe/tensor/fft/__init__.py +32 -0
  346. maxframe/tensor/fft/core.py +168 -0
  347. maxframe/tensor/fft/fft.py +112 -0
  348. maxframe/tensor/fft/fft2.py +118 -0
  349. maxframe/tensor/fft/fftfreq.py +80 -0
  350. maxframe/tensor/fft/fftn.py +123 -0
  351. maxframe/tensor/fft/fftshift.py +79 -0
  352. maxframe/tensor/fft/hfft.py +112 -0
  353. maxframe/tensor/fft/ifft.py +114 -0
  354. maxframe/tensor/fft/ifft2.py +115 -0
  355. maxframe/tensor/fft/ifftn.py +123 -0
  356. maxframe/tensor/fft/ifftshift.py +73 -0
  357. maxframe/tensor/fft/ihfft.py +93 -0
  358. maxframe/tensor/fft/irfft.py +118 -0
  359. maxframe/tensor/fft/irfft2.py +62 -0
  360. maxframe/tensor/fft/irfftn.py +114 -0
  361. maxframe/tensor/fft/rfft.py +116 -0
  362. maxframe/tensor/fft/rfft2.py +63 -0
  363. maxframe/tensor/fft/rfftfreq.py +87 -0
  364. maxframe/tensor/fft/rfftn.py +113 -0
  365. maxframe/tensor/indexing/fill_diagonal.py +1 -7
  366. maxframe/tensor/linalg/__init__.py +7 -0
  367. maxframe/tensor/linalg/_einsumfunc.py +1025 -0
  368. maxframe/tensor/linalg/cholesky.py +117 -0
  369. maxframe/tensor/linalg/einsum.py +339 -0
  370. maxframe/tensor/linalg/lstsq.py +100 -0
  371. maxframe/tensor/linalg/matrix_norm.py +75 -0
  372. maxframe/tensor/linalg/norm.py +249 -0
  373. maxframe/tensor/linalg/solve.py +72 -0
  374. maxframe/tensor/linalg/solve_triangular.py +2 -2
  375. maxframe/tensor/linalg/vector_norm.py +113 -0
  376. maxframe/tensor/misc/__init__.py +24 -1
  377. maxframe/tensor/misc/argwhere.py +72 -0
  378. maxframe/tensor/misc/array_split.py +46 -0
  379. maxframe/tensor/misc/broadcast_arrays.py +57 -0
  380. maxframe/tensor/misc/copyto.py +130 -0
  381. maxframe/tensor/misc/delete.py +104 -0
  382. maxframe/tensor/misc/dsplit.py +68 -0
  383. maxframe/tensor/misc/ediff1d.py +74 -0
  384. maxframe/tensor/misc/expand_dims.py +85 -0
  385. maxframe/tensor/misc/flip.py +90 -0
  386. maxframe/tensor/misc/fliplr.py +64 -0
  387. maxframe/tensor/misc/flipud.py +68 -0
  388. maxframe/tensor/misc/hsplit.py +85 -0
  389. maxframe/tensor/misc/insert.py +139 -0
  390. maxframe/tensor/misc/moveaxis.py +83 -0
  391. maxframe/tensor/misc/result_type.py +88 -0
  392. maxframe/tensor/misc/roll.py +124 -0
  393. maxframe/tensor/misc/rollaxis.py +77 -0
  394. maxframe/tensor/misc/shape.py +89 -0
  395. maxframe/tensor/misc/split.py +190 -0
  396. maxframe/tensor/misc/tile.py +109 -0
  397. maxframe/tensor/misc/vsplit.py +74 -0
  398. maxframe/tensor/reduction/array_equal.py +2 -1
  399. maxframe/tensor/sort/__init__.py +2 -0
  400. maxframe/tensor/sort/argpartition.py +98 -0
  401. maxframe/tensor/sort/partition.py +228 -0
  402. maxframe/tensor/spatial/__init__.py +15 -0
  403. maxframe/tensor/spatial/distance/__init__.py +17 -0
  404. maxframe/tensor/spatial/distance/cdist.py +421 -0
  405. maxframe/tensor/spatial/distance/pdist.py +398 -0
  406. maxframe/tensor/spatial/distance/squareform.py +153 -0
  407. maxframe/tensor/special/__init__.py +159 -21
  408. maxframe/tensor/special/airy.py +55 -0
  409. maxframe/tensor/special/bessel.py +199 -0
  410. maxframe/tensor/special/core.py +65 -4
  411. maxframe/tensor/special/ellip_func_integrals.py +155 -0
  412. maxframe/tensor/special/ellip_harm.py +55 -0
  413. maxframe/tensor/special/err_fresnel.py +223 -0
  414. maxframe/tensor/special/gamma_funcs.py +303 -0
  415. maxframe/tensor/special/hypergeometric_funcs.py +69 -0
  416. maxframe/tensor/special/info_theory.py +189 -0
  417. maxframe/tensor/special/misc.py +21 -0
  418. maxframe/tensor/statistics/__init__.py +6 -0
  419. maxframe/tensor/statistics/corrcoef.py +77 -0
  420. maxframe/tensor/statistics/cov.py +222 -0
  421. maxframe/tensor/statistics/digitize.py +126 -0
  422. maxframe/tensor/statistics/histogram.py +520 -0
  423. maxframe/tensor/statistics/median.py +85 -0
  424. maxframe/tensor/statistics/ptp.py +89 -0
  425. maxframe/tensor/utils.py +3 -3
  426. maxframe/tests/test_udf.py +61 -0
  427. maxframe/tests/test_utils.py +51 -6
  428. maxframe/tests/utils.py +0 -2
  429. maxframe/typing_.py +2 -0
  430. maxframe/udf.py +130 -9
  431. maxframe/utils.py +254 -27
  432. {maxframe-2.0.0b2.dist-info → maxframe-2.3.0rc1.dist-info}/METADATA +3 -3
  433. {maxframe-2.0.0b2.dist-info → maxframe-2.3.0rc1.dist-info}/RECORD +442 -264
  434. maxframe_client/fetcher.py +35 -4
  435. maxframe_client/session/odps.py +7 -2
  436. maxframe_client/session/task.py +8 -1
  437. maxframe_client/tests/test_fetcher.py +76 -3
  438. maxframe_client/tests/test_session.py +28 -1
  439. maxframe/dataframe/arrays.py +0 -864
  440. /maxframe/dataframe/{misc → reshape}/melt.py +0 -0
  441. /maxframe/dataframe/{misc → reshape}/stack.py +0 -0
  442. {maxframe-2.0.0b2.dist-info → maxframe-2.3.0rc1.dist-info}/WHEEL +0 -0
  443. {maxframe-2.0.0b2.dist-info → maxframe-2.3.0rc1.dist-info}/top_level.txt +0 -0
maxframe/tensor/utils.py CHANGED
@@ -167,7 +167,7 @@ def normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False):
167
167
  except TypeError:
168
168
  pass
169
169
  # Going via an iterator directly is slower than via list comprehension.
170
- axis = tuple([validate_axis(ndim, ax, argname) for ax in axis])
170
+ axis = tuple(validate_axis(ndim, ax, argname) for ax in axis)
171
171
  if not allow_duplicate and len(set(axis)) != len(axis):
172
172
  if argname:
173
173
  raise ValueError(f"repeated axis in `{argname}` argument")
@@ -709,8 +709,8 @@ def implement_scipy(scipy_fun_name):
709
709
  return wrapper
710
710
 
711
711
 
712
- def infer_scipy_dtype(scipy_fun_name):
712
+ def infer_scipy_dtype(scipy_fun_name, **kw):
713
713
  scipy_fun = _load_scipy_func(scipy_fun_name)
714
714
  if scipy_fun is None:
715
715
  return lambda x: x
716
- return infer_dtype(scipy_fun)
716
+ return infer_dtype(scipy_fun, **kw)
@@ -0,0 +1,61 @@
1
+ # Copyright 1999-2025 Alibaba Group Holding Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import textwrap
16
+
17
+ from odps import ODPS
18
+ from odps.errors import NoSuchObject
19
+
20
+ from maxframe.tests.utils import tn
21
+ from maxframe.udf import ODPSFunction
22
+
23
+
24
+ def test_odps_function():
25
+ func_body = """from odps.udf import annotate
26
+ @annotate("bigint->bigint")
27
+ class MyMul(object):
28
+ def evaluate(self, arg0):
29
+ return arg0 * 2 if arg0 is not None else None"""
30
+ odps_entry = ODPS.from_environments()
31
+ res_name = tn("test_res")
32
+ func_name = tn("test_odps_func")
33
+
34
+ def _cleanup():
35
+ try:
36
+ odps_entry.delete_resource(res_name + ".py")
37
+ except NoSuchObject:
38
+ pass
39
+ try:
40
+ odps_entry.delete_function(func_name)
41
+ except NoSuchObject:
42
+ pass
43
+
44
+ _cleanup()
45
+
46
+ try:
47
+ test_res = odps_entry.create_resource(
48
+ res_name + ".py", "py", fileobj=textwrap.dedent(func_body)
49
+ )
50
+ test_odps_func_obj = odps_entry.create_function(
51
+ func_name, class_type=f"{res_name}.MyMul", resources=[test_res]
52
+ )
53
+ func = ODPSFunction.wrap(test_odps_func_obj)
54
+ assert isinstance(func, ODPSFunction)
55
+ assert func.__name__ == func_name
56
+ assert func.full_function_name in (
57
+ f"{odps_entry.project}:{func_name}",
58
+ f"{odps_entry.project}:default:{func_name}",
59
+ )
60
+ finally:
61
+ _cleanup()
@@ -31,8 +31,9 @@ import pyarrow as pa
31
31
  import pytest
32
32
 
33
33
  from .. import utils
34
+ from ..lib.dtypes_extension import ArrowDtype
34
35
  from ..serialization import PickleContainer
35
- from ..utils import parse_size_to_megabytes
36
+ from ..utils import parse_size_to_megabytes, validate_and_adjust_resource_ratio
36
37
 
37
38
 
38
39
  def test_string_conversion():
@@ -298,11 +299,11 @@ def test_estimate_pandas_size():
298
299
  s1 = pd.Series(np.random.rand(1000))
299
300
  assert utils.estimate_pandas_size(s1) == sys.getsizeof(s1)
300
301
 
301
- from ..dataframe.arrays import ArrowStringArray
302
-
303
- array = ArrowStringArray(np.random.choice(["abcd", "def", "gh"], size=(1000,)))
304
- s2 = pd.Series(array)
305
- assert utils.estimate_pandas_size(s2) == sys.getsizeof(s2)
302
+ if hasattr(pd, "ArrowDtype"):
303
+ arrow_array = pa.array(np.random.choice(["abcd", "def", "gh"], size=(1000,)))
304
+ array = pd.array(arrow_array, dtype=ArrowDtype(arrow_array.type))
305
+ s2 = pd.Series(array)
306
+ assert utils.estimate_pandas_size(s2) == sys.getsizeof(s2)
306
307
 
307
308
  s3 = pd.Series(np.random.choice(["abcd", "def", "gh"], size=(1000,)))
308
309
  assert (
@@ -366,9 +367,17 @@ def test_arrow_type_from_string():
366
367
  _assert_arrow_type_convert(pa.decimal128(10, 2))
367
368
  _assert_arrow_type_convert(pa.list_(pa.int64()))
368
369
  _assert_arrow_type_convert(pa.map_(pa.string(), pa.int64()))
370
+ _assert_arrow_type_convert(pa.date32())
371
+ _assert_arrow_type_convert(pa.date64())
369
372
  _assert_arrow_type_convert(
370
373
  pa.struct([("key", pa.string()), ("value", pa.list_(pa.int64()))])
371
374
  )
375
+ _assert_arrow_type_convert(
376
+ pa.struct([("key", pa.string(), False), ("value", pa.list_(pa.int64()))])
377
+ )
378
+ _assert_arrow_type_convert(
379
+ pa.struct([("key", pa.string()), ("value", pa.list_(pa.int64()), False)])
380
+ )
372
381
 
373
382
 
374
383
  @pytest.mark.parametrize("use_async", [False, True])
@@ -527,6 +536,7 @@ def test_numeric_inputs_with_default_units(value, default_unit):
527
536
  "input_string, expected",
528
537
  [
529
538
  # Basic binary units
539
+ ("1B", 1 / BYTES_PER_MIB),
530
540
  ("1KiB", BYTES_PER_KIB / BYTES_PER_MIB),
531
541
  ("5miB", 5),
532
542
  ("2giB", 2 * BYTES_PER_GIB / BYTES_PER_MIB),
@@ -571,3 +581,38 @@ def test_parse_size_to_mega_bytes_invalid_inputs(invalid_input, default_unit):
571
581
  """Test invalid inputs that should raise ValueError"""
572
582
  with pytest.raises(ValueError): # Catch ValueError
573
583
  parse_size_to_megabytes(invalid_input, default_number_unit=default_unit)
584
+
585
+
586
+ @pytest.mark.parametrize(
587
+ "udf_resources, max_memory_cpu_ratio, adjust, expected_resources, expected_adjusted, should_warn",
588
+ [
589
+ ({"other": "value"}, 4, False, {"other": "value"}, False, False),
590
+ ({"memory": 8}, 4, False, {"memory": 8}, False, False),
591
+ ({"cpu": 2}, 4, False, {"cpu": 2}, False, False),
592
+ ({"cpu": 2, "memory": 2}, 4, True, {"cpu": 2, "memory": 2}, False, False),
593
+ ({"cpu": 2, "memory": 8}, 4, False, {"cpu": 2, "memory": 8}, False, False),
594
+ ({"cpu": 1, "memory": 8}, 4, False, {"cpu": 1, "memory": 8}, False, False),
595
+ ({"cpu": 2, "memory": 8}, 4, False, {"cpu": 2, "memory": 8}, False, False),
596
+ ({"cpu": 2, "memory": 8}, 4, False, {"cpu": 2, "memory": 8}, False, False),
597
+ ({"cpu": 1, "memory": 8}, 4, True, {"cpu": 2, "memory": 8}, True, True),
598
+ ({"cpu": 1, "memory": 18}, 7, True, {"cpu": 3, "memory": 18}, True, True),
599
+ ({"cpu": 1, "memory": 7.5}, 4, True, {"cpu": 2, "memory": 7.5}, True, True),
600
+ ],
601
+ )
602
+ def test_validate_and_adjust_resource_ratio(
603
+ udf_resources,
604
+ max_memory_cpu_ratio,
605
+ adjust,
606
+ expected_resources,
607
+ expected_adjusted,
608
+ should_warn,
609
+ recwarn,
610
+ ):
611
+ result_resources, was_adjusted = validate_and_adjust_resource_ratio(
612
+ udf_resources, max_memory_cpu_ratio, adjust
613
+ )
614
+ assert result_resources == expected_resources
615
+ assert was_adjusted == expected_adjusted
616
+ if should_warn:
617
+ # check warning
618
+ assert len(recwarn) == 1
maxframe/tests/utils.py CHANGED
@@ -16,7 +16,6 @@ import asyncio
16
16
  import contextlib
17
17
  import functools
18
18
  import hashlib
19
- import logging
20
19
  import os
21
20
  import queue
22
21
  import socket
@@ -233,7 +232,6 @@ def create_test_volume(vol_name, oss_config):
233
232
  yield vol_name
234
233
  finally:
235
234
  try:
236
- logging.warning("Deleting test volume %s", vol_name)
237
235
  odps_entry.delete_volume(vol_name, auto_remove_dir=True, recursive=True)
238
236
  except:
239
237
  pass
maxframe/typing_.py CHANGED
@@ -15,6 +15,7 @@
15
15
  from numbers import Integral
16
16
  from typing import List, TypeVar, Union
17
17
 
18
+ import numpy as np
18
19
  import pandas as pd
19
20
  import pyarrow as pa
20
21
 
@@ -22,6 +23,7 @@ SlicesType = List[Union[None, Integral, slice]]
22
23
 
23
24
  TimeoutType = Union[int, float, None]
24
25
 
26
+ PandasDType = Union[np.dtype, pd.api.extensions.ExtensionDtype]
25
27
 
26
28
  ArrowTableType = Union[pa.Table, pa.RecordBatch]
27
29
  PandasObjectTypes = Union[
maxframe/udf.py CHANGED
@@ -13,12 +13,18 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import shlex
16
+ import sys
16
17
  from typing import Callable, List, Optional, Union
17
18
 
18
- from odps.models import Resource
19
+ import numpy as np
20
+ from odps.models import Function as ODPSFunctionObj
21
+ from odps.models import Resource as ODPSResourceObj
19
22
 
23
+ from .config.validators import is_positive_integer
24
+ from .core.mode import is_mock_mode
20
25
  from .serialization import load_member
21
26
  from .serialization.serializables import (
27
+ AnyField,
22
28
  BoolField,
23
29
  DictField,
24
30
  FieldTypes,
@@ -27,7 +33,8 @@ from .serialization.serializables import (
27
33
  Serializable,
28
34
  StringField,
29
35
  )
30
- from .utils import extract_class_name, tokenize
36
+ from .typing_ import PandasDType
37
+ from .utils import extract_class_name, make_dtype, tokenize
31
38
 
32
39
 
33
40
  class PythonPackOptions(Serializable):
@@ -106,6 +113,7 @@ class MarkedFunction(Serializable):
106
113
  expect_resources = DictField(
107
114
  "expect_resources", FieldTypes.string, default_factory=dict
108
115
  )
116
+ gpu = BoolField("gpu", default=False)
109
117
 
110
118
  def __init__(self, func: Optional[Callable] = None, **kw):
111
119
  super().__init__(func=func, **kw)
@@ -120,8 +128,100 @@ class MarkedFunction(Serializable):
120
128
  return f"<MarkedFunction {self.func!r}>"
121
129
 
122
130
 
123
- def with_resources(*resources: Union[str, Resource], use_wrapper_class: bool = True):
124
- def res_to_str(res: Union[str, Resource]) -> str:
131
+ class ODPSFunction(Serializable):
132
+ __slots__ = ("_caller_type",)
133
+
134
+ full_function_name = StringField("full_function_name")
135
+ expect_engine = StringField("expect_engine", default=None)
136
+ expect_resources = DictField(
137
+ "expect_resources", FieldTypes.string, default_factory=dict
138
+ )
139
+ result_dtype = AnyField("result_dtype", default=None)
140
+
141
+ def __init__(
142
+ self,
143
+ func,
144
+ expect_engine: str = None,
145
+ expect_resources: dict = None,
146
+ dtype: PandasDType = None,
147
+ **kw,
148
+ ):
149
+ full_function_name = None
150
+ if isinstance(func, str):
151
+ full_function_name = func
152
+ elif isinstance(func, ODPSFunctionObj):
153
+ func_parts = [func.project.name]
154
+ if func.schema:
155
+ func_parts.append(func.schema.name)
156
+ func_parts.append(func.name)
157
+ full_function_name = ":".join(func_parts)
158
+ if full_function_name:
159
+ kw["full_function_name"] = full_function_name
160
+
161
+ if dtype is not None:
162
+ kw["result_dtype"] = make_dtype(dtype)
163
+ super().__init__(
164
+ expect_engine=expect_engine, expect_resources=expect_resources, **kw
165
+ )
166
+
167
+ @property
168
+ def __name__(self):
169
+ return self.full_function_name.rsplit(":", 1)[-1]
170
+
171
+ def _detect_caller_type(self) -> Optional[str]:
172
+ if hasattr(self, "_caller_type"):
173
+ return self._caller_type
174
+
175
+ frame = sys._getframe(1)
176
+ is_set = False
177
+ while frame.f_back:
178
+ f_mod = frame.f_globals.get("__name__")
179
+ if f_mod and f_mod.startswith("maxframe.dataframe."):
180
+ if f_mod.endswith(".map"):
181
+ self._caller_type, is_set = "map", True
182
+ elif f_mod.endswith(".aggregation") or ".reduction." in f_mod:
183
+ self._caller_type, is_set = "agg", True
184
+ if is_set:
185
+ return self._caller_type
186
+ frame = frame.f_back
187
+ return None
188
+
189
+ def __call__(self, obj, *args, **kwargs):
190
+ caller_type = self._detect_caller_type()
191
+ if caller_type == "agg":
192
+ return self._call_aggregate(obj, *args, **kwargs)
193
+ raise NotImplementedError("Need to be referenced inside apply or map functions")
194
+
195
+ def _call_aggregate(self, obj, *args, **kwargs):
196
+ from .dataframe.core import DATAFRAME_TYPE, SERIES_TYPE
197
+ from .dataframe.reduction.custom_reduction import build_custom_reduction_result
198
+
199
+ if isinstance(obj, (DATAFRAME_TYPE, SERIES_TYPE)):
200
+ return build_custom_reduction_result(obj, self)
201
+ if is_mock_mode():
202
+ ret = obj.iloc[0]
203
+ if self.result_dtype:
204
+ if hasattr(ret, "astype"):
205
+ ret = ret.astype(self.result_dtype)
206
+ else: # pragma: no cover
207
+ ret = np.array(ret).astype(self.result_dtype).item()
208
+ return ret
209
+ raise NotImplementedError("Need to be referenced inside apply or map functions")
210
+
211
+ def __repr__(self):
212
+ return f"<ODPSStoredFunction {self.full_function_name}>"
213
+
214
+ @classmethod
215
+ def wrap(cls, func):
216
+ if isinstance(func, ODPSFunctionObj):
217
+ return ODPSFunction(func)
218
+ return func
219
+
220
+
221
+ def with_resources(
222
+ *resources: Union[str, ODPSResourceObj], use_wrapper_class: bool = True
223
+ ):
224
+ def res_to_str(res: Union[str, ODPSResourceObj]) -> str:
125
225
  if isinstance(res, str):
126
226
  return res
127
227
  res_parts = [res.project.name]
@@ -177,6 +277,8 @@ def with_running_options(
177
277
  engine: Optional[str] = None,
178
278
  cpu: Optional[int] = None,
179
279
  memory: Optional[Union[str, int]] = None,
280
+ gu: Optional[int] = None,
281
+ gu_quota: Optional[Union[str, List[str]]] = None,
180
282
  **kwargs,
181
283
  ):
182
284
  """
@@ -191,6 +293,10 @@ def with_running_options(
191
293
  memory: Optional[Union[str, int]]
192
294
  The memory to run the UDF. If it is an int, it is in GB.
193
295
  If it is a str, it is in the format of "10GiB", "30MiB", etc.
296
+ gu: Optional[int]
297
+ The GU number to run the UDF.
298
+ gu_quota: Optional[Union[str, List[str]]]
299
+ The GU quota nicknames to run the UDF. The order is the priority of the usage.
194
300
  kwargs
195
301
  Other running options.
196
302
  """
@@ -204,20 +310,37 @@ def with_running_options(
204
310
  raise TypeError("memory must be an int or str")
205
311
  if isinstance(memory, int) and memory <= 0:
206
312
  raise ValueError("memory must be greater than 0")
313
+ if gu is not None and gu <= 0:
314
+ raise ValueError("gu must be greater than 0")
315
+ if gu is not None and (cpu or memory):
316
+ raise ValueError("gu can't be specified with cpu or memory")
207
317
 
208
318
  if cpu:
209
319
  resources["cpu"] = cpu
210
320
  if memory:
211
321
  resources["memory"] = memory
212
322
 
323
+ if isinstance(gu_quota, str):
324
+ gu_quota = [gu_quota]
325
+
326
+ resources["gpu"] = gu
327
+ resources["gu_quota"] = gu_quota
328
+ use_gpu = is_positive_integer(gu)
329
+
213
330
  def func_wrapper(func):
214
- if all(v is None for v in (engine, cpu, memory)):
331
+ if all(v is None for v in (engine, cpu, memory, gu, gu_quota)):
215
332
  return func
216
333
  if isinstance(func, MarkedFunction):
217
334
  func.expect_engine = engine
218
335
  func.expect_resources = resources
336
+ func.gpu = use_gpu
219
337
  return func
220
- return MarkedFunction(func, expect_engine=engine, expect_resources=resources)
338
+ return MarkedFunction(
339
+ func,
340
+ expect_engine=engine,
341
+ expect_resources=resources,
342
+ gpu=use_gpu,
343
+ )
221
344
 
222
345
  return func_wrapper
223
346
 
@@ -225,9 +348,7 @@ def with_running_options(
225
348
  with_resource_libraries = with_resources
226
349
 
227
350
 
228
- def get_udf_resources(
229
- func: Callable,
230
- ) -> List[Union[Resource, str]]:
351
+ def get_udf_resources(func: Callable) -> List[Union[ODPSResourceObj, str]]:
231
352
  return getattr(func, "resources", None) or []
232
353
 
233
354