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,564 @@
1
+ from unittest.mock import MagicMock, patch
2
+
3
+ import pytest
4
+
5
+ from xfintech.connect.artifact import Artifact
6
+ from xfintech.connect.common.connectref import ConnectRef
7
+
8
+ # ============================================================================
9
+ # Fixtures
10
+ # ============================================================================
11
+
12
+
13
+ @pytest.fixture
14
+ def mock_connect_ref():
15
+ """Create a mock ConnectRef"""
16
+ ref = MagicMock(spec=ConnectRef)
17
+ ref.location = "s3://test-bucket/test-key.json"
18
+ ref.describe = MagicMock(return_value={"location": ref.location})
19
+ ref.to_dict = MagicMock(return_value={"location": ref.location})
20
+ ref.__str__ = MagicMock(return_value=ref.location)
21
+ return ref
22
+
23
+
24
+ @pytest.fixture
25
+ def mock_connect():
26
+ """Create a mock Connect object"""
27
+ connect = MagicMock()
28
+ connect.get_object = MagicMock(return_value=b'{"key": "value"}')
29
+ connect.put_object = MagicMock(return_value=MagicMock(location="s3://test-bucket/test-key.json"))
30
+ return connect
31
+
32
+
33
+ @pytest.fixture
34
+ def mock_serialiser():
35
+ """Create a mock Serialiser"""
36
+ serialiser = MagicMock()
37
+ serialiser.serialise = MagicMock(return_value=b'{"serialised": true}')
38
+ return serialiser
39
+
40
+
41
+ @pytest.fixture
42
+ def mock_deserialiser():
43
+ """Create a mock Deserialiser"""
44
+ deserialiser = MagicMock()
45
+ deserialiser.deserialise = MagicMock(return_value={"deserialised": True})
46
+ return deserialiser
47
+
48
+
49
+ # ============================================================================
50
+ # Initialization Tests
51
+ # ============================================================================
52
+
53
+
54
+ def test_artifact_init_with_ref_object(mock_connect_ref):
55
+ """Test Artifact initialization with ConnectRef object"""
56
+ artifact = Artifact(ref=mock_connect_ref)
57
+
58
+ assert artifact.ref == mock_connect_ref
59
+ assert artifact.data is None
60
+ assert artifact.meta is None
61
+
62
+
63
+ def test_artifact_init_with_ref_dict():
64
+ """Test Artifact initialization with ref as dict"""
65
+ ref_dict = {"location": "s3://test-bucket/test-key.json"}
66
+
67
+ with patch("xfintech.connect.artifact.artifact.ConnectRef.from_dict") as mock_from_dict:
68
+ mock_ref = MagicMock()
69
+ mock_from_dict.return_value = mock_ref
70
+
71
+ artifact = Artifact(ref=ref_dict)
72
+
73
+ mock_from_dict.assert_called_once_with(ref_dict)
74
+ assert artifact.ref == mock_ref
75
+
76
+
77
+ def test_artifact_init_with_data(mock_connect_ref):
78
+ """Test Artifact initialization with data"""
79
+ test_data = {"key": "value", "number": 123}
80
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
81
+
82
+ assert artifact.ref == mock_connect_ref
83
+ assert artifact.data == test_data
84
+ assert artifact.meta is None
85
+
86
+
87
+ def test_artifact_init_with_meta(mock_connect_ref):
88
+ """Test Artifact initialization with metadata"""
89
+ test_meta = {"author": "test", "version": "1.0"}
90
+ artifact = Artifact(ref=mock_connect_ref, meta=test_meta)
91
+
92
+ assert artifact.ref == mock_connect_ref
93
+ assert artifact.data is None
94
+ assert artifact.meta == test_meta
95
+ assert artifact.meta is not test_meta # Should be a copy
96
+
97
+
98
+ def test_artifact_init_with_all_params(mock_connect_ref):
99
+ """Test Artifact initialization with all parameters"""
100
+ test_data = {"key": "value"}
101
+ test_meta = {"author": "test"}
102
+
103
+ artifact = Artifact(ref=mock_connect_ref, data=test_data, meta=test_meta)
104
+
105
+ assert artifact.ref == mock_connect_ref
106
+ assert artifact.data == test_data
107
+ assert artifact.meta == test_meta
108
+
109
+
110
+ def test_artifact_init_with_invalid_ref_type():
111
+ """Test Artifact initialization with invalid ref type"""
112
+ with pytest.raises(TypeError, match="Invalid type for ref"):
113
+ Artifact(ref="invalid_string")
114
+
115
+
116
+ def test_artifact_init_with_none_ref():
117
+ """Test Artifact initialization with None ref"""
118
+ with pytest.raises(TypeError):
119
+ Artifact(ref=None)
120
+
121
+
122
+ def test_artifact_meta_is_copied(mock_connect_ref):
123
+ """Test that meta dict is copied, not referenced"""
124
+ original_meta = {"key": "value"}
125
+ artifact = Artifact(ref=mock_connect_ref, meta=original_meta)
126
+
127
+ # Modify original meta
128
+ original_meta["key"] = "changed"
129
+
130
+ # Artifact meta should be unchanged
131
+ assert artifact.meta["key"] == "value"
132
+
133
+
134
+ # ============================================================================
135
+ # from_dict Tests
136
+ # ============================================================================
137
+
138
+
139
+ def test_artifact_from_dict_basic():
140
+ """Test creating Artifact from dict with minimal data"""
141
+ ref_dict = {"location": "s3://test-bucket/test-key.json"}
142
+ artifact_dict = {"ref": ref_dict}
143
+
144
+ with patch("xfintech.connect.artifact.artifact.ConnectRef.from_dict") as mock_from_dict:
145
+ mock_ref = MagicMock()
146
+ mock_from_dict.return_value = mock_ref
147
+
148
+ artifact = Artifact.from_dict(artifact_dict)
149
+
150
+ assert artifact.ref == mock_ref
151
+ assert artifact.data is None
152
+ assert artifact.meta is None
153
+
154
+
155
+ def test_artifact_from_dict_with_data():
156
+ """Test creating Artifact from dict with data"""
157
+ ref_dict = {"location": "s3://test-bucket/test-key.json"}
158
+ test_data = {"key": "value"}
159
+ artifact_dict = {"ref": ref_dict, "data": test_data}
160
+
161
+ with patch("xfintech.connect.artifact.artifact.ConnectRef.from_dict") as mock_from_dict:
162
+ mock_ref = MagicMock()
163
+ mock_from_dict.return_value = mock_ref
164
+
165
+ artifact = Artifact.from_dict(artifact_dict)
166
+
167
+ assert artifact.data == test_data
168
+
169
+
170
+ def test_artifact_from_dict_with_meta():
171
+ """Test creating Artifact from dict with metadata"""
172
+ ref_dict = {"location": "s3://test-bucket/test-key.json"}
173
+ test_meta = {"author": "test"}
174
+ artifact_dict = {"ref": ref_dict, "meta": test_meta}
175
+
176
+ with patch("xfintech.connect.artifact.artifact.ConnectRef.from_dict") as mock_from_dict:
177
+ mock_ref = MagicMock()
178
+ mock_from_dict.return_value = mock_ref
179
+
180
+ artifact = Artifact.from_dict(artifact_dict)
181
+
182
+ assert artifact.meta == test_meta
183
+
184
+
185
+ def test_artifact_from_dict_missing_ref():
186
+ """Test from_dict raises error when ref is missing"""
187
+ artifact_dict = {"data": {"key": "value"}}
188
+
189
+ with pytest.raises(KeyError):
190
+ Artifact.from_dict(artifact_dict)
191
+
192
+
193
+ def test_artifact_from_dict_with_all_fields():
194
+ """Test creating Artifact from dict with all fields"""
195
+ ref_dict = {"location": "s3://test-bucket/test-key.json"}
196
+ test_data = {"key": "value"}
197
+ test_meta = {"author": "test", "version": "1.0"}
198
+ artifact_dict = {"ref": ref_dict, "data": test_data, "meta": test_meta}
199
+
200
+ with patch("xfintech.connect.artifact.artifact.ConnectRef.from_dict") as mock_from_dict:
201
+ mock_ref = MagicMock()
202
+ mock_from_dict.return_value = mock_ref
203
+
204
+ artifact = Artifact.from_dict(artifact_dict)
205
+
206
+ assert artifact.ref == mock_ref
207
+ assert artifact.data == test_data
208
+ assert artifact.meta == test_meta
209
+
210
+
211
+ # ============================================================================
212
+ # String Representation Tests
213
+ # ============================================================================
214
+
215
+
216
+ def test_artifact_str(mock_connect_ref):
217
+ """Test __str__ method"""
218
+ artifact = Artifact(ref=mock_connect_ref)
219
+
220
+ result = str(artifact)
221
+
222
+ assert result == str(mock_connect_ref)
223
+
224
+
225
+ def test_artifact_repr(mock_connect_ref):
226
+ """Test __repr__ method"""
227
+ artifact = Artifact(ref=mock_connect_ref)
228
+
229
+ result = repr(artifact)
230
+
231
+ assert "Artifact" in result
232
+ assert str(mock_connect_ref) in result
233
+
234
+
235
+ # ============================================================================
236
+ # write Method Tests
237
+ # ============================================================================
238
+
239
+
240
+ def test_artifact_write_basic(mock_connect_ref, mock_connect):
241
+ """Test basic write operation without serialisation"""
242
+ test_data = {"key": "value"}
243
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
244
+
245
+ artifact.write(connect=mock_connect)
246
+
247
+ mock_connect.put_object.assert_called_once_with(
248
+ data=test_data,
249
+ location=mock_connect_ref.location,
250
+ )
251
+
252
+
253
+ def test_artifact_write_with_serialiser(mock_connect_ref, mock_connect, mock_serialiser):
254
+ """Test write operation with serialiser"""
255
+ test_data = {"key": "value"}
256
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
257
+
258
+ artifact.write(connect=mock_connect, serialiser=mock_serialiser, format="json")
259
+
260
+ mock_serialiser.serialise.assert_called_once_with(
261
+ test_data,
262
+ format="json",
263
+ )
264
+ mock_connect.put_object.assert_called_once()
265
+
266
+
267
+ def test_artifact_write_no_data(mock_connect_ref, mock_connect):
268
+ """Test write raises error when no data"""
269
+ artifact = Artifact(ref=mock_connect_ref)
270
+
271
+ with pytest.raises(ValueError, match="No data to write"):
272
+ artifact.write(connect=mock_connect)
273
+
274
+
275
+ def test_artifact_write_updates_ref(mock_connect_ref, mock_connect):
276
+ """Test write updates the ref with returned value"""
277
+ test_data = {"key": "value"}
278
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
279
+
280
+ new_ref = MagicMock()
281
+ new_ref.location = "s3://test-bucket/new-key.json"
282
+ mock_connect.put_object.return_value = new_ref
283
+
284
+ artifact.write(connect=mock_connect)
285
+
286
+ assert artifact.ref == new_ref
287
+
288
+
289
+ def test_artifact_write_with_kwargs(mock_connect_ref, mock_connect):
290
+ """Test write passes through kwargs"""
291
+ test_data = {"key": "value"}
292
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
293
+
294
+ artifact.write(connect=mock_connect, custom_param="value")
295
+
296
+ mock_connect.put_object.assert_called_once_with(
297
+ data=test_data,
298
+ location=mock_connect_ref.location,
299
+ custom_param="value",
300
+ )
301
+
302
+
303
+ def test_artifact_write_serialiser_error(mock_connect_ref, mock_connect, mock_serialiser):
304
+ """Test write handles serialiser errors"""
305
+ test_data = {"key": "value"}
306
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
307
+
308
+ mock_serialiser.serialise.side_effect = Exception("Serialisation failed")
309
+
310
+ with pytest.raises(Exception, match="Failed to write artifact"):
311
+ artifact.write(connect=mock_connect, serialiser=mock_serialiser, format="json")
312
+
313
+
314
+ def test_artifact_write_connect_error(mock_connect_ref, mock_connect):
315
+ """Test write handles connection errors"""
316
+ test_data = {"key": "value"}
317
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
318
+
319
+ mock_connect.put_object.side_effect = Exception("Connection failed")
320
+
321
+ with pytest.raises(Exception, match="Failed to write artifact"):
322
+ artifact.write(connect=mock_connect)
323
+
324
+
325
+ # ============================================================================
326
+ # read Method Tests
327
+ # ============================================================================
328
+
329
+
330
+ def test_artifact_read_basic(mock_connect_ref, mock_connect):
331
+ """Test basic read operation without deserialisation"""
332
+ artifact = Artifact(ref=mock_connect_ref)
333
+
334
+ result = artifact.read(connect=mock_connect)
335
+
336
+ mock_connect.get_object.assert_called_once_with(
337
+ location=mock_connect_ref.location,
338
+ )
339
+ assert artifact.data == b'{"key": "value"}'
340
+ assert result is artifact # Should return self
341
+
342
+
343
+ def test_artifact_read_with_deserialiser(mock_connect_ref, mock_connect, mock_deserialiser):
344
+ """Test read operation with deserialiser"""
345
+ artifact = Artifact(ref=mock_connect_ref)
346
+
347
+ artifact.read(connect=mock_connect, deserialiser=mock_deserialiser, format="json")
348
+
349
+ mock_connect.get_object.assert_called_once()
350
+ mock_deserialiser.deserialise.assert_called_once_with(
351
+ b'{"key": "value"}',
352
+ format="json",
353
+ )
354
+ assert artifact.data == {"deserialised": True}
355
+
356
+
357
+ def test_artifact_read_with_kwargs(mock_connect_ref, mock_connect):
358
+ """Test read passes through kwargs"""
359
+ artifact = Artifact(ref=mock_connect_ref)
360
+
361
+ artifact.read(connect=mock_connect, custom_param="value")
362
+
363
+ mock_connect.get_object.assert_called_once_with(
364
+ location=mock_connect_ref.location,
365
+ custom_param="value",
366
+ )
367
+
368
+
369
+ def test_artifact_read_returns_self(mock_connect_ref, mock_connect):
370
+ """Test read returns self for chaining"""
371
+ artifact = Artifact(ref=mock_connect_ref)
372
+
373
+ result = artifact.read(connect=mock_connect)
374
+
375
+ assert result is artifact
376
+
377
+
378
+ def test_artifact_read_connect_error(mock_connect_ref, mock_connect):
379
+ """Test read handles connection errors"""
380
+ artifact = Artifact(ref=mock_connect_ref)
381
+
382
+ mock_connect.get_object.side_effect = Exception("Connection failed")
383
+
384
+ with pytest.raises(Exception, match="Failed to read artifact"):
385
+ artifact.read(connect=mock_connect)
386
+
387
+
388
+ def test_artifact_read_deserialiser_error(mock_connect_ref, mock_connect, mock_deserialiser):
389
+ """Test read handles deserialiser errors"""
390
+ artifact = Artifact(ref=mock_connect_ref)
391
+
392
+ mock_deserialiser.deserialise.side_effect = Exception("Deserialisation failed")
393
+
394
+ with pytest.raises(Exception, match="Failed to read artifact"):
395
+ artifact.read(connect=mock_connect, deserialiser=mock_deserialiser, format="json")
396
+
397
+
398
+ # ============================================================================
399
+ # describe Method Tests
400
+ # ============================================================================
401
+
402
+
403
+ def test_artifact_describe_basic(mock_connect_ref):
404
+ """Test describe method with minimal data"""
405
+ artifact = Artifact(ref=mock_connect_ref)
406
+
407
+ result = artifact.describe()
408
+
409
+ assert "ref" in result
410
+ mock_connect_ref.describe.assert_called_once()
411
+
412
+
413
+ def test_artifact_describe_with_meta(mock_connect_ref):
414
+ """Test describe includes metadata"""
415
+ test_meta = {"author": "test", "version": "1.0"}
416
+ artifact = Artifact(ref=mock_connect_ref, meta=test_meta)
417
+
418
+ result = artifact.describe()
419
+
420
+ assert "ref" in result
421
+ assert "meta" in result
422
+ assert result["meta"] == test_meta
423
+
424
+
425
+ def test_artifact_describe_with_data(mock_connect_ref):
426
+ """Test describe includes data type"""
427
+ test_data = {"key": "value"}
428
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
429
+
430
+ result = artifact.describe()
431
+
432
+ assert "ref" in result
433
+ assert "data_type" in result
434
+ assert result["data_type"] == "dict"
435
+
436
+
437
+ def test_artifact_describe_with_all_fields(mock_connect_ref):
438
+ """Test describe with all fields present"""
439
+ test_data = {"key": "value"}
440
+ test_meta = {"author": "test"}
441
+ artifact = Artifact(ref=mock_connect_ref, data=test_data, meta=test_meta)
442
+
443
+ result = artifact.describe()
444
+
445
+ assert "ref" in result
446
+ assert "meta" in result
447
+ assert "data_type" in result
448
+
449
+
450
+ def test_artifact_describe_ref_without_method(mock_connect_ref):
451
+ """Test describe handles ref without describe method"""
452
+ mock_connect_ref.describe = None
453
+ artifact = Artifact(ref=mock_connect_ref)
454
+
455
+ result = artifact.describe()
456
+
457
+ assert "ref" in result
458
+ assert isinstance(result["ref"], str)
459
+
460
+
461
+ # ============================================================================
462
+ # to_dict Method Tests
463
+ # ============================================================================
464
+
465
+
466
+ def test_artifact_to_dict_basic(mock_connect_ref):
467
+ """Test to_dict method with minimal data"""
468
+ artifact = Artifact(ref=mock_connect_ref)
469
+
470
+ result = artifact.to_dict()
471
+
472
+ assert "ref" in result
473
+ mock_connect_ref.to_dict.assert_called_once()
474
+
475
+
476
+ def test_artifact_to_dict_with_meta(mock_connect_ref):
477
+ """Test to_dict includes metadata"""
478
+ test_meta = {"author": "test"}
479
+ artifact = Artifact(ref=mock_connect_ref, meta=test_meta)
480
+
481
+ result = artifact.to_dict()
482
+
483
+ assert "ref" in result
484
+ assert "meta" in result
485
+ assert result["meta"] == test_meta
486
+
487
+
488
+ def test_artifact_to_dict_with_data(mock_connect_ref):
489
+ """Test to_dict includes data"""
490
+ test_data = {"key": "value"}
491
+ artifact = Artifact(ref=mock_connect_ref, data=test_data)
492
+
493
+ result = artifact.to_dict()
494
+
495
+ assert "ref" in result
496
+ assert "data" in result
497
+ assert result["data"] == test_data
498
+
499
+
500
+ def test_artifact_to_dict_round_trip(mock_connect_ref):
501
+ """Test from_dict and to_dict round trip"""
502
+ test_data = {"key": "value"}
503
+ test_meta = {"author": "test"}
504
+ artifact1 = Artifact(ref=mock_connect_ref, data=test_data, meta=test_meta)
505
+
506
+ # Mock to_dict to return a dict
507
+ mock_connect_ref.to_dict.return_value = {"location": "s3://test-bucket/test-key.json"}
508
+
509
+ artifact_dict = artifact1.to_dict()
510
+
511
+ with patch("xfintech.connect.artifact.artifact.ConnectRef.from_dict") as mock_from_dict:
512
+ mock_from_dict.return_value = mock_connect_ref
513
+
514
+ artifact2 = Artifact.from_dict(artifact_dict)
515
+
516
+ assert artifact2.data == test_data
517
+ assert artifact2.meta == test_meta
518
+
519
+
520
+ def test_artifact_to_dict_ref_without_method(mock_connect_ref):
521
+ """Test to_dict handles ref without to_dict method"""
522
+ mock_connect_ref.to_dict = None
523
+ artifact = Artifact(ref=mock_connect_ref)
524
+
525
+ result = artifact.to_dict()
526
+
527
+ assert "ref" in result
528
+ assert isinstance(result["ref"], str)
529
+
530
+
531
+ # ============================================================================
532
+ # Integration Tests
533
+ # ============================================================================
534
+
535
+
536
+ def test_artifact_write_read_workflow(mock_connect_ref, mock_connect, mock_serialiser, mock_deserialiser):
537
+ """Test complete write and read workflow"""
538
+ test_data = {"key": "value", "number": 123}
539
+
540
+ # Write
541
+ artifact1 = Artifact(ref=mock_connect_ref, data=test_data)
542
+ artifact1.write(connect=mock_connect, serialiser=mock_serialiser, format="json")
543
+
544
+ # Read
545
+ artifact2 = Artifact(ref=mock_connect_ref)
546
+ artifact2.read(connect=mock_connect, deserialiser=mock_deserialiser, format="json")
547
+
548
+ assert artifact2.data == {"deserialised": True}
549
+
550
+
551
+ def test_artifact_with_metadata_workflow(mock_connect_ref):
552
+ """Test artifact with metadata through its lifecycle"""
553
+ test_data = {"key": "value"}
554
+ test_meta = {"author": "test", "version": "1.0", "created": "2026-01-08"}
555
+
556
+ artifact = Artifact(ref=mock_connect_ref, data=test_data, meta=test_meta)
557
+
558
+ # Verify metadata is preserved
559
+ description = artifact.describe()
560
+ assert description["meta"] == test_meta
561
+
562
+ # Verify metadata in dict representation
563
+ artifact_dict = artifact.to_dict()
564
+ assert artifact_dict["meta"] == test_meta
@@ -0,0 +1,12 @@
1
+ from .connect import ConnectLike
2
+ from .connectref import ConnectRef, ConnectRefLike
3
+ from .error import ConnectFailedError, ConnectKeyError, ConnectRefKeyError
4
+
5
+ __all__ = [
6
+ "ConnectLike",
7
+ "ConnectRef",
8
+ "ConnectRefLike",
9
+ "ConnectRefKeyError",
10
+ "ConnectKeyError",
11
+ "ConnectFailedError",
12
+ ]
@@ -0,0 +1,49 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Protocol, runtime_checkable
4
+
5
+ from xfintech.connect.common.connectref import ConnectRef
6
+
7
+
8
+ @runtime_checkable
9
+ class ConnectLike(Protocol):
10
+ """
11
+ 描述:
12
+ - 连接接口协议,定义存储连接的基本操作。
13
+ - 支持对象的读取和写入操作。
14
+ - 实现类可以是 S3、本地文件系统或其他存储后端。
15
+ - 使用 @runtime_checkable 装饰器支持运行时类型检查。
16
+
17
+ 方法:
18
+ - get_object(location, **kwargs): 从指定位置获取对象数据。
19
+ - put_object(data, location, **kwargs): 将数据写入指定位置并返回引用。
20
+
21
+ 例子:
22
+ ```python
23
+ from xfintech.connect.common.connect import ConnectLike
24
+
25
+ class MyConnect:
26
+ def get_object(self, location: str, **kwargs) -> bytes:
27
+ return b"data"
28
+
29
+ def put_object(self, data: bytes, location: str, **kwargs) -> ConnectRef:
30
+ return ConnectRef(location=location)
31
+
32
+ # 运行时检查
33
+ connect = MyConnect()
34
+ assert isinstance(connect, ConnectLike)
35
+ ```
36
+ """
37
+
38
+ def get_object(
39
+ self,
40
+ location: str,
41
+ **kwargs: Any,
42
+ ) -> bytes: ...
43
+
44
+ def put_object(
45
+ self,
46
+ data: bytes,
47
+ location: str,
48
+ **kwargs: Any,
49
+ ) -> ConnectRef: ...