lib-x17-fintech 2.1.3__py3-none-any.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.
Files changed (282) hide show
  1. lib_x17_fintech-2.1.3.dist-info/METADATA +633 -0
  2. lib_x17_fintech-2.1.3.dist-info/RECORD +282 -0
  3. lib_x17_fintech-2.1.3.dist-info/WHEEL +5 -0
  4. lib_x17_fintech-2.1.3.dist-info/licenses/LICENSE +1 -0
  5. lib_x17_fintech-2.1.3.dist-info/top_level.txt +1 -0
  6. xfintech/__init__.py +0 -0
  7. xfintech/connect/__init__.py +18 -0
  8. xfintech/connect/artifact/__init__.py +5 -0
  9. xfintech/connect/artifact/artifact.py +168 -0
  10. xfintech/connect/artifact/tests/__init__.py +3 -0
  11. xfintech/connect/artifact/tests/test_class_artifact_all.py +564 -0
  12. xfintech/connect/common/__init__.py +12 -0
  13. xfintech/connect/common/connect.py +49 -0
  14. xfintech/connect/common/connectref.py +119 -0
  15. xfintech/connect/common/error.py +62 -0
  16. xfintech/connect/common/tests/__init__.py +1 -0
  17. xfintech/connect/common/tests/test_class_connectlike_all.py +544 -0
  18. xfintech/connect/common/tests/test_class_connectref_all.py +586 -0
  19. xfintech/connect/common/tests/test_class_errors_all.py +524 -0
  20. xfintech/connect/instance/__init__.py +7 -0
  21. xfintech/connect/instance/macos.py +121 -0
  22. xfintech/connect/instance/s3.py +176 -0
  23. xfintech/connect/instance/tests/__init__.py +1 -0
  24. xfintech/connect/instance/tests/test_class_macosconnect_all.py +692 -0
  25. xfintech/connect/instance/tests/test_class_s3connect_all.py +603 -0
  26. xfintech/data/__init__.py +20 -0
  27. xfintech/data/common/__init__.py +15 -0
  28. xfintech/data/common/cache.py +186 -0
  29. xfintech/data/common/coolant.py +171 -0
  30. xfintech/data/common/metric.py +138 -0
  31. xfintech/data/common/paginate.py +132 -0
  32. xfintech/data/common/params.py +162 -0
  33. xfintech/data/common/retry.py +201 -0
  34. xfintech/data/common/tests/__init__.py +1 -0
  35. xfintech/data/common/tests/test_class_cache_all.py +681 -0
  36. xfintech/data/common/tests/test_class_coolant_all.py +534 -0
  37. xfintech/data/common/tests/test_class_metric_all.py +705 -0
  38. xfintech/data/common/tests/test_class_paginate_all.py +508 -0
  39. xfintech/data/common/tests/test_class_params_all.py +891 -0
  40. xfintech/data/common/tests/test_class_retry_all.py +714 -0
  41. xfintech/data/job/__init__.py +17 -0
  42. xfintech/data/job/errors.py +112 -0
  43. xfintech/data/job/house.py +156 -0
  44. xfintech/data/job/job.py +247 -0
  45. xfintech/data/job/joblike.py +47 -0
  46. xfintech/data/job/tests/__init__.py +1 -0
  47. xfintech/data/job/tests/test_class_errors_all.py +275 -0
  48. xfintech/data/job/tests/test_class_house_all.py +801 -0
  49. xfintech/data/job/tests/test_class_job_all.py +684 -0
  50. xfintech/data/job/tests/test_class_joblike_all.py +482 -0
  51. xfintech/data/relay/__init__.py +7 -0
  52. xfintech/data/relay/client.py +114 -0
  53. xfintech/data/relay/clientlike.py +45 -0
  54. xfintech/data/relay/tests/test_class_relayclient_all.py +484 -0
  55. xfintech/data/relay/tests/test_class_relayclientlike_all.py +500 -0
  56. xfintech/data/source/__init__.py +7 -0
  57. xfintech/data/source/baostock/__init__.py +21 -0
  58. xfintech/data/source/baostock/job/__init__.py +5 -0
  59. xfintech/data/source/baostock/job/job.py +217 -0
  60. xfintech/data/source/baostock/job/tests/__init__.py +0 -0
  61. xfintech/data/source/baostock/job/tests/test_class_baostockjob_all.py +547 -0
  62. xfintech/data/source/baostock/session/__init__.py +8 -0
  63. xfintech/data/source/baostock/session/relay.py +223 -0
  64. xfintech/data/source/baostock/session/session.py +241 -0
  65. xfintech/data/source/baostock/session/tests/__init__.py +0 -0
  66. xfintech/data/source/baostock/session/tests/test_class_relay_all.py +694 -0
  67. xfintech/data/source/baostock/session/tests/test_class_session_all.py +505 -0
  68. xfintech/data/source/baostock/stock/__init__.py +0 -0
  69. xfintech/data/source/baostock/stock/hs300stock/__init__.py +3 -0
  70. xfintech/data/source/baostock/stock/hs300stock/constant.py +49 -0
  71. xfintech/data/source/baostock/stock/hs300stock/hs300stock.py +133 -0
  72. xfintech/data/source/baostock/stock/hs300stock/tests/__init__.py +1 -0
  73. xfintech/data/source/baostock/stock/hs300stock/tests/test_class_hs300index_all.py +413 -0
  74. xfintech/data/source/baostock/stock/minuteline/__init__.py +19 -0
  75. xfintech/data/source/baostock/stock/minuteline/constant.py +89 -0
  76. xfintech/data/source/baostock/stock/minuteline/minuteline.py +163 -0
  77. xfintech/data/source/baostock/stock/minuteline/tests/__init__.py +0 -0
  78. xfintech/data/source/baostock/stock/minuteline/tests/test_class_minuteline_all.py +582 -0
  79. xfintech/data/source/baostock/stock/stock/__init__.py +19 -0
  80. xfintech/data/source/baostock/stock/stock/constant.py +55 -0
  81. xfintech/data/source/baostock/stock/stock/stock.py +149 -0
  82. xfintech/data/source/baostock/stock/stock/tests/__init__.py +0 -0
  83. xfintech/data/source/baostock/stock/stock/tests/test_class_stock_all.py +508 -0
  84. xfintech/data/source/baostock/stock/stockinfo/__init__.py +5 -0
  85. xfintech/data/source/baostock/stock/stockinfo/constant.py +66 -0
  86. xfintech/data/source/baostock/stock/stockinfo/stockinfo.py +176 -0
  87. xfintech/data/source/baostock/stock/stockinfo/tests/__init__.py +1 -0
  88. xfintech/data/source/baostock/stock/stockinfo/tests/test_class_stockinfo_all.py +617 -0
  89. xfintech/data/source/baostock/stock/sz50stock/__init__.py +3 -0
  90. xfintech/data/source/baostock/stock/sz50stock/constant.py +49 -0
  91. xfintech/data/source/baostock/stock/sz50stock/sz50stock.py +133 -0
  92. xfintech/data/source/baostock/stock/sz50stock/tests/__init__.py +1 -0
  93. xfintech/data/source/baostock/stock/sz50stock/tests/test_class_sz50stock_all.py +397 -0
  94. xfintech/data/source/baostock/stock/tradedate/__init__.py +19 -0
  95. xfintech/data/source/baostock/stock/tradedate/constant.py +72 -0
  96. xfintech/data/source/baostock/stock/tradedate/tests/__init__.py +0 -0
  97. xfintech/data/source/baostock/stock/tradedate/tests/test_class_tradedate_all.py +695 -0
  98. xfintech/data/source/baostock/stock/tradedate/tradedate.py +208 -0
  99. xfintech/data/source/baostock/stock/zz500stock/__init__.py +3 -0
  100. xfintech/data/source/baostock/stock/zz500stock/constant.py +55 -0
  101. xfintech/data/source/baostock/stock/zz500stock/tests/__init__.py +1 -0
  102. xfintech/data/source/baostock/stock/zz500stock/tests/test_class_zz500stock_all.py +421 -0
  103. xfintech/data/source/baostock/stock/zz500stock/zz500stock.py +133 -0
  104. xfintech/data/source/tushare/__init__.py +61 -0
  105. xfintech/data/source/tushare/job/__init__.py +5 -0
  106. xfintech/data/source/tushare/job/job.py +257 -0
  107. xfintech/data/source/tushare/job/tests/test_class_tusharejob_all.py +589 -0
  108. xfintech/data/source/tushare/session/__init__.py +5 -0
  109. xfintech/data/source/tushare/session/relay.py +231 -0
  110. xfintech/data/source/tushare/session/session.py +239 -0
  111. xfintech/data/source/tushare/session/tests/test_class_relay_all.py +719 -0
  112. xfintech/data/source/tushare/session/tests/test_class_session_all.py +705 -0
  113. xfintech/data/source/tushare/stock/__init__.py +55 -0
  114. xfintech/data/source/tushare/stock/adjfactor/__init__.py +19 -0
  115. xfintech/data/source/tushare/stock/adjfactor/adjfactor.py +150 -0
  116. xfintech/data/source/tushare/stock/adjfactor/constant.py +71 -0
  117. xfintech/data/source/tushare/stock/adjfactor/tests/__init__.py +0 -0
  118. xfintech/data/source/tushare/stock/adjfactor/tests/test_class_adjfactor_all.py +372 -0
  119. xfintech/data/source/tushare/stock/capflow/__init__.py +19 -0
  120. xfintech/data/source/tushare/stock/capflow/capflow.py +171 -0
  121. xfintech/data/source/tushare/stock/capflow/constant.py +105 -0
  122. xfintech/data/source/tushare/stock/capflow/tests/__init__.py +0 -0
  123. xfintech/data/source/tushare/stock/capflow/tests/test_class_capflow_all.py +589 -0
  124. xfintech/data/source/tushare/stock/capflowdc/__init__.py +19 -0
  125. xfintech/data/source/tushare/stock/capflowdc/capflowdc.py +167 -0
  126. xfintech/data/source/tushare/stock/capflowdc/constant.py +95 -0
  127. xfintech/data/source/tushare/stock/capflowdc/tests/__init__.py +0 -0
  128. xfintech/data/source/tushare/stock/capflowdc/tests/test_class_capflowdc_all.py +814 -0
  129. xfintech/data/source/tushare/stock/capflowths/__init__.py +19 -0
  130. xfintech/data/source/tushare/stock/capflowths/capflowths.py +173 -0
  131. xfintech/data/source/tushare/stock/capflowths/constant.py +92 -0
  132. xfintech/data/source/tushare/stock/capflowths/tests/__init__.py +0 -0
  133. xfintech/data/source/tushare/stock/capflowths/tests/test_class_capflowths_all.py +551 -0
  134. xfintech/data/source/tushare/stock/company/__init__.py +19 -0
  135. xfintech/data/source/tushare/stock/company/company.py +188 -0
  136. xfintech/data/source/tushare/stock/company/constant.py +92 -0
  137. xfintech/data/source/tushare/stock/company/tests/__init__.py +1 -0
  138. xfintech/data/source/tushare/stock/company/tests/test_class_company_all.py +829 -0
  139. xfintech/data/source/tushare/stock/companybusiness/__init__.py +21 -0
  140. xfintech/data/source/tushare/stock/companybusiness/companybusiness.py +183 -0
  141. xfintech/data/source/tushare/stock/companybusiness/constant.py +91 -0
  142. xfintech/data/source/tushare/stock/companybusiness/tests/__init__.py +0 -0
  143. xfintech/data/source/tushare/stock/companybusiness/tests/test_class_companybusiness_all.py +633 -0
  144. xfintech/data/source/tushare/stock/companycashflow/__init__.py +21 -0
  145. xfintech/data/source/tushare/stock/companycashflow/companycashflow.py +277 -0
  146. xfintech/data/source/tushare/stock/companycashflow/constant.py +293 -0
  147. xfintech/data/source/tushare/stock/companycashflow/tests/__init__.py +0 -0
  148. xfintech/data/source/tushare/stock/companycashflow/tests/test_class_companycashflow_all.py +619 -0
  149. xfintech/data/source/tushare/stock/companydebt/__init__.py +19 -0
  150. xfintech/data/source/tushare/stock/companydebt/companydebt.py +339 -0
  151. xfintech/data/source/tushare/stock/companydebt/constant.py +403 -0
  152. xfintech/data/source/tushare/stock/companydebt/tests/__init__.py +0 -0
  153. xfintech/data/source/tushare/stock/companydebt/tests/test_class_companydebt_all.py +655 -0
  154. xfintech/data/source/tushare/stock/companyoverview/__init__.py +21 -0
  155. xfintech/data/source/tushare/stock/companyoverview/companyoverview.py +214 -0
  156. xfintech/data/source/tushare/stock/companyoverview/constant.py +152 -0
  157. xfintech/data/source/tushare/stock/companyoverview/tests/__init__.py +0 -0
  158. xfintech/data/source/tushare/stock/companyoverview/tests/test_class_companyoverview_all.py +647 -0
  159. xfintech/data/source/tushare/stock/companyprofit/__init__.py +21 -0
  160. xfintech/data/source/tushare/stock/companyprofit/companyprofit.py +272 -0
  161. xfintech/data/source/tushare/stock/companyprofit/constant.py +259 -0
  162. xfintech/data/source/tushare/stock/companyprofit/tests/__init__.py +0 -0
  163. xfintech/data/source/tushare/stock/companyprofit/tests/test_class_companyprofit_all.py +635 -0
  164. xfintech/data/source/tushare/stock/conceptcapflowdc/__init__.py +21 -0
  165. xfintech/data/source/tushare/stock/conceptcapflowdc/conceptcapflowdc.py +175 -0
  166. xfintech/data/source/tushare/stock/conceptcapflowdc/constant.py +106 -0
  167. xfintech/data/source/tushare/stock/conceptcapflowdc/tests/__init__.py +0 -0
  168. xfintech/data/source/tushare/stock/conceptcapflowdc/tests/test_class_conceptcapflowdc_all.py +568 -0
  169. xfintech/data/source/tushare/stock/conceptcapflowths/__init__.py +21 -0
  170. xfintech/data/source/tushare/stock/conceptcapflowths/conceptcapflowths.py +188 -0
  171. xfintech/data/source/tushare/stock/conceptcapflowths/constant.py +89 -0
  172. xfintech/data/source/tushare/stock/conceptcapflowths/tests/__init__.py +0 -0
  173. xfintech/data/source/tushare/stock/conceptcapflowths/tests/test_class_conceptcapflowths_all.py +516 -0
  174. xfintech/data/source/tushare/stock/dayline/__init__.py +19 -0
  175. xfintech/data/source/tushare/stock/dayline/constant.py +87 -0
  176. xfintech/data/source/tushare/stock/dayline/dayline.py +177 -0
  177. xfintech/data/source/tushare/stock/dayline/tests/__init__.py +0 -0
  178. xfintech/data/source/tushare/stock/dayline/tests/test_class_dayline_all.py +585 -0
  179. xfintech/data/source/tushare/stock/industrycapflowths/__init__.py +21 -0
  180. xfintech/data/source/tushare/stock/industrycapflowths/constant.py +89 -0
  181. xfintech/data/source/tushare/stock/industrycapflowths/industrycapflowths.py +192 -0
  182. xfintech/data/source/tushare/stock/industrycapflowths/tests/__init__.py +0 -0
  183. xfintech/data/source/tushare/stock/industrycapflowths/tests/test_class_industrycapflowths_all.py +683 -0
  184. xfintech/data/source/tushare/stock/marketindexcapflowdc/__init__.py +21 -0
  185. xfintech/data/source/tushare/stock/marketindexcapflowdc/constant.py +90 -0
  186. xfintech/data/source/tushare/stock/marketindexcapflowdc/marketindexcapflowdc.py +173 -0
  187. xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/__init__.py +0 -0
  188. xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/test_class_marketindexcapflowdc_all.py +793 -0
  189. xfintech/data/source/tushare/stock/monthline/__init__.py +19 -0
  190. xfintech/data/source/tushare/stock/monthline/constant.py +87 -0
  191. xfintech/data/source/tushare/stock/monthline/monthline.py +180 -0
  192. xfintech/data/source/tushare/stock/monthline/tests/__init__.py +0 -0
  193. xfintech/data/source/tushare/stock/monthline/tests/test_class_monthline_all.py +574 -0
  194. xfintech/data/source/tushare/stock/stock/__init__.py +19 -0
  195. xfintech/data/source/tushare/stock/stock/constant.py +105 -0
  196. xfintech/data/source/tushare/stock/stock/stock.py +193 -0
  197. xfintech/data/source/tushare/stock/stock/tests/__init__.py +0 -0
  198. xfintech/data/source/tushare/stock/stock/tests/test_class_stock_all.py +788 -0
  199. xfintech/data/source/tushare/stock/stockdividend/__init__.py +21 -0
  200. xfintech/data/source/tushare/stock/stockdividend/constant.py +111 -0
  201. xfintech/data/source/tushare/stock/stockdividend/stockdividend.py +180 -0
  202. xfintech/data/source/tushare/stock/stockdividend/tests/__init__.py +0 -0
  203. xfintech/data/source/tushare/stock/stockdividend/tests/test_class_stockdividend_all.py +725 -0
  204. xfintech/data/source/tushare/stock/stockinfo/__init__.py +19 -0
  205. xfintech/data/source/tushare/stock/stockinfo/constant.py +104 -0
  206. xfintech/data/source/tushare/stock/stockinfo/stockinfo.py +208 -0
  207. xfintech/data/source/tushare/stock/stockinfo/tests/__init__.py +0 -0
  208. xfintech/data/source/tushare/stock/stockinfo/tests/test_class_stockinfo_all.py +881 -0
  209. xfintech/data/source/tushare/stock/stockipo/__init__.py +19 -0
  210. xfintech/data/source/tushare/stock/stockipo/constant.py +90 -0
  211. xfintech/data/source/tushare/stock/stockipo/stockipo.py +234 -0
  212. xfintech/data/source/tushare/stock/stockipo/tests/__init__.py +1 -0
  213. xfintech/data/source/tushare/stock/stockipo/tests/test_class_stockipo_all.py +750 -0
  214. xfintech/data/source/tushare/stock/stockpledge/__init__.py +19 -0
  215. xfintech/data/source/tushare/stock/stockpledge/constant.py +72 -0
  216. xfintech/data/source/tushare/stock/stockpledge/stockpledge.py +158 -0
  217. xfintech/data/source/tushare/stock/stockpledge/tests/__init__.py +0 -0
  218. xfintech/data/source/tushare/stock/stockpledge/tests/test_class_stockpledge_all.py +664 -0
  219. xfintech/data/source/tushare/stock/stockpledgedetail/__init__.py +21 -0
  220. xfintech/data/source/tushare/stock/stockpledgedetail/constant.py +85 -0
  221. xfintech/data/source/tushare/stock/stockpledgedetail/stockpledgedetail.py +171 -0
  222. xfintech/data/source/tushare/stock/stockpledgedetail/tests/__init__.py +0 -0
  223. xfintech/data/source/tushare/stock/stockpledgedetail/tests/test_class_stockpledgedetail_all.py +112 -0
  224. xfintech/data/source/tushare/stock/stockst/__init__.py +19 -0
  225. xfintech/data/source/tushare/stock/stockst/constant.py +80 -0
  226. xfintech/data/source/tushare/stock/stockst/stockst.py +189 -0
  227. xfintech/data/source/tushare/stock/stockst/tests/__init__.py +0 -0
  228. xfintech/data/source/tushare/stock/stockst/tests/test_class_stockst_all.py +693 -0
  229. xfintech/data/source/tushare/stock/stocksuspend/__init__.py +21 -0
  230. xfintech/data/source/tushare/stock/stocksuspend/constant.py +75 -0
  231. xfintech/data/source/tushare/stock/stocksuspend/stocksuspend.py +151 -0
  232. xfintech/data/source/tushare/stock/stocksuspend/tests/__init__.py +0 -0
  233. xfintech/data/source/tushare/stock/stocksuspend/tests/test_class_stocksuspend_all.py +626 -0
  234. xfintech/data/source/tushare/stock/techindex/__init__.py +19 -0
  235. xfintech/data/source/tushare/stock/techindex/constant.py +600 -0
  236. xfintech/data/source/tushare/stock/techindex/techindex.py +314 -0
  237. xfintech/data/source/tushare/stock/techindex/tests/__init__.py +0 -0
  238. xfintech/data/source/tushare/stock/techindex/tests/test_class_techindex_all.py +576 -0
  239. xfintech/data/source/tushare/stock/tradedate/__init__.py +19 -0
  240. xfintech/data/source/tushare/stock/tradedate/constant.py +93 -0
  241. xfintech/data/source/tushare/stock/tradedate/tests/__init__.py +0 -0
  242. xfintech/data/source/tushare/stock/tradedate/tests/test_class_tradedate_all.py +947 -0
  243. xfintech/data/source/tushare/stock/tradedate/tradedate.py +234 -0
  244. xfintech/data/source/tushare/stock/weekline/__init__.py +19 -0
  245. xfintech/data/source/tushare/stock/weekline/constant.py +87 -0
  246. xfintech/data/source/tushare/stock/weekline/tests/__init__.py +0 -0
  247. xfintech/data/source/tushare/stock/weekline/tests/test_class_weekline_all.py +575 -0
  248. xfintech/data/source/tushare/stock/weekline/weekline.py +182 -0
  249. xfintech/fabric/__init__.py +18 -0
  250. xfintech/fabric/column/__init__.py +7 -0
  251. xfintech/fabric/column/info.py +202 -0
  252. xfintech/fabric/column/kind.py +102 -0
  253. xfintech/fabric/column/tests/__init__.py +0 -0
  254. xfintech/fabric/column/tests/test_class_info_all.py +207 -0
  255. xfintech/fabric/column/tests/test_class_kind_all.py +80 -0
  256. xfintech/fabric/table/__init__.py +5 -0
  257. xfintech/fabric/table/info.py +263 -0
  258. xfintech/fabric/table/tests/__init__.py +0 -0
  259. xfintech/fabric/table/tests/test_class_info_all.py +547 -0
  260. xfintech/serde/__init__.py +35 -0
  261. xfintech/serde/common/__init__.py +9 -0
  262. xfintech/serde/common/dataformat.py +78 -0
  263. xfintech/serde/common/deserialiserlike.py +38 -0
  264. xfintech/serde/common/error.py +182 -0
  265. xfintech/serde/common/serialiserlike.py +38 -0
  266. xfintech/serde/common/tests/__init__.py +1 -0
  267. xfintech/serde/common/tests/test_class_dataformat_all.py +694 -0
  268. xfintech/serde/common/tests/test_class_deserialiserlike_all.py +500 -0
  269. xfintech/serde/common/tests/test_class_errors_all.py +518 -0
  270. xfintech/serde/common/tests/test_class_serialiserlike_all.py +401 -0
  271. xfintech/serde/deserialiser/__init__.py +7 -0
  272. xfintech/serde/deserialiser/pandas.py +113 -0
  273. xfintech/serde/deserialiser/python.py +68 -0
  274. xfintech/serde/deserialiser/tests/__init__.py +1 -0
  275. xfintech/serde/deserialiser/tests/test_class_pandasdeserialiser_all.py +503 -0
  276. xfintech/serde/deserialiser/tests/test_class_pythondeserialiser_all.py +570 -0
  277. xfintech/serde/serialiser/__init__.py +7 -0
  278. xfintech/serde/serialiser/pandas.py +116 -0
  279. xfintech/serde/serialiser/python.py +71 -0
  280. xfintech/serde/serialiser/tests/__init__.py +1 -0
  281. xfintech/serde/serialiser/tests/test_class_pandasserialiser_all.py +474 -0
  282. xfintech/serde/serialiser/tests/test_class_pythonserialiser_all.py +508 -0
@@ -0,0 +1,725 @@
1
+ """
2
+ Comprehensive test suite for StockDividend class
3
+ Tests cover initialization, transformation, execution, and integration scenarios
4
+ """
5
+
6
+ import pandas as pd
7
+ import pytest
8
+
9
+ from xfintech.data.source.tushare.stock.stockdividend import StockDividend
10
+ from xfintech.data.source.tushare.stock.stockdividend.constant import (
11
+ KEY,
12
+ NAME,
13
+ PAGINATE,
14
+ SOURCE,
15
+ TARGET,
16
+ )
17
+
18
+ # ============================================================================
19
+ # Test Fixtures
20
+ # ============================================================================
21
+
22
+
23
+ class FakeConnection:
24
+ """Fake Tushare connection for testing"""
25
+
26
+ def __init__(self, frame: pd.DataFrame):
27
+ self.frame = frame
28
+
29
+ def dividend(self, **kwargs):
30
+ """Mock dividend API call"""
31
+ return self.frame
32
+
33
+
34
+ class FakeSession:
35
+ """Fake session for testing"""
36
+
37
+ def __init__(self, connection: FakeConnection):
38
+ self.connection = connection
39
+
40
+
41
+ @pytest.fixture
42
+ def mock_session():
43
+ """Create a mock session with empty data"""
44
+ fake_conn = FakeConnection(frame=pd.DataFrame())
45
+ return FakeSession(fake_conn)
46
+
47
+
48
+ @pytest.fixture
49
+ def sample_source_data():
50
+ """Sample dividend data in Tushare format"""
51
+ return pd.DataFrame(
52
+ {
53
+ "ts_code": ["600848.SH", "600848.SH", "000001.SZ"],
54
+ "end_date": ["20201231", "20191231", "20201231"],
55
+ "ann_date": ["20210415", "20200410", "20210420"],
56
+ "div_proc": ["实施", "实施", "预案"],
57
+ "stk_div": ["0.10", "0.15", "0.00"],
58
+ "stk_bo_rate": ["0.05", "0.08", "0.00"],
59
+ "stk_co_rate": ["0.05", "0.07", "0.00"],
60
+ "cash_div": ["0.50", "0.60", "0.30"],
61
+ "cash_div_tax": ["0.55", "0.65", "0.32"],
62
+ "record_date": ["20210520", "20200515", "20210525"],
63
+ "ex_date": ["20210521", "20200516", "20210526"],
64
+ "pay_date": ["20210528", "20200525", "20210601"],
65
+ "div_listdate": ["20210528", "20200525", "20210601"],
66
+ "imp_ann_date": ["20210415", "20200410", "20210420"],
67
+ "base_date": ["20201231", "20191231", "20201231"],
68
+ "base_share": ["100000.00", "95000.00", "200000.00"],
69
+ }
70
+ )
71
+
72
+
73
+ # ============================================================================
74
+ # Initialization Tests
75
+ # ============================================================================
76
+
77
+
78
+ def test_stockdividend_init_basic(mock_session):
79
+ """Test basic initialization with required session"""
80
+ dividend = StockDividend(session=mock_session)
81
+ assert dividend.name == NAME
82
+ assert dividend.key == KEY
83
+ assert dividend.source == SOURCE
84
+ assert dividend.target == TARGET
85
+ assert dividend.paginate == PAGINATE
86
+
87
+
88
+ def test_stockdividend_init_with_params_dict(mock_session):
89
+ """Test initialization with params as dict"""
90
+ params = {"ts_code": "600848.SH", "ann_date": "20210415"}
91
+ dividend = StockDividend(session=mock_session, params=params)
92
+ assert dividend.params.get("ts_code") == "600848.SH"
93
+ assert dividend.params.get("ann_date") == "20210415"
94
+
95
+
96
+ def test_stockdividend_init_with_params_object(mock_session):
97
+ """Test initialization with params as Params object"""
98
+ from xfintech.data.common.params import Params
99
+
100
+ params = Params(ts_code="600848.SH")
101
+ dividend = StockDividend(session=mock_session, params=params)
102
+ assert dividend.params.get("ts_code") == "600848.SH"
103
+
104
+
105
+ def test_stockdividend_init_with_multiple_date_params(mock_session):
106
+ """Test initialization with multiple date parameters"""
107
+ params = {
108
+ "ts_code": "600848.SH",
109
+ "ann_date": "20210415",
110
+ "record_date": "20210520",
111
+ "ex_date": "20210521",
112
+ }
113
+ dividend = StockDividend(session=mock_session, params=params)
114
+ assert dividend.params.get("ann_date") == "20210415"
115
+ assert dividend.params.get("record_date") == "20210520"
116
+
117
+
118
+ def test_stockdividend_init_with_cache_bool_true(mock_session):
119
+ """Test initialization with cache enabled"""
120
+ dividend = StockDividend(session=mock_session, cache=True)
121
+ assert dividend.cache is not None
122
+
123
+
124
+ def test_stockdividend_init_with_cache_bool_false(mock_session):
125
+ """Test initialization with cache disabled"""
126
+ dividend = StockDividend(session=mock_session, cache=False)
127
+ assert dividend.cache is None
128
+
129
+
130
+ def test_stockdividend_init_with_cache_dict(mock_session):
131
+ """Test initialization with cache config dict"""
132
+ cache_config = {"path": "/tmp/cache", "key": "test"}
133
+ dividend = StockDividend(session=mock_session, cache=cache_config)
134
+ assert dividend.cache is not None
135
+
136
+
137
+ def test_stockdividend_init_default_paginate_limit(mock_session):
138
+ """Test that default pagination limit is set correctly"""
139
+ dividend = StockDividend(session=mock_session)
140
+ assert dividend.paginate.pagesize == 1000
141
+ assert dividend.paginate.pagelimit == 1000
142
+
143
+
144
+ def test_stockdividend_init_with_all_params(mock_session):
145
+ """Test initialization with all parameters"""
146
+ params = {"ts_code": "600848.SH", "ann_date": "20210415"}
147
+ coolant = {"interval": 0.5}
148
+ retry = {"max_attempts": 3}
149
+ cache = True
150
+
151
+ dividend = StockDividend(session=mock_session, params=params, coolant=coolant, retry=retry, cache=cache)
152
+ assert dividend.params.get("ts_code") == "600848.SH"
153
+ assert dividend.cache is not None
154
+
155
+
156
+ def test_stockdividend_constants():
157
+ """Test that constants are correctly defined"""
158
+ assert NAME == "stockdividend"
159
+ assert KEY == "/tushare/stockdividend"
160
+ assert SOURCE.name == "dividend"
161
+ assert TARGET.name == "stockdividend"
162
+ assert PAGINATE.pagesize == 1000
163
+ assert PAGINATE.pagelimit == 1000
164
+
165
+
166
+ # ============================================================================
167
+ # Transform Tests
168
+ # ============================================================================
169
+
170
+
171
+ def test_stockdividend_transform_basic(sample_source_data):
172
+ """Test basic transformation of dividend data"""
173
+ fake_conn = FakeConnection(frame=sample_source_data)
174
+ session = FakeSession(fake_conn)
175
+ dividend = StockDividend(session=session)
176
+
177
+ result = dividend.transform(sample_source_data)
178
+
179
+ assert len(result) == 3
180
+ assert "code" in result.columns
181
+ assert "ann_date" in result.columns
182
+ assert "ann_datecode" in result.columns
183
+
184
+
185
+ def test_stockdividend_transform_code_mapping(sample_source_data):
186
+ """Test that ts_code is correctly mapped to code"""
187
+ fake_conn = FakeConnection(frame=sample_source_data)
188
+ session = FakeSession(fake_conn)
189
+ dividend = StockDividend(session=session)
190
+
191
+ result = dividend.transform(sample_source_data)
192
+
193
+ assert result.iloc[0]["code"] == "000001.SZ"
194
+ assert result.iloc[1]["code"] == "600848.SH"
195
+
196
+
197
+ def test_stockdividend_transform_date_format(sample_source_data):
198
+ """Test that dates are properly formatted"""
199
+ fake_conn = FakeConnection(frame=sample_source_data)
200
+ session = FakeSession(fake_conn)
201
+ dividend = StockDividend(session=session)
202
+
203
+ result = dividend.transform(sample_source_data)
204
+
205
+ assert pd.api.types.is_datetime64_any_dtype(result["ann_date"]) is False
206
+ assert result.iloc[1]["ann_date"] == "2020-04-10"
207
+ assert result.iloc[1]["record_date"] == "2020-05-15"
208
+
209
+
210
+ def test_stockdividend_transform_datecode_preserved(sample_source_data):
211
+ """Test that datecode is correctly created"""
212
+ fake_conn = FakeConnection(frame=sample_source_data)
213
+ session = FakeSession(fake_conn)
214
+ dividend = StockDividend(session=session)
215
+
216
+ result = dividend.transform(sample_source_data)
217
+
218
+ assert result.iloc[1]["ann_datecode"] == "20200410"
219
+ assert result.iloc[1]["record_datecode"] == "20200515"
220
+ assert result.iloc[1]["ex_datecode"] == "20200516"
221
+
222
+
223
+ def test_stockdividend_transform_numeric_conversions(sample_source_data):
224
+ """Test that numeric fields are properly converted"""
225
+ fake_conn = FakeConnection(frame=sample_source_data)
226
+ session = FakeSession(fake_conn)
227
+ dividend = StockDividend(session=session)
228
+
229
+ result = dividend.transform(sample_source_data)
230
+
231
+ assert result.iloc[1]["stk_div"] == 0.15
232
+ assert result.iloc[1]["cash_div"] == 0.60
233
+ assert result.iloc[1]["base_share"] == 95000.00
234
+ assert pd.api.types.is_numeric_dtype(result["stk_div"])
235
+
236
+
237
+ def test_stockdividend_transform_string_fields(sample_source_data):
238
+ """Test that string fields are properly converted"""
239
+ fake_conn = FakeConnection(frame=sample_source_data)
240
+ session = FakeSession(fake_conn)
241
+ dividend = StockDividend(session=session)
242
+
243
+ result = dividend.transform(sample_source_data)
244
+
245
+ assert result.iloc[1]["div_proc"] == "实施"
246
+ assert result.iloc[0]["div_proc"] == "预案"
247
+ assert result.iloc[1]["end_date"] == "20191231"
248
+
249
+
250
+ def test_stockdividend_transform_empty_dataframe():
251
+ """Test transformation with empty dataframe"""
252
+ fake_conn = FakeConnection(frame=pd.DataFrame())
253
+ session = FakeSession(fake_conn)
254
+ dividend = StockDividend(session=session)
255
+
256
+ result = dividend.transform(pd.DataFrame())
257
+
258
+ assert isinstance(result, pd.DataFrame)
259
+ assert result.empty
260
+ assert len(result.columns) == len(TARGET.list_column_names())
261
+
262
+
263
+ def test_stockdividend_transform_none_input():
264
+ """Test transformation with None input"""
265
+ fake_conn = FakeConnection(frame=pd.DataFrame())
266
+ session = FakeSession(fake_conn)
267
+ dividend = StockDividend(session=session)
268
+
269
+ result = dividend.transform(None)
270
+
271
+ assert isinstance(result, pd.DataFrame)
272
+ assert result.empty
273
+
274
+
275
+ def test_stockdividend_transform_handles_invalid_dates():
276
+ """Test that invalid dates are handled gracefully"""
277
+ data = pd.DataFrame(
278
+ {
279
+ "ts_code": ["600848.SH"],
280
+ "end_date": ["20201231"],
281
+ "ann_date": ["invalid"],
282
+ "div_proc": ["实施"],
283
+ "stk_div": ["0.10"],
284
+ "cash_div": ["0.50"],
285
+ "record_date": ["20210520"],
286
+ "ex_date": ["20210521"],
287
+ "pay_date": ["20210528"],
288
+ "div_listdate": ["20210528"],
289
+ "imp_ann_date": ["20210415"],
290
+ "base_date": ["20201231"],
291
+ }
292
+ )
293
+
294
+ fake_conn = FakeConnection(frame=data)
295
+ session = FakeSession(fake_conn)
296
+ dividend = StockDividend(session=session)
297
+
298
+ result = dividend.transform(data)
299
+
300
+ assert len(result) == 1
301
+ assert pd.isna(result.iloc[0]["ann_date"])
302
+
303
+
304
+ def test_stockdividend_transform_removes_duplicates(sample_source_data):
305
+ """Test that duplicate rows are removed"""
306
+ # Create data with duplicates
307
+ data = pd.concat([sample_source_data, sample_source_data.iloc[[0]]], ignore_index=True)
308
+
309
+ fake_conn = FakeConnection(frame=data)
310
+ session = FakeSession(fake_conn)
311
+ dividend = StockDividend(session=session)
312
+
313
+ result = dividend.transform(data)
314
+
315
+ # Should have 3 unique rows, not 4
316
+ assert len(result) == 3
317
+
318
+
319
+ def test_stockdividend_transform_sorts_by_code_and_ann_date(sample_source_data):
320
+ """Test that output is sorted by code and ann_date"""
321
+ fake_conn = FakeConnection(frame=sample_source_data)
322
+ session = FakeSession(fake_conn)
323
+ dividend = StockDividend(session=session)
324
+
325
+ result = dividend.transform(sample_source_data)
326
+
327
+ # Check sorting: 000001.SZ first, then 600848.SH by dates
328
+ assert result.iloc[0]["code"] == "000001.SZ"
329
+ assert result.iloc[1]["code"] == "600848.SH"
330
+ assert result.iloc[1]["ann_date"] == "2020-04-10"
331
+ assert result.iloc[2]["code"] == "600848.SH"
332
+ assert result.iloc[2]["ann_date"] == "2021-04-15"
333
+
334
+
335
+ def test_stockdividend_transform_resets_index():
336
+ """Test that index is reset after transformation"""
337
+ data = pd.DataFrame(
338
+ {
339
+ "ts_code": ["600848.SH", "000001.SZ"],
340
+ "end_date": ["20201231", "20201231"],
341
+ "ann_date": ["20210415", "20210420"],
342
+ "div_proc": ["实施", "预案"],
343
+ "stk_div": ["0.10", "0.00"],
344
+ "cash_div": ["0.50", "0.30"],
345
+ "record_date": ["20210520", "20210525"],
346
+ "ex_date": ["20210521", "20210526"],
347
+ "pay_date": ["20210528", "20210601"],
348
+ "div_listdate": ["20210528", "20210601"],
349
+ "imp_ann_date": ["20210415", "20210420"],
350
+ "base_date": ["20201231", "20201231"],
351
+ },
352
+ index=[5, 10],
353
+ )
354
+
355
+ fake_conn = FakeConnection(frame=data)
356
+ session = FakeSession(fake_conn)
357
+ dividend = StockDividend(session=session)
358
+
359
+ result = dividend.transform(data)
360
+
361
+ assert result.index.tolist() == [0, 1]
362
+
363
+
364
+ def test_stockdividend_transform_only_target_columns(sample_source_data):
365
+ """Test that only target columns are in output"""
366
+ fake_conn = FakeConnection(frame=sample_source_data)
367
+ session = FakeSession(fake_conn)
368
+ dividend = StockDividend(session=session)
369
+
370
+ result = dividend.transform(sample_source_data)
371
+
372
+ expected_cols = set(TARGET.list_column_names())
373
+ actual_cols = set(result.columns)
374
+
375
+ assert actual_cols == expected_cols
376
+
377
+
378
+ def test_stockdividend_transform_all_date_fields(sample_source_data):
379
+ """Test that all date fields are properly transformed"""
380
+ fake_conn = FakeConnection(frame=sample_source_data)
381
+ session = FakeSession(fake_conn)
382
+ dividend = StockDividend(session=session)
383
+
384
+ result = dividend.transform(sample_source_data)
385
+
386
+ # Check that all date/datecode pairs exist
387
+ date_pairs = [
388
+ ("ann_date", "ann_datecode"),
389
+ ("record_date", "record_datecode"),
390
+ ("ex_date", "ex_datecode"),
391
+ ("pay_date", "pay_datecode"),
392
+ ("div_listdate", "div_listdatecode"),
393
+ ("imp_ann_date", "imp_ann_datecode"),
394
+ ("base_date", "base_datecode"),
395
+ ]
396
+
397
+ for date_col, datecode_col in date_pairs:
398
+ assert date_col in result.columns
399
+ assert datecode_col in result.columns
400
+
401
+
402
+ # ============================================================================
403
+ # Run Method Tests
404
+ # ============================================================================
405
+
406
+
407
+ def test_stockdividend_run_basic(sample_source_data):
408
+ """Test basic run() execution"""
409
+ fake_conn = FakeConnection(frame=sample_source_data)
410
+ session = FakeSession(fake_conn)
411
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
412
+
413
+ result = dividend.run()
414
+
415
+ assert isinstance(result, pd.DataFrame)
416
+ assert len(result) > 0
417
+
418
+
419
+ def test_stockdividend_run_with_cache_hit(sample_source_data):
420
+ """Test that run() returns cached data when available"""
421
+ fake_conn = FakeConnection(frame=sample_source_data)
422
+ session = FakeSession(fake_conn)
423
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"}, cache=True)
424
+
425
+ # First run should fetch and cache
426
+ result1 = dividend.run()
427
+
428
+ # Second run should return cached data
429
+ result2 = dividend.run()
430
+
431
+ pd.testing.assert_frame_equal(result1, result2)
432
+
433
+
434
+ def test_stockdividend_run_with_ann_date(sample_source_data):
435
+ """Test run() with ann_date parameter"""
436
+ fake_conn = FakeConnection(frame=sample_source_data)
437
+ session = FakeSession(fake_conn)
438
+ dividend = StockDividend(session=session, params={"ann_date": "20210415"})
439
+
440
+ result = dividend.run()
441
+
442
+ assert isinstance(result, pd.DataFrame)
443
+
444
+
445
+ def test_stockdividend_run_with_datetime_params(sample_source_data):
446
+ """Test run() with datetime objects as parameters"""
447
+ from datetime import datetime
448
+
449
+ fake_conn = FakeConnection(frame=sample_source_data)
450
+ session = FakeSession(fake_conn)
451
+ dividend = StockDividend(
452
+ session=session,
453
+ params={
454
+ "ts_code": "600848.SH",
455
+ "ann_date": datetime(2021, 4, 15),
456
+ },
457
+ )
458
+
459
+ result = dividend.run()
460
+
461
+ assert isinstance(result, pd.DataFrame)
462
+
463
+
464
+ def test_stockdividend_run_adds_fields_param(sample_source_data):
465
+ """Test that run() adds fields parameter if not provided"""
466
+ fake_conn = FakeConnection(frame=sample_source_data)
467
+ session = FakeSession(fake_conn)
468
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
469
+
470
+ # Monkey patch _fetchall to capture params
471
+ dividend._fetchall
472
+ captured_params = {}
473
+
474
+ def mock_fetchall(api, **kwargs):
475
+ captured_params.update(kwargs)
476
+ return sample_source_data
477
+
478
+ dividend._fetchall = mock_fetchall
479
+ dividend.run()
480
+
481
+ assert "fields" in captured_params
482
+ assert len(captured_params["fields"]) > 0
483
+
484
+
485
+ def test_stockdividend_run_sets_cache(sample_source_data):
486
+ """Test that run() saves result to cache"""
487
+ fake_conn = FakeConnection(frame=sample_source_data)
488
+ session = FakeSession(fake_conn)
489
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"}, cache=True)
490
+
491
+ result = dividend.run()
492
+
493
+ # Cache should be set after run
494
+ cached = dividend._load_cache()
495
+ assert cached is not None
496
+ pd.testing.assert_frame_equal(result, cached)
497
+
498
+
499
+ def test_stockdividend_run_calls_transform(sample_source_data):
500
+ """Test that run() calls transform method"""
501
+ fake_conn = FakeConnection(frame=sample_source_data)
502
+ session = FakeSession(fake_conn)
503
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
504
+
505
+ # Monkey patch transform to track if it was called
506
+ original_transform = dividend.transform
507
+ transform_called = {"called": False}
508
+
509
+ def mock_transform(data):
510
+ transform_called["called"] = True
511
+ return original_transform(data)
512
+
513
+ dividend.transform = mock_transform
514
+ dividend.run()
515
+
516
+ assert transform_called["called"] is True
517
+
518
+
519
+ def test_stockdividend_run_uses_dividend_api(sample_source_data):
520
+ """Test that run() uses dividend API"""
521
+ fake_conn = FakeConnection(frame=sample_source_data)
522
+ session = FakeSession(fake_conn)
523
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
524
+
525
+ # Monkey patch _fetchall to capture API
526
+ captured_api = {"api": None}
527
+
528
+ def mock_fetchall(api, **kwargs):
529
+ captured_api["api"] = api
530
+ return sample_source_data
531
+
532
+ dividend._fetchall = mock_fetchall
533
+ dividend.run()
534
+
535
+ assert captured_api["api"] == session.connection.dividend
536
+
537
+
538
+ # ============================================================================
539
+ # Integration Tests
540
+ # ============================================================================
541
+
542
+
543
+ def test_stockdividend_full_workflow(sample_source_data):
544
+ """Test complete workflow from initialization to output"""
545
+ fake_conn = FakeConnection(frame=sample_source_data)
546
+ session = FakeSession(fake_conn)
547
+
548
+ dividend = StockDividend(
549
+ session=session,
550
+ params={"ts_code": "600848.SH"},
551
+ cache=True,
552
+ )
553
+
554
+ result = dividend.run()
555
+
556
+ # Verify output structure
557
+ assert isinstance(result, pd.DataFrame)
558
+ assert len(result) == 3
559
+ assert "code" in result.columns
560
+ assert "ann_date" in result.columns
561
+ assert "div_proc" in result.columns
562
+ assert "stk_div" in result.columns
563
+
564
+ # Verify data types
565
+ assert pd.api.types.is_numeric_dtype(result["stk_div"])
566
+ assert pd.api.types.is_numeric_dtype(result["cash_div"])
567
+
568
+
569
+ def test_stockdividend_cache_persistence(sample_source_data):
570
+ """Test that cache persists across multiple runs"""
571
+ fake_conn = FakeConnection(frame=sample_source_data)
572
+ session = FakeSession(fake_conn)
573
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"}, cache=True)
574
+
575
+ # Run once to populate cache
576
+ result1 = dividend.run()
577
+
578
+ # Clear in-memory data to simulate fresh load
579
+ dividend2 = StockDividend(session=session, params={"ts_code": "600848.SH"}, cache=True)
580
+ result2 = dividend2.run()
581
+
582
+ pd.testing.assert_frame_equal(result1, result2)
583
+
584
+
585
+ def test_stockdividend_params_uniqueness(mock_session):
586
+ """Test that different params produce different cache keys"""
587
+ dividend1 = StockDividend(
588
+ session=mock_session,
589
+ params={"ts_code": "600848.SH"},
590
+ cache=True,
591
+ )
592
+ dividend2 = StockDividend(
593
+ session=mock_session,
594
+ params={"ts_code": "000001.SZ"},
595
+ cache=True,
596
+ )
597
+
598
+ # Test that different params are properly stored
599
+ assert dividend1.params.get("ts_code") == "600848.SH"
600
+ assert dividend2.params.get("ts_code") == "000001.SZ"
601
+ assert dividend1.params.get("ts_code") != dividend2.params.get("ts_code")
602
+
603
+
604
+ def test_stockdividend_empty_result_handling():
605
+ """Test handling of empty API results"""
606
+ empty_data = pd.DataFrame()
607
+ fake_conn = FakeConnection(frame=empty_data)
608
+ session = FakeSession(fake_conn)
609
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
610
+
611
+ result = dividend.run()
612
+
613
+ assert isinstance(result, pd.DataFrame)
614
+ assert result.empty
615
+ assert len(result.columns) > 0
616
+
617
+
618
+ def test_stockdividend_large_dataset_handling():
619
+ """Test handling of large datasets"""
620
+ # Create large dataset
621
+ large_data = pd.DataFrame(
622
+ {
623
+ "ts_code": ["600848.SH"] * 1000,
624
+ "end_date": ["20201231"] * 1000,
625
+ "ann_date": ["20210415"] * 1000,
626
+ "div_proc": ["实施"] * 1000,
627
+ "stk_div": ["0.10"] * 1000,
628
+ "cash_div": ["0.50"] * 1000,
629
+ "record_date": ["20210520"] * 1000,
630
+ "ex_date": ["20210521"] * 1000,
631
+ "pay_date": ["20210528"] * 1000,
632
+ "div_listdate": ["20210528"] * 1000,
633
+ "imp_ann_date": ["20210415"] * 1000,
634
+ "base_date": ["20201231"] * 1000,
635
+ }
636
+ )
637
+
638
+ fake_conn = FakeConnection(frame=large_data)
639
+ session = FakeSession(fake_conn)
640
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
641
+
642
+ result = dividend.run()
643
+
644
+ # Should deduplicate to 1 row
645
+ assert len(result) == 1
646
+
647
+
648
+ def test_stockdividend_without_cache(sample_source_data):
649
+ """Test that class works correctly without caching"""
650
+ fake_conn = FakeConnection(frame=sample_source_data)
651
+ session = FakeSession(fake_conn)
652
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"}, cache=False)
653
+
654
+ result = dividend.run()
655
+
656
+ assert isinstance(result, pd.DataFrame)
657
+ assert len(result) > 0
658
+ assert dividend.cache is None
659
+
660
+
661
+ def test_stockdividend_handles_missing_fields():
662
+ """Test that missing fields don't break transformation"""
663
+ # Data with only subset of fields
664
+ minimal_data = pd.DataFrame(
665
+ {
666
+ "ts_code": ["600848.SH"],
667
+ "end_date": ["20201231"],
668
+ "ann_date": ["20210415"],
669
+ "div_proc": ["实施"],
670
+ "stk_div": ["0.10"],
671
+ "cash_div": ["0.50"],
672
+ "record_date": ["20210520"],
673
+ "ex_date": ["20210521"],
674
+ }
675
+ )
676
+
677
+ fake_conn = FakeConnection(frame=minimal_data)
678
+ session = FakeSession(fake_conn)
679
+ dividend = StockDividend(session=session, params={"ts_code": "600848.SH"})
680
+
681
+ result = dividend.run()
682
+
683
+ # Should complete without error
684
+ assert len(result) == 1
685
+ # Missing fields should be NaN
686
+ assert pd.isna(result.iloc[0]["base_share"])
687
+
688
+
689
+ def test_stockdividend_api_doc_reference():
690
+ """Test that class correctly references API documentation"""
691
+ assert "doc_id=103" in StockDividend.__doc__
692
+
693
+
694
+ def test_stockdividend_crosssection_scale():
695
+ """Test that module is correctly configured as crosssection scale"""
696
+ assert SOURCE.meta["scale"] == "crosssection"
697
+ assert TARGET.meta["scale"] == "crosssection"
698
+
699
+
700
+ def test_stockdividend_multiple_stocks_handling(sample_source_data):
701
+ """Test handling of data with multiple stocks"""
702
+ fake_conn = FakeConnection(frame=sample_source_data)
703
+ session = FakeSession(fake_conn)
704
+ dividend = StockDividend(session=session, params={"ann_date": "20210415"})
705
+
706
+ result = dividend.run()
707
+
708
+ # Should have data for both stocks
709
+ assert len(result) == 3
710
+ assert "600848.SH" in result["code"].values
711
+ assert "000001.SZ" in result["code"].values
712
+
713
+
714
+ def test_stockdividend_handles_zero_values(sample_source_data):
715
+ """Test that zero values in numeric fields are handled correctly"""
716
+ fake_conn = FakeConnection(frame=sample_source_data)
717
+ session = FakeSession(fake_conn)
718
+ dividend = StockDividend(session=session)
719
+
720
+ result = dividend.transform(sample_source_data)
721
+
722
+ # Check that zero values are preserved (not treated as missing)
723
+ zero_div_rows = result[result["stk_div"] == 0.0]
724
+ assert len(zero_div_rows) == 1
725
+ assert zero_div_rows.iloc[0]["code"] == "000001.SZ"