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,186 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import pickle
5
+ import uuid
6
+ from pathlib import Path
7
+ from typing import Any, Dict, List, Optional
8
+
9
+
10
+ class Cache:
11
+ """
12
+ 描述:
13
+ - 文件缓存管理器,用于避免重复的 API 调用和数据处理。
14
+ - 使用 pickle 序列化存储任意 Python 对象。
15
+ - 使用 MD5 哈希将缓存键转换为文件名。
16
+ - 自动创建和管理缓存目录。
17
+ - 每个 Cache 实例有唯一标识符,避免冲突。
18
+
19
+ 属性:
20
+ - identifier: str, 缓存实例的唯一标识符(12位十六进制)。
21
+ - path: Path, 缓存文件存储路径。
22
+ - DEFAULT_PARENT: Path, 类常量,默认缓存根目录为 /tmp/xfintech/。
23
+
24
+ 方法:
25
+ - get(unit): 获取缓存值,不存在或出错返回 None。
26
+ - set(unit, value): 设置缓存值。
27
+ - get_unit(unit): 获取缓存单元的文件路径(MD5哈希)。
28
+ - list(): 返回所有缓存文件的哈希键列表。
29
+ - clear(): 清空所有缓存文件。
30
+ - describe(): 返回缓存详细信息。
31
+ - to_dict(): 返回缓存信息字典。
32
+ - __contains__(unit): 支持 'in' 操作符检查缓存是否存在。
33
+ - __str__(): 返回缓存路径字符串。
34
+ - __repr__(): 返回对象的详细字符串表示。
35
+
36
+ 例子:
37
+ ```python
38
+ from xfintech.data.common.cache import Cache
39
+
40
+ # 基本用法
41
+ cache = Cache()
42
+ cache.set("api_result", {"data": [1, 2, 3]})
43
+ result = cache.get("api_result")
44
+ print(result) # {"data": [1, 2, 3]}
45
+
46
+ # 检查缓存是否存在
47
+ if "api_result" in cache:
48
+ data = cache.get("api_result")
49
+
50
+ # 自定义缓存路径
51
+ cache = Cache(path="/custom/cache/path")
52
+
53
+ # 列出所有缓存键
54
+ keys = cache.list()
55
+ print(f"缓存数量: {len(keys)}")
56
+
57
+ # 获取缓存信息
58
+ info = cache.to_dict()
59
+ print(f"缓存路径: {info['path']}")
60
+ print(f"缓存标识: {info['identifier']}")
61
+
62
+ # 清空缓存
63
+ cache.clear()
64
+
65
+ # 缓存任意对象
66
+ cache.set("user", {"name": "张三", "age": 30})
67
+ cache.set("numbers", [1, 2, 3, 4, 5])
68
+ cache.set("dataframe", pd.DataFrame(...))
69
+
70
+ # 缓存失败返回 None
71
+ result = cache.get("nonexistent") # None
72
+ ```
73
+ """
74
+
75
+ DEFAULT_PARENT = Path("/tmp/xfintech/")
76
+
77
+ @classmethod
78
+ def from_dict(
79
+ cls,
80
+ data: Dict[str, Any],
81
+ ) -> Cache:
82
+ if isinstance(data, Cache):
83
+ return data
84
+ return cls(
85
+ path=data.get("path"),
86
+ )
87
+
88
+ def __init__(
89
+ self,
90
+ identifier: Optional[str] = None,
91
+ path: Optional[str | Path] = None,
92
+ ) -> None:
93
+ self.identifier: str = self._resolve_identifier(identifier)
94
+ self.path: Path = self._resolve_path(path)
95
+
96
+ def _resolve_identifier(
97
+ self,
98
+ identifier: Optional[str] = None,
99
+ ) -> str:
100
+ if identifier is not None:
101
+ return identifier
102
+ return uuid.uuid4().hex[0:12]
103
+
104
+ def _resolve_path(
105
+ self,
106
+ path: str | Path | None,
107
+ ) -> Path:
108
+ if path is not None:
109
+ path = Path(path) / self.identifier
110
+ else:
111
+ path = self.DEFAULT_PARENT / self.identifier
112
+ if not path.exists():
113
+ path.mkdir(parents=True, exist_ok=True)
114
+ return path
115
+
116
+ def get_unit(self, unit: str) -> Path:
117
+ key = unit.encode("utf-8")
118
+ hashed = hashlib.md5(
119
+ key,
120
+ usedforsecurity=False,
121
+ ).hexdigest()
122
+ return self.path / f"{hashed}.pkl"
123
+
124
+ def __contains__(self, unit: str) -> bool:
125
+ path = self.get_unit(unit)
126
+ return path.exists()
127
+
128
+ def __str__(self):
129
+ return str(self.path)
130
+
131
+ def __repr__(self):
132
+ return f"{self.__class__.__name__}(path={self.path})"
133
+
134
+ def get(
135
+ self,
136
+ unit: str,
137
+ ) -> Optional[Any]:
138
+ unitpath = self.get_unit(unit)
139
+ if not unitpath.exists():
140
+ return None
141
+ try:
142
+ with unitpath.open("rb") as f:
143
+ payload = pickle.load(f)
144
+ value = payload.get("value")
145
+ return value
146
+ except Exception:
147
+ return None
148
+
149
+ def set(
150
+ self,
151
+ unit: str,
152
+ value: Any,
153
+ ) -> None:
154
+ unitpath = self.get_unit(unit)
155
+ payload = {"value": value}
156
+ with unitpath.open("wb") as f:
157
+ pickle.dump(payload, f)
158
+
159
+ def list(
160
+ self,
161
+ ) -> List[str]:
162
+ keys = []
163
+ for file in self.path.glob("*.pkl"):
164
+ keys.append(file.stem)
165
+ return keys
166
+
167
+ def clear(self) -> None:
168
+ for file in self.path.glob("*.pkl"):
169
+ try:
170
+ file.unlink()
171
+ except Exception:
172
+ pass
173
+
174
+ def describe(
175
+ self,
176
+ ) -> Dict[str, Any]:
177
+ return self.to_dict()
178
+
179
+ def to_dict(
180
+ self,
181
+ ) -> Dict[str, Any]:
182
+ return {
183
+ "identifier": self.identifier,
184
+ "path": str(self.path),
185
+ "units": self.list(),
186
+ }
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ import time
5
+ from typing import Any, Dict, Optional
6
+
7
+
8
+ class Coolant:
9
+ """
10
+ 描述:
11
+ - 冷却器类,用于在操作之间添加延迟(冷却时间)。
12
+ - 支持固定间隔冷却和随机抖动功能。
13
+ - 可配置基础间隔时间和抖动范围。
14
+ - 主要用于限制 API 调用频率或避免请求风暴。
15
+
16
+ 属性:
17
+ - interval: int, 基础冷却间隔时间(秒),0 表示不冷却,默认为 0。
18
+ - use_jitter: bool, 是否启用随机抖动,默认为 False。
19
+ - jitter_min: float, 最小抖动时间(秒),默认为 0.1 秒。
20
+ - jitter_max: float, 最大抖动时间(秒),默认为 3.0 秒。
21
+ - DEFAULT_INTERVAL: int, 类常量,默认间隔时间为 0。
22
+ - DEFAULT_JITTER_MIN: float, 类常量,默认最小抖动时间为 0.1 秒。
23
+ - DEFAULT_JITTER_MAX: float, 类常量,默认最大抖动时间为 3.0 秒。
24
+
25
+ 方法:
26
+ - cool(): 执行冷却操作,包括基础间隔和可选的抖动。
27
+ - jitter(): 执行随机抖动延迟(内部方法)。
28
+
29
+ 例子:
30
+ ```python
31
+ from xfintech.data.common.coolant import Coolant
32
+ import time
33
+
34
+ # 基本用法:固定间隔冷却
35
+ coolant = Coolant(interval=2)
36
+ start = time.time()
37
+ coolant.cool()
38
+ elapsed = time.time() - start
39
+ print(f"冷却时间: {elapsed:.2f}秒") # 约 2.0 秒
40
+
41
+ # 使用抖动:在基础间隔上添加随机延迟
42
+ coolant = Coolant(interval=1, use_jitter=True)
43
+ coolant.cool() # 等待 1 秒 + 0.1~3.0 秒随机抖动
44
+
45
+ # 自定义抖动范围
46
+ coolant = Coolant(
47
+ interval=2,
48
+ use_jitter=True,
49
+ jitter_min=0.5,
50
+ jitter_max=1.5
51
+ )
52
+ coolant.cool() # 等待 2 秒 + 0.5~1.5 秒随机抖动
53
+
54
+ # 仅抖动,无固定间隔
55
+ coolant = Coolant(interval=0, use_jitter=True)
56
+ coolant.cool() # 仅等待 0.1~3.0 秒随机抖动
57
+
58
+ # 不冷却
59
+ coolant = Coolant(interval=0)
60
+ coolant.cool() # 立即返回,不等待
61
+
62
+ # 在循环中使用
63
+ coolant = Coolant(interval=1, use_jitter=True)
64
+ for i in range(5):
65
+ # 执行某些操作
66
+ print(f"任务 {i}")
67
+ coolant.cool() # 每次操作后冷却
68
+ ```
69
+ """
70
+
71
+ DEFAULT_INTERVAL = 0
72
+ DEFAULT_JITTER_MIN = 0.1
73
+ DEFAULT_JITTER_MAX = 3.0
74
+
75
+ @classmethod
76
+ def from_dict(
77
+ cls,
78
+ data: Dict[str, Any],
79
+ ) -> Coolant:
80
+ if isinstance(data, Coolant):
81
+ return data
82
+ return cls(
83
+ interval=data.get("interval"),
84
+ use_jitter=data.get("use_jitter"),
85
+ jitter_min=data.get("jitter_min"),
86
+ jitter_max=data.get("jitter_max"),
87
+ )
88
+
89
+ def __init__(
90
+ self,
91
+ interval: Optional[int] = None,
92
+ use_jitter: Optional[bool] = False,
93
+ jitter_min: Optional[float | int] = None,
94
+ jitter_max: Optional[float | int] = None,
95
+ ) -> None:
96
+ self.interval: int = self._resolve_interval(interval)
97
+ self.use_jitter: bool = use_jitter
98
+ self.jitter_min: float = self._resolve_jitter_min(jitter_min)
99
+ self.jitter_max: float = self._resolve_jitter_max(jitter_max)
100
+
101
+ def _resolve_interval(
102
+ self,
103
+ interval: Optional[int] = None,
104
+ ) -> int:
105
+ if interval is not None:
106
+ return interval
107
+ else:
108
+ return self.DEFAULT_INTERVAL
109
+
110
+ def _resolve_jitter_min(
111
+ self,
112
+ value: Optional[float | int] = None,
113
+ ) -> float:
114
+ if self.use_jitter:
115
+ if value is not None:
116
+ return float(value)
117
+ else:
118
+ return float(self.DEFAULT_JITTER_MIN)
119
+ else:
120
+ return 0.0
121
+
122
+ def _resolve_jitter_max(
123
+ self,
124
+ value: Optional[float | int] = None,
125
+ ) -> float:
126
+ if self.use_jitter:
127
+ if value is not None:
128
+ return float(value)
129
+ else:
130
+ return float(self.DEFAULT_JITTER_MAX)
131
+ else:
132
+ return 0.0
133
+
134
+ def __str__(self) -> str:
135
+ return str(self.interval)
136
+
137
+ def __repr__(self) -> str:
138
+ return f"{self.__class__.__name__}(interval={self.interval!r}, use_jitter={self.use_jitter!r}, "
139
+
140
+ def jitter(self) -> None:
141
+ if self.use_jitter:
142
+ delay = random.uniform(
143
+ self.jitter_min,
144
+ self.jitter_max,
145
+ )
146
+ time.sleep(round(delay, 1))
147
+
148
+ def cool(self) -> None:
149
+ if self.interval <= 0:
150
+ self.jitter() # Still apply jitter even if interval is 0
151
+ return
152
+ time.sleep(round(self.interval, 1))
153
+ self.jitter()
154
+
155
+ def describe(self) -> Dict[str, Any]:
156
+ result = {}
157
+ result["interval"] = self.interval
158
+ result["use_jitter"] = self.use_jitter
159
+ if self.use_jitter:
160
+ result["jitter_min"] = self.jitter_min
161
+ result["jitter_max"] = self.jitter_max
162
+ return result
163
+
164
+ def to_dict(self) -> Dict[str, Any]:
165
+ result = {
166
+ "interval": self.interval,
167
+ "use_jitter": self.use_jitter,
168
+ "jitter_min": self.jitter_min,
169
+ "jitter_max": self.jitter_max,
170
+ }
171
+ return result
@@ -0,0 +1,138 @@
1
+ from __future__ import annotations
2
+
3
+ import traceback
4
+ from typing import Dict, List, Optional
5
+
6
+ import pandas as pd
7
+
8
+
9
+ class Metric:
10
+ """
11
+ 描述:
12
+ - 用于跟踪操作执行时间和错误的工具类。
13
+ - 支持上下文管理器模式,自动记录开始和结束时间。
14
+ - 可以在执行过程中标记关键时间点(marks)。
15
+ - 自动捕获并保存上下文管理器中发生的异常信息。
16
+ - 提供多种格式的时间和状态数据输出。
17
+
18
+ 属性:
19
+ - start_at: Optional[pd.Timestamp], 开始时间戳。
20
+ - finish_at: Optional[pd.Timestamp], 结束时间戳。
21
+ - marks: Dict[str, pd.Timestamp], 命名时间标记点的字典。
22
+ - errors: List[str], 捕获的异常堆栈信息列表。
23
+ - duration: float, 只读属性,返回执行时长(秒),如果未结束则返回至当前时间的时长。
24
+
25
+ 方法:
26
+ - start(): 记录开始时间。
27
+ - finish(): 记录结束时间。
28
+ - mark(name): 在当前时间记录一个命名标记点。
29
+ - reset(): 重置所有状态(时间、标记、错误)。
30
+ - get_start_iso(): 返回 ISO 格式的开始时间字符串。
31
+ - get_finish_iso(): 返回 ISO 格式的结束时间字符串。
32
+ - get_mark_iso(): 返回所有标记点的 ISO 格式时间字典。
33
+ - describe(): 返回包含非空字段的状态字典。
34
+ - to_dict(): 返回包含所有字段的完整状态字典。
35
+
36
+ 例子:
37
+ ```python
38
+ from xfintech.data.common.metric import Metric
39
+ import time
40
+
41
+ # 作为上下文管理器使用
42
+ with Metric() as m:
43
+ time.sleep(0.1)
44
+ m.mark("checkpoint_1")
45
+ time.sleep(0.1)
46
+ m.mark("checkpoint_2")
47
+ ```
48
+ """
49
+
50
+ def __init__(self) -> None:
51
+ self.start_at: Optional[pd.Timestamp] = None
52
+ self.finish_at: Optional[pd.Timestamp] = None
53
+ self.marks: Dict[str, pd.Timestamp] = {}
54
+ self.errors: List[str] = []
55
+
56
+ @property
57
+ def duration(self) -> float:
58
+ if not self.start_at:
59
+ return 0.0
60
+ if not self.finish_at:
61
+ now = pd.Timestamp.now()
62
+ return (now - self.start_at).total_seconds()
63
+ diff = self.finish_at - self.start_at
64
+ return diff.total_seconds()
65
+
66
+ def reset(self) -> None:
67
+ self.start_at = None
68
+ self.finish_at = None
69
+ self.marks = {}
70
+ self.errors = []
71
+
72
+ def __enter__(self) -> Metric:
73
+ self.reset()
74
+ self.start()
75
+ return self
76
+
77
+ def __exit__(
78
+ self,
79
+ exc_type,
80
+ exc_val,
81
+ exc_tb,
82
+ ) -> bool:
83
+ if exc_val:
84
+ tb = traceback.format_exception(
85
+ exc_type,
86
+ exc_val,
87
+ exc_tb,
88
+ )
89
+ self.errors = [line.rstrip("\n") for line in tb]
90
+ self.finish()
91
+ return False
92
+
93
+ def start(self) -> None:
94
+ self.start_at = pd.Timestamp.now()
95
+
96
+ def get_start_iso(self) -> Optional[str]:
97
+ if self.start_at is None:
98
+ return None
99
+ return self.start_at.isoformat()
100
+
101
+ def finish(self) -> None:
102
+ self.finish_at = pd.Timestamp.now()
103
+
104
+ def get_finish_iso(self) -> Optional[str]:
105
+ if self.finish_at is None:
106
+ return None
107
+ return self.finish_at.isoformat()
108
+
109
+ def mark(self, name: str) -> None:
110
+ self.marks[name] = pd.Timestamp.now()
111
+
112
+ def get_mark_iso(self) -> Dict[str, str]:
113
+ result = {}
114
+ for k, v in self.marks.items():
115
+ result[k] = v.isoformat()
116
+ return result
117
+
118
+ def describe(self) -> Dict[str, Optional[object]]:
119
+ result = {}
120
+ if self.start_at is not None:
121
+ result["started_at"] = self.get_start_iso()
122
+ if self.finish_at is not None:
123
+ result["finished_at"] = self.get_finish_iso()
124
+ result["duration"] = self.duration
125
+ if self.errors:
126
+ result["errors"] = self.errors
127
+ if self.marks:
128
+ result["marks"] = self.get_mark_iso()
129
+ return result
130
+
131
+ def to_dict(self) -> Dict[str, Optional[object]]:
132
+ return {
133
+ "started_at": self.get_start_iso(),
134
+ "finished_at": self.get_finish_iso(),
135
+ "duration": self.duration,
136
+ "errors": self.errors,
137
+ "marks": self.get_mark_iso(),
138
+ }
@@ -0,0 +1,132 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Dict
4
+
5
+
6
+ class Paginate:
7
+ """
8
+ 描述:
9
+ - 分页器类,用于管理数据分页请求。
10
+ - 支持配置每页大小、总限制和偏移量。
11
+ - 提供方法重置偏移量和获取下一页偏移量。
12
+
13
+ 属性:
14
+ - pagesize: int, 每页数据大小,默认为 5000。
15
+ - pagelimit: int, 总数据限制,默认为 10000。
16
+ - offset: int, 当前数据偏移量,默认为 0。
17
+
18
+ 方法:
19
+ - reset(): 重置偏移量为 0。
20
+ - next(): 将偏移量增加一个页面大小,并返回新的偏移量。
21
+ - describe(): 返回分页器配置信息字典(排除零值)。
22
+ - to_dict(): 返回包含所有配置的完整字典。
23
+ - from_dict(data): 从字典创建 Paginate 实例。
24
+
25
+ 例子:
26
+ ```python
27
+ from xfintech.data.common.paginate import Paginate
28
+
29
+ # 创建分页器实例
30
+ paginator = Paginate(pagesize=1000, pagelimit=5000)
31
+
32
+ # 获取第一页数据(offset=0)
33
+ print(f"当前偏移量: {paginator.offset}") # 输出: 当前偏移量: 0
34
+
35
+ # 移动到下一页
36
+ new_offset = paginator.next()
37
+ print(f"新的偏移量: {new_offset}") # 输出: 新的偏移量: 1000
38
+
39
+ # 继续翻页
40
+ paginator.next()
41
+ print(f"第三页偏移量: {paginator.offset}") # 输出: 第三页偏移量: 2000
42
+
43
+ # 重置到第一页
44
+ paginator.reset()
45
+ print(f"重置后偏移量: {paginator.offset}") # 输出: 重置后偏移量: 0
46
+
47
+ # 从字典创建
48
+ new_paginator = Paginate.from_dict({
49
+ "pagesize": 500,
50
+ "pagelimit": 2000,
51
+ "offset": 1000
52
+ })
53
+ ```
54
+ """
55
+
56
+ DEFAULT_PAGESIZE: int = 5000
57
+ DEFAULT_PAGELIMIT: int = 10000
58
+ DEFAULT_OFFSET: int = 0
59
+
60
+ @classmethod
61
+ def from_dict(
62
+ cls,
63
+ data: Dict[str, Any],
64
+ ) -> Paginate:
65
+ if isinstance(data, Paginate):
66
+ return data
67
+ return cls(
68
+ pagelimit=data.get("pagelimit"),
69
+ pagesize=data.get("pagesize"),
70
+ offset=data.get("offset"),
71
+ )
72
+
73
+ def __init__(
74
+ self,
75
+ pagelimit: int = 10000,
76
+ pagesize: int = 5000,
77
+ offset: int = 0,
78
+ ) -> None:
79
+ self.pagelimit = self._resolve_pagelimit(pagelimit)
80
+ self.pagesize = self._resolve_pagesize(pagesize)
81
+ self.offset = self._resolve_offset(offset)
82
+
83
+ def _resolve_pagelimit(
84
+ self,
85
+ pagelimit: int,
86
+ ) -> int:
87
+ if pagelimit and pagelimit > 0:
88
+ return pagelimit
89
+ else:
90
+ return self.DEFAULT_PAGELIMIT
91
+
92
+ def _resolve_pagesize(
93
+ self,
94
+ pagesize: int,
95
+ ) -> int:
96
+ if pagesize and pagesize > 0:
97
+ return pagesize
98
+ else:
99
+ return self.DEFAULT_PAGESIZE
100
+
101
+ def _resolve_offset(
102
+ self,
103
+ offset: int,
104
+ ) -> int:
105
+ if offset and offset >= 0:
106
+ return offset
107
+ else:
108
+ return self.DEFAULT_OFFSET
109
+
110
+ def reset(self) -> None:
111
+ self.offset = 0
112
+
113
+ def next(self) -> int:
114
+ self.offset += self.pagesize
115
+ return self.offset
116
+
117
+ def describe(self) -> Dict[str, Any]:
118
+ result = {}
119
+ if self.pagesize:
120
+ result["pagesize"] = self.pagesize
121
+ if self.pagelimit:
122
+ result["pagelimit"] = self.pagelimit
123
+ if self.offset:
124
+ result["offset"] = self.offset
125
+ return result
126
+
127
+ def to_dict(self) -> Dict[str, Any]:
128
+ return {
129
+ "pagesize": self.pagesize,
130
+ "pagelimit": self.pagelimit,
131
+ "offset": self.offset,
132
+ }