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,551 @@
1
+ """
2
+ Test suite for CapflowTHS class
3
+ Tests cover initialization, data fetching, transformation, date handling, and utility methods
4
+ """
5
+
6
+ from datetime import date, datetime
7
+ from unittest.mock import MagicMock, patch
8
+
9
+ import pandas as pd
10
+ import pytest
11
+
12
+ from xfintech.data.common.cache import Cache
13
+ from xfintech.data.common.coolant import Coolant
14
+ from xfintech.data.common.retry import Retry
15
+ from xfintech.data.source.tushare.session.session import Session
16
+ from xfintech.data.source.tushare.stock.capflowths.capflowths import CapflowTHS
17
+ from xfintech.data.source.tushare.stock.capflowths.constant import (
18
+ KEY,
19
+ NAME,
20
+ SOURCE,
21
+ TARGET,
22
+ )
23
+
24
+ # Fixtures
25
+
26
+
27
+ @pytest.fixture
28
+ def mock_session():
29
+ """Create a mock Tushare session"""
30
+ session = MagicMock(spec=Session)
31
+ session._credential = "test_token"
32
+ session.id = "test1234"
33
+ session.mode = "direct"
34
+ session.relay_url = None
35
+ session.relay_secret = None
36
+ session.connected = True
37
+
38
+ # Mock the connection object
39
+ mock_connection = MagicMock()
40
+ mock_connection.moneyflow_ths = MagicMock()
41
+ session.connection = mock_connection
42
+
43
+ return session
44
+
45
+
46
+ @pytest.fixture
47
+ def sample_source_data():
48
+ """Create sample source data in Tushare format"""
49
+ return pd.DataFrame(
50
+ {
51
+ "trade_date": ["20241011", "20241010", "20241009"],
52
+ "ts_code": ["000001.SZ", "000001.SZ", "000002.SZ"],
53
+ "name": ["平安银行", "平安银行", "万科A"],
54
+ "pct_change": [2.47, 1.22, 3.15],
55
+ "latest": [15.83, 15.45, 8.92],
56
+ "net_amount": [12589.45, 8234.67, -5432.11],
57
+ "net_d5_amount": [45632.89, 42123.44, -15234.67],
58
+ "buy_lg_amount": [8500.23, 6200.45, -3200.55],
59
+ "buy_lg_amount_rate": [4.25, 3.87, -2.15],
60
+ "buy_md_amount": [2800.12, 1500.22, -1500.33],
61
+ "buy_md_amount_rate": [1.40, 0.94, -1.01],
62
+ "buy_sm_amount": [1289.10, 534.00, -731.23],
63
+ "buy_sm_amount_rate": [0.64, 0.33, -0.49],
64
+ }
65
+ )
66
+
67
+
68
+ # Initialization Tests
69
+
70
+
71
+ class TestInitialization:
72
+ """Test initialization and configuration"""
73
+
74
+ def test_init_basic(self, mock_session):
75
+ """Test basic initialization"""
76
+ job = CapflowTHS(session=mock_session)
77
+
78
+ assert job.name == NAME
79
+ assert job.key == KEY
80
+ assert job.source == SOURCE
81
+ assert job.target == TARGET
82
+
83
+ def test_init_with_params(self, mock_session):
84
+ """Test initialization with params"""
85
+ params = {"ts_code": "000001.SZ", "start_date": "20240101"}
86
+ job = CapflowTHS(session=mock_session, params=params)
87
+
88
+ assert job.params.ts_code == "000001.SZ"
89
+ assert job.params.start_date == "20240101"
90
+
91
+ def test_init_with_all_components(self, mock_session):
92
+ """Test initialization with all components"""
93
+ params = {"ts_code": "000001.SZ"}
94
+ coolant = Coolant(interval=0.2)
95
+ retry = Retry(retry=3)
96
+ cache = Cache(path="/tmp/test_cache")
97
+
98
+ job = CapflowTHS(
99
+ session=mock_session,
100
+ params=params,
101
+ coolant=coolant,
102
+ retry=retry,
103
+ cache=cache,
104
+ )
105
+
106
+ assert job.params.ts_code == "000001.SZ"
107
+ assert job.coolant.interval == 0.2
108
+ assert job.retry.retry == 3
109
+ assert job.cache is not None
110
+ assert isinstance(job.cache, Cache)
111
+
112
+ def test_source_schema(self):
113
+ """Test source schema has all required columns"""
114
+ assert SOURCE is not None
115
+ assert SOURCE.desc == "同花顺个股资金流向数据(Tushare格式)"
116
+
117
+ column_names = SOURCE.columns
118
+ assert "ts_code" in column_names
119
+ assert "trade_date" in column_names
120
+ assert "name" in column_names
121
+ assert "pct_change" in column_names
122
+ assert "latest" in column_names
123
+ assert "net_amount" in column_names
124
+ assert "buy_lg_amount" in column_names
125
+
126
+ def test_target_schema(self):
127
+ """Test target schema has all required columns"""
128
+ assert TARGET is not None
129
+ assert TARGET.desc == "同花顺个股资金流向数据(xfintech标准格式)"
130
+
131
+ column_names = TARGET.columns
132
+ assert "code" in column_names
133
+ assert "date" in column_names
134
+ assert "datecode" in column_names
135
+ assert "name" in column_names
136
+ assert "percent_change" in column_names
137
+ assert "latest" in column_names
138
+ assert "net_amount" in column_names
139
+
140
+
141
+ # Transform Tests
142
+
143
+
144
+ class TestTransform:
145
+ """Test data transformation"""
146
+
147
+ def test_transform_basic(self, mock_session, sample_source_data):
148
+ """Test basic data transformation"""
149
+ job = CapflowTHS(session=mock_session)
150
+ result = job.transform(sample_source_data)
151
+
152
+ assert len(result) == 3
153
+ assert "code" in result.columns
154
+ assert "date" in result.columns
155
+ assert "datecode" in result.columns
156
+ # Data is sorted by code, so first row is 000001.SZ
157
+ assert result.iloc[0]["code"] == "000001.SZ"
158
+ assert result.iloc[2]["code"] == "000002.SZ"
159
+
160
+ def test_transform_date_conversion(self, mock_session, sample_source_data):
161
+ """Test date field conversions"""
162
+ job = CapflowTHS(session=mock_session)
163
+ result = job.transform(sample_source_data)
164
+
165
+ # Check date format (YYYY-MM-DD) - sorted by code and date
166
+ assert result.iloc[0]["date"] == "2024-10-10" # 000001.SZ earliest
167
+ assert result.iloc[1]["date"] == "2024-10-11" # 000001.SZ latest
168
+ assert result.iloc[2]["date"] == "2024-10-09" # 000002.SZ
169
+
170
+ # Check datecode format (YYYYMMDD)
171
+ assert result.iloc[1]["datecode"] == "20241011"
172
+
173
+ def test_transform_field_mappings(self, mock_session, sample_source_data):
174
+ """Test field mapping transformations"""
175
+ job = CapflowTHS(session=mock_session)
176
+ result = job.transform(sample_source_data)
177
+
178
+ # Use second row (000001.SZ, 20241011) after sorting
179
+ row = result.iloc[1]
180
+ assert row["code"] == "000001.SZ"
181
+ assert row["name"] == "平安银行"
182
+ assert row["percent_change"] == 2.47
183
+ assert row["latest"] == 15.83
184
+
185
+ def test_transform_numeric_fields(self, mock_session, sample_source_data):
186
+ """Test numeric field transformations"""
187
+ job = CapflowTHS(session=mock_session)
188
+ result = job.transform(sample_source_data)
189
+
190
+ row = result.iloc[0]
191
+ # Check all numeric fields are properly converted
192
+ assert pd.notna(row["latest"])
193
+ assert pd.notna(row["percent_change"])
194
+ assert pd.notna(row["net_amount"])
195
+ assert pd.notna(row["net_d5_amount"])
196
+ assert pd.notna(row["buy_lg_amount"])
197
+ assert pd.notna(row["buy_lg_amount_rate"])
198
+
199
+ def test_transform_empty_data(self, mock_session):
200
+ """Test transform with empty data"""
201
+ job = CapflowTHS(session=mock_session)
202
+
203
+ # Test with None
204
+ result = job.transform(None)
205
+ assert result.empty
206
+ assert len(result.columns) == len(TARGET.columns)
207
+
208
+ # Test with empty DataFrame
209
+ empty_df = pd.DataFrame()
210
+ result = job.transform(empty_df)
211
+ assert result.empty
212
+ assert len(result.columns) == len(TARGET.columns)
213
+
214
+ def test_transform_none_data(self, mock_session):
215
+ """Test transform with None data"""
216
+ job = CapflowTHS(session=mock_session)
217
+ result = job.transform(None)
218
+
219
+ assert result.empty
220
+ assert list(result.columns) == TARGET.list_column_names()
221
+
222
+ def test_transform_invalid_data(self, mock_session):
223
+ """Test transform with invalid numeric values"""
224
+ data = pd.DataFrame(
225
+ {
226
+ "trade_date": ["20241011", "invalid_date"],
227
+ "ts_code": ["000001.SZ", "000002.SZ"],
228
+ "name": ["平安银行", "万科A"],
229
+ "pct_change": [2.47, "invalid"],
230
+ "latest": [15.83, 8.92],
231
+ "net_amount": [12589.45, -5432.11],
232
+ "net_d5_amount": [45632.89, -15234.67],
233
+ "buy_lg_amount": [8500.23, -3200.55],
234
+ "buy_lg_amount_rate": [4.25, -2.15],
235
+ "buy_md_amount": [2800.12, -1500.33],
236
+ "buy_md_amount_rate": [1.40, -1.01],
237
+ "buy_sm_amount": [1289.10, -731.23],
238
+ "buy_sm_amount_rate": [0.64, -0.49],
239
+ }
240
+ )
241
+ job = CapflowTHS(session=mock_session)
242
+ result = job.transform(data)
243
+
244
+ # Should handle invalid data gracefully
245
+ assert len(result) == 2
246
+ assert pd.isna(result.iloc[1]["date"]) # Invalid date
247
+ assert pd.isna(result.iloc[1]["percent_change"]) # Invalid numeric
248
+
249
+ def test_transform_duplicates_removed(self, mock_session):
250
+ """Test that duplicates are removed"""
251
+ data = pd.DataFrame(
252
+ {
253
+ "trade_date": ["20241011", "20241011", "20241010"],
254
+ "ts_code": ["000001.SZ", "000001.SZ", "000002.SZ"],
255
+ "name": ["平安银行", "平安银行", "万科A"],
256
+ "pct_change": [2.47, 2.47, 1.22],
257
+ "latest": [15.83, 15.83, 8.92],
258
+ "net_amount": [12589.45, 12589.45, -5432.11],
259
+ "net_d5_amount": [45632.89, 45632.89, -15234.67],
260
+ "buy_lg_amount": [8500.23, 8500.23, -3200.55],
261
+ "buy_lg_amount_rate": [4.25, 4.25, -2.15],
262
+ "buy_md_amount": [2800.12, 2800.12, -1500.33],
263
+ "buy_md_amount_rate": [1.40, 1.40, -1.01],
264
+ "buy_sm_amount": [1289.10, 1289.10, -731.23],
265
+ "buy_sm_amount_rate": [0.64, 0.64, -0.49],
266
+ }
267
+ )
268
+ job = CapflowTHS(session=mock_session)
269
+ result = job.transform(data)
270
+
271
+ # Duplicates should be removed
272
+ assert len(result) == 2
273
+
274
+ def test_transform_sorting(self, mock_session):
275
+ """Test that result is sorted by code and date"""
276
+ data = pd.DataFrame(
277
+ {
278
+ "trade_date": ["20241011", "20241009", "20241010"],
279
+ "ts_code": ["000002.SZ", "000001.SZ", "000001.SZ"],
280
+ "name": ["万科A", "平安银行", "平安银行"],
281
+ "pct_change": [3.15, 1.22, 2.47],
282
+ "latest": [8.92, 15.45, 15.83],
283
+ "net_amount": [-5432.11, 8234.67, 12589.45],
284
+ "net_d5_amount": [-15234.67, 42123.44, 45632.89],
285
+ "buy_lg_amount": [-3200.55, 6200.45, 8500.23],
286
+ "buy_lg_amount_rate": [-2.15, 3.87, 4.25],
287
+ "buy_md_amount": [-1500.33, 1500.22, 2800.12],
288
+ "buy_md_amount_rate": [-1.01, 0.94, 1.40],
289
+ "buy_sm_amount": [-731.23, 534.00, 1289.10],
290
+ "buy_sm_amount_rate": [-0.49, 0.33, 0.64],
291
+ }
292
+ )
293
+ job = CapflowTHS(session=mock_session)
294
+ result = job.transform(data)
295
+
296
+ # Should be sorted by code, then date
297
+ expected_order = ["000001.SZ", "000001.SZ", "000002.SZ"]
298
+ actual_order = result["code"].tolist()
299
+ assert actual_order == expected_order
300
+
301
+ # Check date ordering for 000001.SZ
302
+ assert result.iloc[0]["date"] == "2024-10-09" # Earlier date first
303
+ assert result.iloc[1]["date"] == "2024-10-10"
304
+
305
+
306
+ # Run Tests
307
+
308
+
309
+ class TestRun:
310
+ """Test execution logic"""
311
+
312
+ def test_run_basic(self, mock_session, sample_source_data):
313
+ """Test basic run method"""
314
+ job = CapflowTHS(session=mock_session)
315
+
316
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
317
+ result = job.run()
318
+
319
+ assert isinstance(result, pd.DataFrame)
320
+ assert len(result) == 3
321
+ assert "code" in result.columns
322
+ assert "date" in result.columns
323
+
324
+ def test_run_with_params(self, mock_session, sample_source_data):
325
+ """Test run with ts_code parameter"""
326
+ filtered_data = sample_source_data[sample_source_data["ts_code"] == "000001.SZ"]
327
+
328
+ job = CapflowTHS(session=mock_session, params={"ts_code": "000001.SZ"})
329
+
330
+ with patch.object(job, "_fetchall", return_value=filtered_data):
331
+ result = job.run()
332
+
333
+ assert len(result) == 2
334
+ assert all(result["code"] == "000001.SZ")
335
+
336
+ def test_run_with_date_string(self, mock_session, sample_source_data):
337
+ """Test run with trade_date as string"""
338
+ job = CapflowTHS(session=mock_session, params={"trade_date": "20241011"})
339
+
340
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
341
+ job.run()
342
+
343
+ call_kwargs = mock_fetchall.call_args[1]
344
+ assert call_kwargs["trade_date"] == "20241011"
345
+
346
+ def test_run_with_date_datetime(self, mock_session, sample_source_data):
347
+ """Test run with trade_date as datetime object"""
348
+ trade_date = datetime(2024, 10, 11)
349
+ job = CapflowTHS(session=mock_session, params={"trade_date": trade_date})
350
+
351
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
352
+ job.run()
353
+
354
+ call_kwargs = mock_fetchall.call_args[1]
355
+ assert call_kwargs["trade_date"] == "20241011"
356
+
357
+ def test_run_with_date_date(self, mock_session, sample_source_data):
358
+ """Test run with trade_date as date object (not datetime)"""
359
+ trade_date = date(2024, 10, 11)
360
+ job = CapflowTHS(session=mock_session, params={"trade_date": trade_date})
361
+
362
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
363
+ job.run()
364
+
365
+ call_kwargs = mock_fetchall.call_args[1]
366
+ assert call_kwargs["trade_date"] == "20241011"
367
+
368
+ def test_run_with_date_range_string(self, mock_session, sample_source_data):
369
+ """Test run with start_date and end_date as strings"""
370
+ job = CapflowTHS(
371
+ session=mock_session,
372
+ params={"start_date": "20241001", "end_date": "20241031"},
373
+ )
374
+
375
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
376
+ job.run()
377
+
378
+ call_kwargs = mock_fetchall.call_args[1]
379
+ assert call_kwargs["start_date"] == "20241001"
380
+ assert call_kwargs["end_date"] == "20241031"
381
+
382
+ def test_run_with_date_range_datetime(self, mock_session, sample_source_data):
383
+ """Test run with start_date and end_date as datetime objects"""
384
+ job = CapflowTHS(
385
+ session=mock_session,
386
+ params={
387
+ "start_date": datetime(2024, 10, 1),
388
+ "end_date": datetime(2024, 10, 31),
389
+ },
390
+ )
391
+
392
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
393
+ job.run()
394
+
395
+ call_kwargs = mock_fetchall.call_args[1]
396
+ assert call_kwargs["start_date"] == "20241001"
397
+ assert call_kwargs["end_date"] == "20241031"
398
+
399
+ def test_run_calls_transform(self, mock_session, sample_source_data):
400
+ """Test that run calls transform"""
401
+ job = CapflowTHS(session=mock_session)
402
+
403
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
404
+ with patch.object(job, "transform", wraps=job.transform) as mock_transform:
405
+ job.run()
406
+
407
+ mock_transform.assert_called_once()
408
+
409
+ def test_run_with_multiple_params(self, mock_session, sample_source_data):
410
+ """Test run with both ts_code and date range"""
411
+ job = CapflowTHS(
412
+ session=mock_session,
413
+ params={
414
+ "ts_code": "000001.SZ",
415
+ "start_date": "20241001",
416
+ "end_date": "20241031",
417
+ },
418
+ )
419
+
420
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
421
+ job.run()
422
+ call_kwargs = mock_fetchall.call_args[1]
423
+ assert call_kwargs["ts_code"] == "000001.SZ"
424
+ assert call_kwargs["start_date"] == "20241001"
425
+ assert call_kwargs["end_date"] == "20241031"
426
+
427
+
428
+ # Cache Tests
429
+
430
+
431
+ class TestCache:
432
+ """Test caching behavior"""
433
+
434
+ def test_cache_persistence(self, mock_session, sample_source_data):
435
+ """Test that cache persists across runs"""
436
+ job = CapflowTHS(session=mock_session, cache=True)
437
+
438
+ with patch.object(job, "_load_cache", return_value=None) as mock_load:
439
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
440
+ # First run - fetches data and caches it
441
+ result1 = job.run()
442
+ assert mock_fetchall.call_count == 1
443
+ assert mock_load.call_count == 1
444
+
445
+ # Second run - _load_cache still returns None, so _fetchall called again
446
+ result2 = job.run()
447
+ assert mock_fetchall.call_count == 2
448
+ assert mock_load.call_count == 2
449
+
450
+ pd.testing.assert_frame_equal(result1, result2)
451
+
452
+ def test_run_without_cache(self, mock_session, sample_source_data):
453
+ """Test that thscapflow works correctly without cache"""
454
+ job = CapflowTHS(session=mock_session, cache=False)
455
+
456
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
457
+ job.run()
458
+ job.run()
459
+
460
+ # Should fetch twice (no caching)
461
+ assert mock_fetchall.call_count == 2
462
+
463
+ def test_params_identifier_uniqueness(self, mock_session):
464
+ """Test that different params create different cache keys"""
465
+ job1 = CapflowTHS(session=mock_session, params={"trade_date": "20241011"}, cache=True)
466
+ job2 = CapflowTHS(session=mock_session, params={"trade_date": "20241010"}, cache=True)
467
+
468
+ assert job1.params.identifier != job2.params.identifier
469
+
470
+
471
+ # Integration Tests
472
+
473
+
474
+ class TestIntegration:
475
+ """Test end-to-end workflows"""
476
+
477
+ def test_full_workflow(self, mock_session, sample_source_data):
478
+ """Test complete workflow from initialization to data retrieval"""
479
+ job = CapflowTHS(
480
+ session=mock_session,
481
+ params={
482
+ "ts_code": "000001.SZ",
483
+ "start_date": "20241001",
484
+ "end_date": "20241031",
485
+ },
486
+ cache=False,
487
+ )
488
+
489
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
490
+ result = job.run()
491
+
492
+ assert len(result) > 0
493
+ assert "code" in result.columns
494
+ assert "date" in result.columns
495
+
496
+ def test_large_dataset_handling(self, mock_session):
497
+ """Test handling of large datasets"""
498
+ # Create large dataset
499
+ large_data = pd.DataFrame(
500
+ {
501
+ "trade_date": ["20241011"] * 1000,
502
+ "ts_code": [f"{str(i).zfill(6)}.SZ" for i in range(1, 1001)],
503
+ "name": ["股票名称"] * 1000,
504
+ "pct_change": [2.50] * 1000,
505
+ "latest": [10.00] * 1000,
506
+ "net_amount": [5000.00] * 1000,
507
+ "net_d5_amount": [25000.00] * 1000,
508
+ "buy_lg_amount": [3000.00] * 1000,
509
+ "buy_lg_amount_rate": [2.00] * 1000,
510
+ "buy_md_amount": [1500.00] * 1000,
511
+ "buy_md_amount_rate": [1.00] * 1000,
512
+ "buy_sm_amount": [500.00] * 1000,
513
+ "buy_sm_amount_rate": [0.33] * 1000,
514
+ }
515
+ )
516
+
517
+ job = CapflowTHS(session=mock_session, cache=False)
518
+
519
+ with patch.object(job, "_fetchall", return_value=large_data):
520
+ result = job.run()
521
+
522
+ assert len(result) == 1000
523
+
524
+ def test_missing_fields_handling(self, mock_session):
525
+ """Test handling of data with some missing fields"""
526
+ data = pd.DataFrame(
527
+ {
528
+ "trade_date": ["20241011"],
529
+ "ts_code": ["000001.SZ"],
530
+ "name": ["平安银行"],
531
+ "pct_change": [None], # Missing data
532
+ "latest": [15.83],
533
+ "net_amount": [12589.45],
534
+ "net_d5_amount": [None], # Missing data
535
+ "buy_lg_amount": [8500.23],
536
+ "buy_lg_amount_rate": [4.25],
537
+ "buy_md_amount": [2800.12],
538
+ "buy_md_amount_rate": [1.40],
539
+ "buy_sm_amount": [1289.10],
540
+ "buy_sm_amount_rate": [0.64],
541
+ }
542
+ )
543
+
544
+ job = CapflowTHS(session=mock_session, cache=False)
545
+
546
+ with patch.object(job, "_fetchall", return_value=data):
547
+ result = job.run()
548
+
549
+ assert len(result) == 1
550
+ assert pd.isna(result.iloc[0]["percent_change"])
551
+ assert pd.isna(result.iloc[0]["net_d5_amount"])
@@ -0,0 +1,19 @@
1
+ from __future__ import annotations
2
+
3
+ from xfintech.data.source.tushare.stock.company.company import Company
4
+ from xfintech.data.source.tushare.stock.company.constant import (
5
+ KEY,
6
+ NAME,
7
+ PAGINATE,
8
+ SOURCE,
9
+ TARGET,
10
+ )
11
+
12
+ __all__ = [
13
+ "Company",
14
+ "KEY",
15
+ "NAME",
16
+ "PAGINATE",
17
+ "SOURCE",
18
+ "TARGET",
19
+ ]