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,547 @@
1
+ from datetime import date, datetime
2
+ from unittest.mock import Mock
3
+
4
+ import pandas as pd
5
+ import pytest
6
+
7
+ from xfintech.data.common.cache import Cache
8
+ from xfintech.data.common.coolant import Coolant
9
+ from xfintech.data.common.paginate import Paginate
10
+ from xfintech.data.common.params import Params
11
+ from xfintech.data.common.retry import Retry
12
+ from xfintech.data.source.baostock.job.job import BaostockJob
13
+ from xfintech.data.source.baostock.session.session import Session
14
+
15
+ # ============================================================================
16
+ # Helper Classes for Testing
17
+ # ============================================================================
18
+
19
+
20
+ class ConcreteBaostockJob(BaostockJob):
21
+ """Concrete implementation for testing"""
22
+
23
+ def _run(self) -> pd.DataFrame:
24
+ return pd.DataFrame({"test": [1, 2, 3]})
25
+
26
+
27
+ class FetchAllJob(BaostockJob):
28
+ """Job that uses _fetchall in _run"""
29
+
30
+ def _run(self) -> pd.DataFrame:
31
+ api = Mock(return_value=pd.DataFrame({"data": [1, 2, 3]}))
32
+ return self._fetchall(api, code="sh.600000")
33
+
34
+
35
+ # ============================================================================
36
+ # Initialization Tests
37
+ # ============================================================================
38
+
39
+
40
+ def test_baostockjob_init_basic():
41
+ """Test BaostockJob basic initialization"""
42
+ mock_session = Mock(spec=Session)
43
+ mock_session.connection = Mock()
44
+
45
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
46
+
47
+ assert job.name == "test_job"
48
+ assert job.key == "test_key"
49
+ assert job.connection is not None
50
+ assert isinstance(job.params, Params)
51
+ assert isinstance(job.coolant, Coolant)
52
+ assert isinstance(job.paginate, Paginate)
53
+ assert isinstance(job.retry, Retry)
54
+
55
+
56
+ def test_baostockjob_init_with_params():
57
+ """Test BaostockJob initialization with params dict"""
58
+ mock_session = Mock(spec=Session)
59
+ mock_session.connection = Mock()
60
+
61
+ job = ConcreteBaostockJob(
62
+ name="test_job", key="test_key", session=mock_session, params={"code": "sh.600000", "start_date": "2024-01-01"}
63
+ )
64
+
65
+ assert job.params.to_dict()["code"] == "sh.600000"
66
+ assert job.params.to_dict()["start_date"] == "2024-01-01"
67
+
68
+
69
+ def test_baostockjob_init_with_params_object():
70
+ """Test BaostockJob initialization with Params object"""
71
+ mock_session = Mock(spec=Session)
72
+ mock_session.connection = Mock()
73
+ params = Params(code="sh.600000", frequency="5")
74
+
75
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, params=params)
76
+
77
+ assert job.params is params
78
+
79
+
80
+ def test_baostockjob_init_with_coolant_dict():
81
+ """Test BaostockJob initialization with coolant dict"""
82
+ mock_session = Mock(spec=Session)
83
+ mock_session.connection = Mock()
84
+
85
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, coolant={"wait": 0.5})
86
+
87
+ # Coolant stores wait time, not interval
88
+ assert isinstance(job.coolant, Coolant)
89
+
90
+
91
+ def test_baostockjob_init_with_paginate_dict():
92
+ """Test BaostockJob initialization with paginate dict"""
93
+ mock_session = Mock(spec=Session)
94
+ mock_session.connection = Mock()
95
+
96
+ job = ConcreteBaostockJob(
97
+ name="test_job", key="test_key", session=mock_session, paginate={"pagesize": 100, "pagelimit": 1000}
98
+ )
99
+
100
+ assert job.paginate.pagesize == 100
101
+ assert job.paginate.pagelimit == 1000
102
+
103
+
104
+ def test_baostockjob_init_with_retry_dict():
105
+ """Test BaostockJob initialization with retry dict"""
106
+ mock_session = Mock(spec=Session)
107
+ mock_session.connection = Mock()
108
+
109
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, retry={"retry": 3, "wait": 1.0})
110
+
111
+ assert job.retry.retry == 3
112
+ assert job.retry.wait == 1.0
113
+
114
+
115
+ def test_baostockjob_init_with_cache_true():
116
+ """Test BaostockJob initialization with cache enabled"""
117
+ mock_session = Mock(spec=Session)
118
+ mock_session.connection = Mock()
119
+
120
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=True)
121
+
122
+ assert job.cache is not None
123
+ assert isinstance(job.cache, Cache)
124
+
125
+
126
+ def test_baostockjob_init_with_cache_false():
127
+ """Test BaostockJob initialization with cache disabled"""
128
+ mock_session = Mock(spec=Session)
129
+ mock_session.connection = Mock()
130
+
131
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=False)
132
+
133
+ assert job.cache is None
134
+
135
+
136
+ def test_baostockjob_init_marks_checkpoints():
137
+ """Test BaostockJob marks initialization checkpoints"""
138
+ mock_session = Mock(spec=Session)
139
+ mock_session.connection = Mock()
140
+
141
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
142
+
143
+ # Should have marked _resolve_connection[OK]
144
+ marks = job.metric.marks
145
+ assert "_resolve_connection[OK]" in marks
146
+
147
+
148
+ # ============================================================================
149
+ # Connection Resolution Tests
150
+ # ============================================================================
151
+
152
+
153
+ def test_resolve_connection_success():
154
+ """Test successful connection resolution"""
155
+ mock_session = Mock(spec=Session)
156
+ mock_connection = Mock()
157
+ mock_session.connection = mock_connection
158
+
159
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
160
+
161
+ assert job.connection is mock_connection
162
+
163
+
164
+ def test_resolve_connection_no_connection():
165
+ """Test connection resolution when session has no connection"""
166
+ mock_session = Mock(spec=Session)
167
+ mock_session.connection = None
168
+
169
+ with pytest.raises(ConnectionError, match="No active connection found"):
170
+ ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
171
+
172
+
173
+ # ============================================================================
174
+ # Date Parsing Tests
175
+ # ============================================================================
176
+
177
+
178
+ def test_parse_date_params_with_date_object():
179
+ """Test _parse_date_params with date object"""
180
+ mock_session = Mock(spec=Session)
181
+ mock_session.connection = Mock()
182
+
183
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
184
+
185
+ payload = {"start_date": date(2024, 1, 1), "end_date": date(2024, 12, 31)}
186
+ result = job._parse_date_params(payload, ["start_date", "end_date"])
187
+
188
+ assert result["start_date"] == "2024-01-01"
189
+ assert result["end_date"] == "2024-12-31"
190
+
191
+
192
+ def test_parse_date_params_with_datetime_object():
193
+ """Test _parse_date_params with datetime object"""
194
+ mock_session = Mock(spec=Session)
195
+ mock_session.connection = Mock()
196
+
197
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
198
+
199
+ payload = {"start_date": datetime(2024, 1, 1, 10, 30), "end_date": datetime(2024, 12, 31, 15, 45)}
200
+ result = job._parse_date_params(payload, ["start_date", "end_date"])
201
+
202
+ assert result["start_date"] == "2024-01-01"
203
+ assert result["end_date"] == "2024-12-31"
204
+
205
+
206
+ def test_parse_date_params_with_string_hyphen():
207
+ """Test _parse_date_params with string in YYYY-MM-DD format"""
208
+ mock_session = Mock(spec=Session)
209
+ mock_session.connection = Mock()
210
+
211
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
212
+
213
+ payload = {"start_date": "2024-01-01", "end_date": "2024-12-31"}
214
+ result = job._parse_date_params(payload, ["start_date", "end_date"])
215
+
216
+ assert result["start_date"] == "2024-01-01"
217
+ assert result["end_date"] == "2024-12-31"
218
+
219
+
220
+ def test_parse_date_params_with_string_yyyymmdd():
221
+ """Test _parse_date_params with string in YYYYMMDD format"""
222
+ mock_session = Mock(spec=Session)
223
+ mock_session.connection = Mock()
224
+
225
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
226
+
227
+ payload = {"start_date": "20240101", "end_date": "20241231"}
228
+ result = job._parse_date_params(payload, ["start_date", "end_date"])
229
+
230
+ assert result["start_date"] == "2024-01-01"
231
+ assert result["end_date"] == "2024-12-31"
232
+
233
+
234
+ def test_parse_date_params_preserves_other_keys():
235
+ """Test _parse_date_params preserves non-date keys"""
236
+ mock_session = Mock(spec=Session)
237
+ mock_session.connection = Mock()
238
+
239
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
240
+
241
+ payload = {"start_date": "20240101", "code": "sh.600000", "frequency": "5"}
242
+ result = job._parse_date_params(payload, ["start_date"])
243
+
244
+ assert result["start_date"] == "2024-01-01"
245
+ assert result["code"] == "sh.600000"
246
+ assert result["frequency"] == "5"
247
+
248
+
249
+ # ============================================================================
250
+ # String Parsing Tests
251
+ # ============================================================================
252
+
253
+
254
+ def test_parse_string_params_basic():
255
+ """Test _parse_string_params with string values"""
256
+ mock_session = Mock(spec=Session)
257
+ mock_session.connection = Mock()
258
+
259
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
260
+
261
+ payload = {"code": "sh.600000", "frequency": "5", "adjustflag": "3"}
262
+ result = job._parse_string_params(payload, ["code", "frequency"])
263
+
264
+ assert result["code"] == "sh.600000"
265
+ assert result["frequency"] == "5"
266
+
267
+
268
+ def test_parse_string_params_preserves_other_types():
269
+ """Test _parse_string_params preserves non-string types"""
270
+ mock_session = Mock(spec=Session)
271
+ mock_session.connection = Mock()
272
+
273
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
274
+
275
+ payload = {"code": "sh.600000", "pagesize": 100, "enabled": True}
276
+ result = job._parse_string_params(payload, ["code"])
277
+
278
+ assert result["code"] == "sh.600000"
279
+ assert result["pagesize"] == 100
280
+ assert result["enabled"] is True
281
+
282
+
283
+ # ============================================================================
284
+ # _fetchall Tests - Direct Mode
285
+ # ============================================================================
286
+
287
+
288
+ def test_fetchall_direct_mode_success():
289
+ """Test _fetchall in direct mode with successful response"""
290
+ mock_session = Mock(spec=Session)
291
+ mock_session.connection = Mock()
292
+
293
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
294
+
295
+ # Mock ResultSet
296
+ mock_rs = Mock()
297
+ mock_rs.error_code = "0"
298
+ mock_rs.get_data.return_value = pd.DataFrame({"date": ["2024-01-01"], "close": [100.0]})
299
+
300
+ # Mock API that returns ResultSet
301
+ mock_api = Mock(return_value=mock_rs)
302
+
303
+ result = job._fetchall(mock_api, code="sh.600000")
304
+
305
+ assert isinstance(result, pd.DataFrame)
306
+ assert len(result) == 1
307
+ assert "date" in result.columns
308
+ assert "_fetchall[direct_mode" in str(job.metric.marks)
309
+
310
+
311
+ def test_fetchall_direct_mode_error():
312
+ """Test _fetchall in direct mode with error response"""
313
+ mock_session = Mock(spec=Session)
314
+ mock_session.connection = Mock()
315
+
316
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
317
+
318
+ # Mock ResultSet with error
319
+ mock_rs = Mock()
320
+ mock_rs.error_code = "10001001"
321
+ mock_rs.error_msg = "User not logged in"
322
+
323
+ # Mock API that returns ResultSet
324
+ mock_api = Mock(return_value=mock_rs)
325
+
326
+ result = job._fetchall(mock_api, code="sh.600000")
327
+
328
+ assert isinstance(result, pd.DataFrame)
329
+ assert result.empty
330
+ assert "_fetchall[ERROR" in str(job.metric.marks)
331
+
332
+
333
+ def test_fetchall_direct_mode_empty_data():
334
+ """Test _fetchall in direct mode with empty data"""
335
+ mock_session = Mock(spec=Session)
336
+ mock_session.connection = Mock()
337
+
338
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
339
+
340
+ # Mock ResultSet with empty data
341
+ mock_rs = Mock()
342
+ mock_rs.error_code = "0"
343
+ mock_rs.get_data.return_value = pd.DataFrame()
344
+
345
+ # Mock API that returns ResultSet
346
+ mock_api = Mock(return_value=mock_rs)
347
+
348
+ result = job._fetchall(mock_api, code="sh.600000")
349
+
350
+ assert isinstance(result, pd.DataFrame)
351
+ assert result.empty
352
+
353
+
354
+ # ============================================================================
355
+ # _fetchall Tests - Relay Mode
356
+ # ============================================================================
357
+
358
+
359
+ def test_fetchall_relay_mode_success():
360
+ """Test _fetchall in relay mode (returns DataFrame directly)"""
361
+ mock_session = Mock(spec=Session)
362
+ mock_session.connection = Mock()
363
+
364
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
365
+
366
+ # Mock API that returns DataFrame (relay mode)
367
+ expected_df = pd.DataFrame({"date": ["2024-01-01", "2024-01-02"], "close": [100.0, 101.0]})
368
+ mock_api = Mock(return_value=expected_df)
369
+
370
+ result = job._fetchall(mock_api, code="sh.600000")
371
+
372
+ assert isinstance(result, pd.DataFrame)
373
+ assert len(result) == 2
374
+ pd.testing.assert_frame_equal(result, expected_df)
375
+ assert "_fetchall[relay_mode" in str(job.metric.marks)
376
+
377
+
378
+ def test_fetchall_relay_mode_empty_dataframe():
379
+ """Test _fetchall in relay mode with empty DataFrame"""
380
+ mock_session = Mock(spec=Session)
381
+ mock_session.connection = Mock()
382
+
383
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
384
+
385
+ # Mock API that returns empty DataFrame (relay mode)
386
+ empty_df = pd.DataFrame()
387
+ mock_api = Mock(return_value=empty_df)
388
+
389
+ result = job._fetchall(mock_api, code="sh.600000")
390
+
391
+ assert isinstance(result, pd.DataFrame)
392
+ assert result.empty
393
+
394
+
395
+ # ============================================================================
396
+ # Cache Tests
397
+ # ============================================================================
398
+
399
+
400
+ def test_load_cache_success():
401
+ """Test _load_cache when cache hit"""
402
+ mock_session = Mock(spec=Session)
403
+ mock_session.connection = Mock()
404
+
405
+ mock_cache = Mock(spec=Cache)
406
+ cached_data = pd.DataFrame({"test": [1, 2, 3]})
407
+ mock_cache.get.return_value = cached_data
408
+
409
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=mock_cache)
410
+
411
+ result = job._load_cache()
412
+
413
+ assert result is not None
414
+ pd.testing.assert_frame_equal(result, cached_data)
415
+ assert "load_cache[OK]" in job.metric.marks
416
+
417
+
418
+ def test_load_cache_miss():
419
+ """Test _load_cache when cache miss"""
420
+ mock_session = Mock(spec=Session)
421
+ mock_session.connection = Mock()
422
+
423
+ mock_cache = Mock(spec=Cache)
424
+ mock_cache.get.return_value = None
425
+
426
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=mock_cache)
427
+
428
+ result = job._load_cache()
429
+
430
+ assert result is None
431
+
432
+
433
+ def test_load_cache_no_cache():
434
+ """Test _load_cache when cache is disabled"""
435
+ mock_session = Mock(spec=Session)
436
+ mock_session.connection = Mock()
437
+
438
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=False)
439
+
440
+ result = job._load_cache()
441
+
442
+ assert result is None
443
+
444
+
445
+ def test_save_cache_success():
446
+ """Test _save_cache saves data to cache"""
447
+ mock_session = Mock(spec=Session)
448
+ mock_session.connection = Mock()
449
+
450
+ mock_cache = Mock(spec=Cache)
451
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=mock_cache)
452
+
453
+ data = pd.DataFrame({"test": [1, 2, 3]})
454
+ job._save_cache(data)
455
+
456
+ mock_cache.set.assert_called_once()
457
+ assert "_save_cache[OK]" in job.metric.marks
458
+
459
+
460
+ def test_save_cache_no_cache():
461
+ """Test _save_cache when cache is disabled"""
462
+ mock_session = Mock(spec=Session)
463
+ mock_session.connection = Mock()
464
+
465
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=False)
466
+
467
+ data = pd.DataFrame({"test": [1, 2, 3]})
468
+ job._save_cache(data) # Should not raise error
469
+
470
+ # No checkpoint should be marked
471
+ assert "_save_cache[OK]" not in job.metric.marks
472
+
473
+
474
+ # ============================================================================
475
+ # Integration Tests
476
+ # ============================================================================
477
+
478
+
479
+ def test_baostockjob_full_workflow_direct_mode():
480
+ """Test complete BaostockJob workflow in direct mode"""
481
+ mock_session = Mock(spec=Session)
482
+ mock_session.connection = Mock()
483
+
484
+ # Create job with all features
485
+ job = FetchAllJob(
486
+ name="integration_test",
487
+ key="integration_key",
488
+ session=mock_session,
489
+ params={"code": "sh.600000"},
490
+ cache=True,
491
+ retry={"retry": 3, "wait": 1.0},
492
+ paginate={"pagesize": 100, "pagelimit": 1000},
493
+ )
494
+
495
+ # Run the job
496
+ result = job.run()
497
+
498
+ assert isinstance(result, pd.DataFrame)
499
+ assert not result.empty
500
+ assert job.metric.duration > 0
501
+
502
+
503
+ def test_baostockjob_with_date_conversion():
504
+ """Test BaostockJob with date parameter conversion"""
505
+ mock_session = Mock(spec=Session)
506
+ mock_session.connection = Mock()
507
+
508
+ job = ConcreteBaostockJob(
509
+ name="date_test",
510
+ key="date_key",
511
+ session=mock_session,
512
+ params={"code": "sh.600000", "start_date": "20240101", "end_date": date(2024, 12, 31)},
513
+ )
514
+
515
+ # Parse dates
516
+ payload = job.get_params()
517
+ parsed = job._parse_date_params(payload, ["start_date", "end_date"])
518
+
519
+ assert parsed["start_date"] == "2024-01-01"
520
+ assert parsed["end_date"] == "2024-12-31"
521
+
522
+
523
+ # ============================================================================
524
+ # Edge Cases
525
+ # ============================================================================
526
+
527
+
528
+ def test_baostockjob_empty_params():
529
+ """Test BaostockJob with empty parameters"""
530
+ mock_session = Mock(spec=Session)
531
+ mock_session.connection = Mock()
532
+
533
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, params={})
534
+
535
+ assert job.params.to_dict() == {}
536
+
537
+
538
+ def test_baostockjob_metric_tracking():
539
+ """Test BaostockJob tracks metrics correctly"""
540
+ mock_session = Mock(spec=Session)
541
+ mock_session.connection = Mock()
542
+
543
+ job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
544
+ job.run()
545
+ assert job.metric.duration > 0
546
+ assert job.metric.start_at is not None
547
+ assert job.metric.finish_at is not None
@@ -0,0 +1,8 @@
1
+ from .relay import BaostockRelayClient, RelayConnection
2
+ from .session import Session
3
+
4
+ __all__ = [
5
+ "BaostockRelayClient",
6
+ "RelayConnection",
7
+ "Session",
8
+ ]