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,149 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict, List, Literal, Optional
4
+
5
+ import pandas as pd
6
+
7
+ from xfintech.data.common.cache import Cache
8
+ from xfintech.data.common.coolant import Coolant
9
+ from xfintech.data.common.params import Params
10
+ from xfintech.data.common.retry import Retry
11
+ from xfintech.data.job import JobHouse
12
+ from xfintech.data.source.baostock.job import BaostockJob
13
+ from xfintech.data.source.baostock.session.session import Session
14
+ from xfintech.data.source.baostock.stock.stock.constant import (
15
+ KEY,
16
+ NAME,
17
+ PAGINATE,
18
+ SOURCE,
19
+ TARGET,
20
+ )
21
+
22
+
23
+ @JobHouse.register(KEY, alias=KEY)
24
+ class Stock(BaostockJob):
25
+ """
26
+ 描述:
27
+ - 获取上市股票基本信息
28
+ - 返回所有沪深A股上市公司的基础信息
29
+ - 包括股票代码、股票名称、交易状态等信息
30
+ - API文档: http://www.baostock.com/mainContent?file=StockBasicInfoAPI.md
31
+ - SCALE: CrossSection
32
+ - TYPE: Partitioned
33
+ - PAGINATE: 10000 rows / 100 pages
34
+
35
+ 属性:
36
+ - name: str, 作业名称 'stock'。
37
+ - key: str, 作业键 '/baostock/stock'。
38
+ - session: Session, Baostock会话对象。
39
+ - source: TableInfo, 源表信息(BaoStock原始格式)。
40
+ - target: TableInfo, 目标表信息(xfintech格式)。
41
+ - params: Params, 查询参数。
42
+ - day: str, 可选, 指定交易日(YYYY-MM-DD 或 YYYYMMDD)
43
+ - coolant: Coolant, 请求冷却控制。
44
+ - paginate: Paginate, 分页控制(pagesize=10000, pagelimit=100)。
45
+ - retry: Retry, 重试策略。
46
+ - cache: Cache, 缓存管理。
47
+
48
+ 方法:
49
+ - run(): 执行作业,返回股票基本信息DataFrame。
50
+ - _run(): 内部执行逻辑,处理日期参数并调用API。
51
+ - transform(data): 转换数据格式,将源格式转为目标格式。
52
+ - list_codes(): 返回所有股票代码列表。
53
+ - list_names(): 返回所有股票名称列表。
54
+
55
+ 例子:
56
+ ```python
57
+ from xfintech.data.source.baostock.session import Session
58
+ from xfintech.data.source.baostock.stock.stock import Stock
59
+
60
+ session = Session()
61
+ job = Stock(
62
+ session=session,
63
+ params={"day": "20260110"}
64
+ )
65
+ df = job.run()
66
+ ```
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ session: Session,
72
+ params: Optional[Params | Dict[str, Any]] = None,
73
+ coolant: Optional[Coolant | Dict[str, Any]] = None,
74
+ retry: Optional[Retry | Dict[str, Any]] = None,
75
+ cache: Optional[Cache | Dict[str, str] | bool] = None,
76
+ ) -> None:
77
+ super().__init__(
78
+ name=NAME,
79
+ key=KEY,
80
+ session=session,
81
+ source=SOURCE,
82
+ target=TARGET,
83
+ params=params,
84
+ coolant=coolant,
85
+ paginate=PAGINATE,
86
+ retry=retry,
87
+ cache=cache,
88
+ )
89
+
90
+ def _run(self) -> pd.DataFrame:
91
+ cached = self._load_cache()
92
+ if cached is not None:
93
+ return cached
94
+
95
+ # Prepare payload dict
96
+ payload = self.params.to_dict()
97
+ payload = self._parse_date_params(
98
+ payload,
99
+ keys=["day"],
100
+ )
101
+
102
+ # Fetch data from API
103
+ data = self._fetchall(
104
+ api=self.connection.query_all_stock,
105
+ **payload,
106
+ )
107
+ result = self.transform(data)
108
+ self._save_cache(result)
109
+ return result
110
+
111
+ def transform(
112
+ self,
113
+ data: pd.DataFrame,
114
+ ) -> pd.DataFrame:
115
+ cols = self.target.list_column_names()
116
+ if data is None or data.empty:
117
+ return pd.DataFrame(columns=cols)
118
+
119
+ out = data.copy()
120
+ out["code"] = out["code"].astype(str)
121
+ out["trade_status"] = out["tradeStatus"].astype(str)
122
+ out["name"] = out["code_name"].astype(str)
123
+
124
+ # Finalize output
125
+ out = out[cols].drop_duplicates()
126
+ out = out.sort_values(by=["code"])
127
+ out = out.reset_index(drop=True)
128
+ self.markpoint("transform[OK]")
129
+ return out
130
+
131
+ def list_codes(self) -> List[str]:
132
+ df = self.run()
133
+ return sorted(df["code"].unique().tolist())
134
+
135
+ def list_names(self) -> List[str]:
136
+ df = self.run()
137
+ return sorted(df["name"].unique().tolist())
138
+
139
+ def list_tradeable_codes(
140
+ self,
141
+ type: Optional[Literal["0", "1"]] = None,
142
+ ) -> List[str]:
143
+ df = self.run()
144
+ if type is None:
145
+ return sorted(df["code"].unique().tolist())
146
+ else:
147
+ type = str(type)
148
+ tradeable_df = df[df["trade_status"] == type]
149
+ return sorted(tradeable_df["code"].unique().tolist())
@@ -0,0 +1,508 @@
1
+ from unittest.mock import MagicMock, patch
2
+
3
+ import pandas as pd
4
+ import pytest
5
+
6
+ from xfintech.data.common.cache import Cache
7
+ from xfintech.data.common.coolant import Coolant
8
+ from xfintech.data.common.retry import Retry
9
+ from xfintech.data.source.baostock.session.session import Session
10
+ from xfintech.data.source.baostock.stock.stock.constant import (
11
+ KEY,
12
+ NAME,
13
+ SOURCE,
14
+ TARGET,
15
+ )
16
+ from xfintech.data.source.baostock.stock.stock.stock import Stock
17
+
18
+ # ============================================================================
19
+ # Fixtures
20
+ # ============================================================================
21
+
22
+
23
+ @pytest.fixture
24
+ def mock_session():
25
+ """Create a mock Baostock session"""
26
+ session = MagicMock(spec=Session)
27
+ session._credential = None
28
+ session.id = "test1234"
29
+ session.mode = "direct"
30
+ session.relay_url = None
31
+ session.relay_secret = None
32
+ session.connected = True
33
+
34
+ # Mock the connection object
35
+ mock_connection = MagicMock()
36
+ mock_connection.query_all_stock = MagicMock()
37
+ session.connection = mock_connection
38
+
39
+ return session
40
+
41
+
42
+ @pytest.fixture
43
+ def sample_source_data():
44
+ """Create sample source data in Baostock format"""
45
+ return pd.DataFrame(
46
+ {
47
+ "code": ["sh.600000", "sz.000001", "sz.000002"],
48
+ "tradeStatus": ["1", "1", "0"],
49
+ "code_name": ["浦发银行", "平安银行", "万科A"],
50
+ }
51
+ )
52
+
53
+
54
+ # ============================================================================
55
+ # Initialization Tests
56
+ # ============================================================================
57
+
58
+
59
+ def test_stock_initialization_basic(mock_session):
60
+ """Test basic initialization"""
61
+ job = Stock(session=mock_session)
62
+
63
+ assert job.name == NAME
64
+ assert job.key == KEY
65
+ assert job.source == SOURCE
66
+ assert job.target == TARGET
67
+
68
+
69
+ def test_stock_initialization_with_params(mock_session):
70
+ """Test initialization with params"""
71
+ params = {"day": "2026-01-10"}
72
+ job = Stock(session=mock_session, params=params)
73
+
74
+ assert job.params.day == "2026-01-10"
75
+
76
+
77
+ def test_stock_initialization_with_all_components(mock_session):
78
+ """Test initialization with all components"""
79
+ params = {"day": "2026-01-10"}
80
+ coolant = Coolant(interval=0.2)
81
+ retry = Retry(retry=3)
82
+ cache = Cache(path="/tmp/test_cache")
83
+
84
+ job = Stock(
85
+ session=mock_session,
86
+ params=params,
87
+ coolant=coolant,
88
+ retry=retry,
89
+ cache=cache,
90
+ )
91
+
92
+ assert job.params.day == "2026-01-10"
93
+ assert job.coolant.interval == 0.2
94
+ assert job.retry.retry == 3
95
+ assert job.cache is not None
96
+ assert isinstance(job.cache, Cache)
97
+
98
+
99
+ def test_stock_name_and_key():
100
+ """Test name and key constants"""
101
+ assert NAME == "stock"
102
+ assert KEY == "/baostock/stock"
103
+
104
+
105
+ def test_stock_source_schema():
106
+ """Test source schema has all required columns"""
107
+ assert SOURCE is not None
108
+ assert SOURCE.desc == "上市股票基本信息(Baostock格式)"
109
+
110
+ column_names = SOURCE.columns
111
+ assert "code" in column_names
112
+ assert "tradestatus" in column_names # lowercase
113
+ assert "code_name" in column_names
114
+
115
+
116
+ def test_stock_target_schema():
117
+ """Test target schema has all required columns"""
118
+ assert TARGET is not None
119
+ assert TARGET.desc == "上市公司基本信息(xfintech格式)"
120
+
121
+ column_names = TARGET.columns
122
+ assert "code" in column_names
123
+ assert "trade_status" in column_names
124
+ assert "name" in column_names
125
+
126
+
127
+ # ============================================================================
128
+ # Transform Tests
129
+ # ============================================================================
130
+
131
+
132
+ def test_stock_transform_basic(mock_session, sample_source_data):
133
+ """Test basic data transformation"""
134
+ job = Stock(session=mock_session)
135
+ result = job.transform(sample_source_data)
136
+
137
+ assert len(result) == 3
138
+ assert "code" in result.columns
139
+ assert "trade_status" in result.columns
140
+ assert "name" in result.columns
141
+ assert result.iloc[0]["code"] == "sh.600000"
142
+ assert result.iloc[0]["name"] == "浦发银行"
143
+
144
+
145
+ def test_stock_transform_field_types(mock_session, sample_source_data):
146
+ """Test field type conversions"""
147
+ job = Stock(session=mock_session)
148
+ result = job.transform(sample_source_data)
149
+
150
+ # Check string fields
151
+ assert isinstance(result.iloc[0]["code"], str)
152
+ assert isinstance(result.iloc[0]["trade_status"], str)
153
+ assert isinstance(result.iloc[0]["name"], str)
154
+
155
+
156
+ def test_stock_transform_field_mapping(mock_session, sample_source_data):
157
+ """Test field name mappings"""
158
+ job = Stock(session=mock_session)
159
+ result = job.transform(sample_source_data)
160
+
161
+ # Verify field mappings
162
+ assert result.iloc[0]["trade_status"] == "1" # from tradeStatus
163
+ assert result.iloc[0]["name"] == "浦发银行" # from code_name
164
+ assert result.iloc[0]["code"] == "sh.600000"
165
+
166
+
167
+ def test_stock_transform_empty_data(mock_session):
168
+ """Test transform with empty data"""
169
+ job = Stock(session=mock_session)
170
+
171
+ # Test with None
172
+ result = job.transform(None)
173
+ assert result.empty
174
+ assert len(result.columns) == len(TARGET.columns)
175
+
176
+ # Test with empty DataFrame
177
+ empty_df = pd.DataFrame()
178
+ result = job.transform(empty_df)
179
+ assert result.empty
180
+ assert len(result.columns) == len(TARGET.columns)
181
+
182
+
183
+ def test_stock_transform_duplicate_removal(mock_session):
184
+ """Test that duplicates are removed"""
185
+ data = pd.DataFrame(
186
+ {
187
+ "code": ["sh.600000", "sh.600000", "sz.000001"],
188
+ "tradeStatus": ["1", "1", "1"],
189
+ "code_name": ["浦发银行", "浦发银行", "平安银行"],
190
+ }
191
+ )
192
+ job = Stock(session=mock_session)
193
+ result = job.transform(data)
194
+
195
+ # Duplicates should be removed
196
+ assert len(result) == 2
197
+
198
+
199
+ def test_stock_transform_sorting(mock_session):
200
+ """Test that result is sorted by code"""
201
+ data = pd.DataFrame(
202
+ {
203
+ "code": ["sz.000002", "sh.600000", "sz.000001"],
204
+ "tradeStatus": ["1", "1", "1"],
205
+ "code_name": ["万科A", "浦发银行", "平安银行"],
206
+ }
207
+ )
208
+ job = Stock(session=mock_session)
209
+ result = job.transform(data)
210
+
211
+ # Should be sorted by code
212
+ assert result.iloc[0]["code"] == "sh.600000"
213
+ assert result.iloc[1]["code"] == "sz.000001"
214
+ assert result.iloc[2]["code"] == "sz.000002"
215
+
216
+
217
+ # ============================================================================
218
+ # Run Tests
219
+ # ============================================================================
220
+
221
+
222
+ def test_stock_run_basic(mock_session, sample_source_data):
223
+ """Test basic run method"""
224
+ job = Stock(session=mock_session)
225
+
226
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
227
+ result = job.run()
228
+
229
+ assert isinstance(result, pd.DataFrame)
230
+ assert len(result) == 3
231
+ assert "code" in result.columns
232
+ assert "trade_status" in result.columns
233
+ assert "name" in result.columns
234
+
235
+
236
+ def test_stock_run_with_day_param(mock_session, sample_source_data):
237
+ """Test run with day parameter"""
238
+ job = Stock(session=mock_session, params={"day": "2026-01-10"})
239
+
240
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
241
+ job.run()
242
+
243
+ call_kwargs = mock_fetchall.call_args[1]
244
+ assert call_kwargs["day"] == "2026-01-10"
245
+
246
+
247
+ def test_stock_run_calls_query_all_stock(mock_session, sample_source_data):
248
+ """Test that run calls query_all_stock API"""
249
+ job = Stock(session=mock_session)
250
+
251
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
252
+ job.run()
253
+
254
+ # Verify that _fetchall was called with the correct API
255
+ assert mock_fetchall.call_count == 1
256
+ call_args = mock_fetchall.call_args
257
+ assert call_args[1]["api"] == job.connection.query_all_stock
258
+
259
+
260
+ def test_stock_run_calls_transform(mock_session, sample_source_data):
261
+ """Test that run calls transform"""
262
+ job = Stock(session=mock_session)
263
+
264
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
265
+ with patch.object(job, "transform", wraps=job.transform) as mock_transform:
266
+ job.run()
267
+
268
+ mock_transform.assert_called_once()
269
+
270
+
271
+ # ============================================================================
272
+ # Cache Tests
273
+ # ============================================================================
274
+
275
+
276
+ def test_stock_cache_persistence(mock_session, sample_source_data):
277
+ """Test that cache persists across runs"""
278
+ job = Stock(session=mock_session, cache=True)
279
+
280
+ with patch.object(job, "_load_cache", return_value=None) as mock_load:
281
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
282
+ # First run - fetches data and caches it
283
+ result1 = job.run()
284
+ assert mock_fetchall.call_count == 1
285
+ assert mock_load.call_count == 1
286
+
287
+ # Second run - _load_cache still returns None, so _fetchall called again
288
+ result2 = job.run()
289
+ assert mock_fetchall.call_count == 2
290
+ assert mock_load.call_count == 2
291
+
292
+ pd.testing.assert_frame_equal(result1, result2)
293
+
294
+
295
+ def test_stock_params_identifier_uniqueness(mock_session):
296
+ """Test that different params create different cache keys"""
297
+ job1 = Stock(session=mock_session, params={"day": "2026-01-10"}, cache=True)
298
+ job2 = Stock(session=mock_session, params={"day": "2026-01-11"}, cache=True)
299
+
300
+ assert job1.params.identifier != job2.params.identifier
301
+
302
+
303
+ def test_stock_without_cache(mock_session, sample_source_data):
304
+ """Test that stock works correctly without cache"""
305
+ job = Stock(session=mock_session, cache=False)
306
+
307
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
308
+ job.run()
309
+ job.run()
310
+
311
+ # Should fetch twice (no caching)
312
+ assert mock_fetchall.call_count == 2
313
+
314
+
315
+ # ============================================================================
316
+ # Date Parsing Tests
317
+ # ============================================================================
318
+
319
+
320
+ def test_stock_date_parsing_yyyymmdd(mock_session, sample_source_data):
321
+ """Test date parsing from YYYYMMDD format"""
322
+ job = Stock(session=mock_session, params={"day": "20260110"})
323
+
324
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
325
+ job.run()
326
+
327
+ call_kwargs = mock_fetchall.call_args[1]
328
+ # Should convert YYYYMMDD to YYYY-MM-DD
329
+ assert call_kwargs["day"] == "2026-01-10"
330
+
331
+
332
+ def test_stock_date_parsing_hyphen_format(mock_session, sample_source_data):
333
+ """Test date parsing preserves YYYY-MM-DD format"""
334
+ job = Stock(session=mock_session, params={"day": "2026-01-10"})
335
+
336
+ with patch.object(job, "_fetchall", return_value=sample_source_data) as mock_fetchall:
337
+ job.run()
338
+
339
+ call_kwargs = mock_fetchall.call_args[1]
340
+ assert call_kwargs["day"] == "2026-01-10"
341
+
342
+
343
+ # ============================================================================
344
+ # Integration Tests
345
+ # ============================================================================
346
+
347
+
348
+ def test_stock_full_workflow(mock_session, sample_source_data):
349
+ """Test complete workflow from initialization to data retrieval"""
350
+ job = Stock(session=mock_session, params={"day": "2026-01-10"})
351
+
352
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
353
+ result = job.run()
354
+
355
+ assert not result.empty
356
+ assert len(result) == 3
357
+ assert list(result.columns) == ["code", "trade_status", "name"]
358
+
359
+
360
+ def test_stock_with_large_dataset(mock_session):
361
+ """Test handling of large dataset"""
362
+ # Create a large dataset
363
+ large_data = pd.DataFrame(
364
+ {
365
+ "code": [f"sh.{600000 + i}" for i in range(1000)],
366
+ "tradeStatus": ["1"] * 1000,
367
+ "code_name": [f"股票{i}" for i in range(1000)],
368
+ }
369
+ )
370
+
371
+ job = Stock(session=mock_session)
372
+
373
+ with patch.object(job, "_fetchall", return_value=large_data):
374
+ result = job.run()
375
+
376
+ assert len(result) == 1000
377
+ assert result.iloc[0]["code"] == "sh.600000"
378
+ assert result.iloc[-1]["code"] == "sh.600999"
379
+
380
+
381
+ def test_stock_with_various_trade_statuses(mock_session):
382
+ """Test handling stocks with different trade statuses"""
383
+ data = pd.DataFrame(
384
+ {
385
+ "code": ["sh.600000", "sz.000001", "sz.000002"],
386
+ "tradeStatus": ["1", "0", "1"],
387
+ "code_name": ["浦发银行", "平安银行", "万科A"],
388
+ }
389
+ )
390
+
391
+ job = Stock(session=mock_session)
392
+
393
+ with patch.object(job, "_fetchall", return_value=data):
394
+ result = job.run()
395
+
396
+ assert len(result) == 3
397
+ # Check that all trade statuses are preserved
398
+ assert "1" in result["trade_status"].values
399
+ assert "0" in result["trade_status"].values
400
+
401
+
402
+ def test_stock_with_empty_result_from_api(mock_session):
403
+ """Test handling of empty result from API"""
404
+ empty_data = pd.DataFrame(columns=["code", "tradeStatus", "code_name"])
405
+
406
+ job = Stock(session=mock_session)
407
+
408
+ with patch.object(job, "_fetchall", return_value=empty_data):
409
+ result = job.run()
410
+
411
+ assert result.empty
412
+ assert list(result.columns) == ["code", "trade_status", "name"]
413
+
414
+
415
+ def test_stock_with_special_characters_in_names(mock_session):
416
+ """Test handling of special characters in stock names"""
417
+ data = pd.DataFrame(
418
+ {
419
+ "code": ["sh.600000", "sz.000001"],
420
+ "tradeStatus": ["1", "1"],
421
+ "code_name": ["*ST浦发", "ST平安"],
422
+ }
423
+ )
424
+
425
+ job = Stock(session=mock_session)
426
+
427
+ with patch.object(job, "_fetchall", return_value=data):
428
+ result = job.run()
429
+
430
+ assert result.iloc[0]["name"] == "*ST浦发"
431
+ assert result.iloc[1]["name"] == "ST平安"
432
+
433
+
434
+ # ============================================================================
435
+ # List Methods Tests
436
+ # ============================================================================
437
+
438
+
439
+ def test_stock_list_codes(mock_session, sample_source_data):
440
+ """Test list_codes method"""
441
+ job = Stock(session=mock_session)
442
+
443
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
444
+ codes = job.list_codes()
445
+
446
+ assert isinstance(codes, list)
447
+ assert len(codes) == 3
448
+ assert "sh.600000" in codes
449
+ assert "sz.000001" in codes
450
+ assert "sz.000002" in codes
451
+ # Should be sorted
452
+ assert codes == sorted(codes)
453
+
454
+
455
+ def test_stock_list_names(mock_session, sample_source_data):
456
+ """Test list_names method"""
457
+ job = Stock(session=mock_session)
458
+
459
+ with patch.object(job, "_fetchall", return_value=sample_source_data):
460
+ names = job.list_names()
461
+
462
+ assert isinstance(names, list)
463
+ assert len(names) == 3
464
+ assert "浦发银行" in names
465
+ assert "平安银行" in names
466
+ assert "万科A" in names
467
+ # Should be sorted
468
+ assert names == sorted(names)
469
+
470
+
471
+ def test_stock_list_codes_with_duplicates(mock_session):
472
+ """Test list_codes removes duplicates"""
473
+ data = pd.DataFrame(
474
+ {
475
+ "code": ["sh.600000", "sh.600000", "sz.000001"],
476
+ "tradeStatus": ["1", "1", "1"],
477
+ "code_name": ["浦发银行", "浦发银行", "平安银行"],
478
+ }
479
+ )
480
+
481
+ job = Stock(session=mock_session)
482
+
483
+ with patch.object(job, "_fetchall", return_value=data):
484
+ codes = job.list_codes()
485
+
486
+ # Should return unique codes only
487
+ assert len(codes) == 2
488
+ assert codes.count("sh.600000") == 1
489
+
490
+
491
+ def test_stock_list_names_with_duplicates(mock_session):
492
+ """Test list_names removes duplicates"""
493
+ data = pd.DataFrame(
494
+ {
495
+ "code": ["sh.600000", "sz.000001", "sz.000002"],
496
+ "tradeStatus": ["1", "1", "1"],
497
+ "code_name": ["浦发银行", "平安银行", "平安银行"],
498
+ }
499
+ )
500
+
501
+ job = Stock(session=mock_session)
502
+
503
+ with patch.object(job, "_fetchall", return_value=data):
504
+ names = job.list_names()
505
+
506
+ # Should return unique names only
507
+ assert len(names) == 2
508
+ assert names.count("平安银行") == 1
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+
3
+ from xfintech.data.source.baostock.stock.stockinfo.stockinfo import StockInfo
4
+
5
+ __all__ = ["StockInfo"]