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,524 @@
1
+ """
2
+ 描述:
3
+ - xfintech.connect.common.error 模块的单元测试。
4
+ - 测试所有自定义异常类的继承、实例化和使用。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import pytest
10
+
11
+ from xfintech.connect.common.error import (
12
+ ConnectFailedError,
13
+ ConnectKeyError,
14
+ ConnectRefKeyError,
15
+ )
16
+
17
+ # =============================================================================
18
+ # ConnectRefKeyError Tests
19
+ # =============================================================================
20
+
21
+
22
+ def test_connectrefkeyerror_inherits_from_keyerror():
23
+ """测试 ConnectRefKeyError 继承自 KeyError"""
24
+ assert issubclass(ConnectRefKeyError, KeyError)
25
+
26
+
27
+ def test_connectrefkeyerror_can_instantiate():
28
+ """测试可以实例化 ConnectRefKeyError"""
29
+ error = ConnectRefKeyError("Test message")
30
+ assert isinstance(error, ConnectRefKeyError)
31
+ assert isinstance(error, KeyError)
32
+
33
+
34
+ def test_connectrefkeyerror_can_raise():
35
+ """测试可以抛出 ConnectRefKeyError"""
36
+ with pytest.raises(ConnectRefKeyError):
37
+ raise ConnectRefKeyError("Missing required key")
38
+
39
+
40
+ def test_connectrefkeyerror_message():
41
+ """测试 ConnectRefKeyError 消息"""
42
+ msg = "'location' is required in data"
43
+ error = ConnectRefKeyError(msg)
44
+ # KeyError wraps message in quotes
45
+ assert msg in str(error)
46
+
47
+
48
+ def test_connectrefkeyerror_can_catch_as_keyerror():
49
+ """测试可以作为 KeyError 捕获"""
50
+ with pytest.raises(KeyError):
51
+ raise ConnectRefKeyError("Missing key")
52
+
53
+
54
+ def test_connectrefkeyerror_empty_message():
55
+ """测试空消息"""
56
+ error = ConnectRefKeyError()
57
+ assert isinstance(error, ConnectRefKeyError)
58
+
59
+
60
+ def test_connectrefkeyerror_with_multiple_args():
61
+ """测试多参数实例化"""
62
+ error = ConnectRefKeyError("Error", "Extra info")
63
+ assert len(error.args) == 2
64
+
65
+
66
+ def test_connectrefkeyerror_use_case():
67
+ """测试实际使用场景"""
68
+
69
+ def validate_data(data):
70
+ if "location" not in data:
71
+ raise ConnectRefKeyError("'location' is required in data")
72
+
73
+ with pytest.raises(ConnectRefKeyError) as excinfo:
74
+ validate_data({"kind": "s3"})
75
+ assert "'location' is required in data" in str(excinfo.value)
76
+
77
+
78
+ def test_connectrefkeyerror_in_dict_access():
79
+ """测试在字典访问中使用"""
80
+
81
+ def get_location(data):
82
+ try:
83
+ return data["location"]
84
+ except KeyError:
85
+ raise ConnectRefKeyError("location key missing")
86
+
87
+ with pytest.raises(ConnectRefKeyError):
88
+ get_location({})
89
+
90
+
91
+ def test_connectrefkeyerror_with_cause():
92
+ """测试带原因链的异常"""
93
+ original = KeyError("original")
94
+ try:
95
+ raise ConnectRefKeyError("wrapped") from original
96
+ except ConnectRefKeyError as e:
97
+ assert e.__cause__ is original
98
+
99
+
100
+ # =============================================================================
101
+ # ConnectKeyError Tests
102
+ # =============================================================================
103
+
104
+
105
+ def test_connectkeyerror_inherits_from_keyerror():
106
+ """测试 ConnectKeyError 继承自 KeyError"""
107
+ assert issubclass(ConnectKeyError, KeyError)
108
+
109
+
110
+ def test_connectkeyerror_can_instantiate():
111
+ """测试可以实例化 ConnectKeyError"""
112
+ error = ConnectKeyError("Test message")
113
+ assert isinstance(error, ConnectKeyError)
114
+ assert isinstance(error, KeyError)
115
+
116
+
117
+ def test_connectkeyerror_can_raise():
118
+ """测试可以抛出 ConnectKeyError"""
119
+ with pytest.raises(ConnectKeyError):
120
+ raise ConnectKeyError("Invalid key")
121
+
122
+
123
+ def test_connectkeyerror_message():
124
+ """测试 ConnectKeyError 消息"""
125
+ msg = "location cannot be None"
126
+ error = ConnectKeyError(msg)
127
+ assert msg in str(error)
128
+
129
+
130
+ def test_connectkeyerror_can_catch_as_keyerror():
131
+ """测试可以作为 KeyError 捕获"""
132
+ with pytest.raises(KeyError):
133
+ raise ConnectKeyError("Key error")
134
+
135
+
136
+ def test_connectkeyerror_empty_message():
137
+ """测试空消息"""
138
+ error = ConnectKeyError()
139
+ assert isinstance(error, ConnectKeyError)
140
+
141
+
142
+ def test_connectkeyerror_with_multiple_args():
143
+ """测试多参数实例化"""
144
+ error = ConnectKeyError("Error", "Extra")
145
+ assert len(error.args) == 2
146
+
147
+
148
+ def test_connectkeyerror_use_case():
149
+ """测试实际使用场景"""
150
+
151
+ def validate_location(location):
152
+ if location is None:
153
+ raise ConnectKeyError("location cannot be None")
154
+ if not location:
155
+ raise ConnectKeyError("location cannot be empty")
156
+
157
+ with pytest.raises(ConnectKeyError) as excinfo:
158
+ validate_location(None)
159
+ assert "cannot be None" in str(excinfo.value)
160
+
161
+ with pytest.raises(ConnectKeyError) as excinfo:
162
+ validate_location("")
163
+ assert "cannot be empty" in str(excinfo.value)
164
+
165
+
166
+ def test_connectkeyerror_in_validation():
167
+ """测试在验证逻辑中使用"""
168
+
169
+ def check_required_keys(data, required):
170
+ for key in required:
171
+ if key not in data:
172
+ raise ConnectKeyError(f"Required key missing: {key}")
173
+
174
+ with pytest.raises(ConnectKeyError, match="location"):
175
+ check_required_keys({"kind": "s3"}, ["location", "kind"])
176
+
177
+
178
+ def test_connectkeyerror_with_cause():
179
+ """测试带原因链的异常"""
180
+ original = ValueError("Invalid value")
181
+ try:
182
+ raise ConnectKeyError("Key invalid") from original
183
+ except ConnectKeyError as e:
184
+ assert e.__cause__ is original
185
+
186
+
187
+ # =============================================================================
188
+ # ConnectFailedError Tests
189
+ # =============================================================================
190
+
191
+
192
+ def test_connectfailederror_inherits_from_exception():
193
+ """测试 ConnectFailedError 继承自 Exception"""
194
+ assert issubclass(ConnectFailedError, Exception)
195
+
196
+
197
+ def test_connectfailederror_not_keyerror():
198
+ """测试不是 KeyError"""
199
+ assert not issubclass(ConnectFailedError, KeyError)
200
+
201
+
202
+ def test_connectfailederror_can_instantiate():
203
+ """测试可以实例化 ConnectFailedError"""
204
+ error = ConnectFailedError("Test message")
205
+ assert isinstance(error, ConnectFailedError)
206
+ assert isinstance(error, Exception)
207
+
208
+
209
+ def test_connectfailederror_can_raise():
210
+ """测试可以抛出 ConnectFailedError"""
211
+ with pytest.raises(ConnectFailedError):
212
+ raise ConnectFailedError("Operation failed")
213
+
214
+
215
+ def test_connectfailederror_message():
216
+ """测试 ConnectFailedError 消息"""
217
+ msg = "Failed to read file"
218
+ error = ConnectFailedError(msg)
219
+ assert str(error) == msg
220
+
221
+
222
+ def test_connectfailederror_can_catch_as_exception():
223
+ """测试可以作为 Exception 捕获"""
224
+ with pytest.raises(Exception):
225
+ raise ConnectFailedError("Failed")
226
+
227
+
228
+ def test_connectfailederror_empty_message():
229
+ """测试空消息"""
230
+ error = ConnectFailedError()
231
+ assert isinstance(error, ConnectFailedError)
232
+
233
+
234
+ def test_connectfailederror_with_multiple_args():
235
+ """测试多参数实例化"""
236
+ error = ConnectFailedError("Error", "Details")
237
+ assert len(error.args) == 2
238
+
239
+
240
+ def test_connectfailederror_use_case_read():
241
+ """测试读取失败场景"""
242
+
243
+ def read_file(path):
244
+ try:
245
+ with open(path, "rb") as f:
246
+ return f.read()
247
+ except Exception as e:
248
+ raise ConnectFailedError(f"Failed to read {path}: {e}") from e
249
+
250
+ with pytest.raises(ConnectFailedError) as excinfo:
251
+ read_file("/nonexistent/file.txt")
252
+ assert "Failed to read" in str(excinfo.value)
253
+
254
+
255
+ def test_connectfailederror_use_case_write():
256
+ """测试写入失败场景"""
257
+
258
+ def write_file(path, data):
259
+ try:
260
+ with open(path, "wb") as f:
261
+ f.write(data)
262
+ except Exception as e:
263
+ raise ConnectFailedError(f"Failed to write {path}: {e}") from e
264
+
265
+ with pytest.raises(ConnectFailedError) as excinfo:
266
+ write_file("/invalid/path/file.txt", b"data")
267
+ assert "Failed to write" in str(excinfo.value)
268
+
269
+
270
+ def test_connectfailederror_with_cause():
271
+ """测试带原因链的异常"""
272
+ original = IOError("File not found")
273
+ try:
274
+ raise ConnectFailedError("Operation failed") from original
275
+ except ConnectFailedError as e:
276
+ assert e.__cause__ is original
277
+ assert isinstance(e.__cause__, IOError)
278
+
279
+
280
+ def test_connectfailederror_nested_exception():
281
+ """测试嵌套异常"""
282
+ try:
283
+ try:
284
+ raise ValueError("Inner error")
285
+ except ValueError as ve:
286
+ raise ConnectFailedError("Outer error") from ve
287
+ except ConnectFailedError as e:
288
+ assert isinstance(e.__cause__, ValueError)
289
+
290
+
291
+ # =============================================================================
292
+ # Cross-Error Tests
293
+ # =============================================================================
294
+
295
+
296
+ def test_all_errors_are_distinct():
297
+ """测试所有错误类是不同的"""
298
+ assert ConnectRefKeyError is not ConnectKeyError
299
+ assert ConnectRefKeyError is not ConnectFailedError
300
+ assert ConnectKeyError is not ConnectFailedError
301
+
302
+
303
+ def test_error_hierarchy():
304
+ """测试错误层次结构"""
305
+ # Both KeyError subclasses
306
+ assert issubclass(ConnectRefKeyError, KeyError)
307
+ assert issubclass(ConnectKeyError, KeyError)
308
+
309
+ # But not subclasses of each other
310
+ assert not issubclass(ConnectRefKeyError, ConnectKeyError)
311
+ assert not issubclass(ConnectKeyError, ConnectRefKeyError)
312
+
313
+ # ConnectFailedError is separate
314
+ assert not issubclass(ConnectFailedError, KeyError)
315
+ assert not issubclass(ConnectFailedError, ConnectRefKeyError)
316
+ assert not issubclass(ConnectFailedError, ConnectKeyError)
317
+
318
+
319
+ def test_can_catch_multiple_keyerrors():
320
+ """测试可以捕获多个 KeyError 子类"""
321
+
322
+ def raise_ref_key_error():
323
+ raise ConnectRefKeyError("ref error")
324
+
325
+ def raise_connect_key_error():
326
+ raise ConnectKeyError("connect error")
327
+
328
+ # Can catch both as KeyError
329
+ with pytest.raises(KeyError):
330
+ raise_ref_key_error()
331
+
332
+ with pytest.raises(KeyError):
333
+ raise_connect_key_error()
334
+
335
+
336
+ def test_specific_error_catching():
337
+ """测试特定错误捕获"""
338
+
339
+ def operation(error_type):
340
+ if error_type == "ref":
341
+ raise ConnectRefKeyError("ref error")
342
+ elif error_type == "key":
343
+ raise ConnectKeyError("key error")
344
+ else:
345
+ raise ConnectFailedError("failed")
346
+
347
+ # Catch specific errors
348
+ with pytest.raises(ConnectRefKeyError):
349
+ operation("ref")
350
+
351
+ with pytest.raises(ConnectKeyError):
352
+ operation("key")
353
+
354
+ with pytest.raises(ConnectFailedError):
355
+ operation("failed")
356
+
357
+
358
+ def test_error_catching_order():
359
+ """测试错误捕获顺序"""
360
+
361
+ def risky_operation():
362
+ raise ConnectRefKeyError("error")
363
+
364
+ # Specific catches first
365
+ caught_specific = False
366
+ caught_general = False
367
+
368
+ try:
369
+ risky_operation()
370
+ except ConnectRefKeyError:
371
+ caught_specific = True
372
+ except KeyError:
373
+ caught_general = True
374
+
375
+ assert caught_specific
376
+ assert not caught_general
377
+
378
+
379
+ # =============================================================================
380
+ # Error Message Tests
381
+ # =============================================================================
382
+
383
+
384
+ def test_error_messages_are_preserved():
385
+ """测试错误消息被保留"""
386
+ messages = [
387
+ "Simple message",
388
+ "Message with 'quotes'",
389
+ "Unicode message: 测试错误",
390
+ "Long " + "x" * 1000 + " message",
391
+ ]
392
+
393
+ for msg in messages:
394
+ e1 = ConnectRefKeyError(msg)
395
+ e2 = ConnectKeyError(msg)
396
+ e3 = ConnectFailedError(msg)
397
+
398
+ # For KeyError subclasses, message might be wrapped
399
+ assert msg in str(e1) or msg in repr(e1) or msg.replace("'", "\\'") in str(e1)
400
+ assert msg in str(e2) or msg in repr(e2) or msg.replace("'", "\\'") in str(e2)
401
+ assert msg in str(e3)
402
+
403
+
404
+ def test_formatted_error_messages():
405
+ """测试格式化的错误消息"""
406
+ location = "/path/to/file"
407
+ error = ConnectFailedError(f"Failed to access {location}")
408
+ assert location in str(error)
409
+
410
+
411
+ # =============================================================================
412
+ # Practical Workflow Tests
413
+ # =============================================================================
414
+
415
+
416
+ def test_connect_workflow_errors():
417
+ """测试连接工作流中的错误处理"""
418
+
419
+ def connect_operation(location):
420
+ # Validation
421
+ if not location:
422
+ raise ConnectKeyError("location is required")
423
+
424
+ # Try operation
425
+ try:
426
+ # Simulate operation
427
+ if location == "invalid":
428
+ raise IOError("Cannot access")
429
+ except IOError as e:
430
+ raise ConnectFailedError(f"Operation failed: {e}") from e
431
+
432
+ # Test validation error
433
+ with pytest.raises(ConnectKeyError):
434
+ connect_operation("")
435
+
436
+ # Test operation error
437
+ with pytest.raises(ConnectFailedError):
438
+ connect_operation("invalid")
439
+
440
+
441
+ def test_ref_creation_workflow_errors():
442
+ """测试引用创建工作流中的错误处理"""
443
+
444
+ def create_ref_from_data(data):
445
+ if "location" not in data:
446
+ raise ConnectRefKeyError("'location' is required")
447
+
448
+ location = data["location"]
449
+ if not location:
450
+ raise ConnectKeyError("location cannot be empty")
451
+
452
+ # Simulate ref creation succeeds
453
+ return {"location": location, "kind": data.get("kind")}
454
+
455
+ # Test missing location
456
+ with pytest.raises(ConnectRefKeyError):
457
+ create_ref_from_data({"kind": "s3"})
458
+
459
+ # Test empty location
460
+ with pytest.raises(ConnectKeyError):
461
+ create_ref_from_data({"location": ""})
462
+
463
+ # Test success
464
+ result = create_ref_from_data({"location": "test"})
465
+ assert result["location"] == "test"
466
+
467
+
468
+ def test_error_context_preservation():
469
+ """测试错误上下文保留"""
470
+
471
+ def inner_operation():
472
+ raise ValueError("Inner error with details")
473
+
474
+ def outer_operation():
475
+ try:
476
+ inner_operation()
477
+ except ValueError as e:
478
+ raise ConnectFailedError("Outer operation failed") from e
479
+
480
+ with pytest.raises(ConnectFailedError) as excinfo:
481
+ outer_operation()
482
+
483
+ error = excinfo.value
484
+ assert error.__cause__ is not None
485
+ assert isinstance(error.__cause__, ValueError)
486
+ assert "Inner error" in str(error.__cause__)
487
+
488
+
489
+ # =============================================================================
490
+ # Error Module Tests
491
+ # =============================================================================
492
+
493
+
494
+ def test_all_errors_importable():
495
+ """测试所有错误可以导入"""
496
+ from xfintech.connect.common.error import (
497
+ ConnectFailedError,
498
+ ConnectKeyError,
499
+ ConnectRefKeyError,
500
+ )
501
+
502
+ assert ConnectRefKeyError is not None
503
+ assert ConnectKeyError is not None
504
+ assert ConnectFailedError is not None
505
+
506
+
507
+ def test_error_module_has_all_classes():
508
+ """测试错误模块包含所有类"""
509
+ import xfintech.connect.common.error as error_module
510
+
511
+ assert hasattr(error_module, "ConnectRefKeyError")
512
+ assert hasattr(error_module, "ConnectKeyError")
513
+ assert hasattr(error_module, "ConnectFailedError")
514
+
515
+
516
+ def test_errors_have_docstrings():
517
+ """测试错误类有文档字符串"""
518
+ assert ConnectRefKeyError.__doc__ is not None
519
+ assert ConnectKeyError.__doc__ is not None
520
+ assert ConnectFailedError.__doc__ is not None
521
+
522
+ assert len(ConnectRefKeyError.__doc__) > 0
523
+ assert len(ConnectKeyError.__doc__) > 0
524
+ assert len(ConnectFailedError.__doc__) > 0
@@ -0,0 +1,7 @@
1
+ from .macos import MacOSConnect
2
+ from .s3 import S3Connect
3
+
4
+ __all__ = [
5
+ "MacOSConnect",
6
+ "S3Connect",
7
+ ]
@@ -0,0 +1,121 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Union
5
+
6
+ from xfintech.connect.common.connect import ConnectLike
7
+ from xfintech.connect.common.connectref import ConnectRef
8
+ from xfintech.connect.common.error import ConnectFailedError, ConnectKeyError
9
+
10
+
11
+ class MacOSConnect(ConnectLike):
12
+ """
13
+ 描述:
14
+ - macOS 本地文件系统连接实现类。
15
+ - 实现了 ConnectLike 协议,用于与本地文件系统进行交互。
16
+ - 支持读取和写入本地文件。
17
+ - 自动处理路径解析、用户目录展开和父目录创建。
18
+ - 适用于 macOS 和其他 Unix-like 系统。
19
+
20
+ 属性:
21
+ - kind: 连接类型标识,固定为 "macos"。
22
+
23
+ 例子:
24
+ ```python
25
+ from xfintech.connect.instance.macos import MacOSConnect
26
+
27
+ connect = MacOSConnect()
28
+
29
+ # 写入数据到本地文件
30
+ ref = connect.put_object(b"data", "/path/to/file.txt")
31
+
32
+ # 读取本地文件
33
+ data = connect.get_object("/path/to/file.txt")
34
+
35
+ # 使用 Path 对象
36
+ from pathlib import Path
37
+ ref = connect.put_object(b"data", Path("~/data/file.txt"))
38
+
39
+ # 支持用户目录展开
40
+ data = connect.get_object("~/documents/data.bin")
41
+ ```
42
+ """
43
+
44
+ def __init__(self) -> None:
45
+ self.kind: str = "macos"
46
+
47
+ def _resolve_path(
48
+ self,
49
+ location: Union[str, Path],
50
+ ) -> Path:
51
+ if location is None:
52
+ msg = "location cannot be None"
53
+ raise ConnectKeyError(msg)
54
+ if isinstance(location, Path):
55
+ location = location
56
+ else:
57
+ location = Path(location)
58
+ location = location.expanduser().resolve(strict=False)
59
+ location.parent.mkdir(
60
+ parents=True,
61
+ exist_ok=True,
62
+ )
63
+ return location
64
+
65
+ def __str__(self) -> str:
66
+ return f"{self.__class__.__name__}"
67
+
68
+ def __repr__(self) -> str:
69
+ return f"{self.__class__.__name__}()"
70
+
71
+ def put_bytes(
72
+ self,
73
+ data: bytes,
74
+ location: Union[str, Path],
75
+ **kwargs: Any,
76
+ ) -> None:
77
+ path = self._resolve_path(location)
78
+ try:
79
+ with path.open("wb") as f:
80
+ f.write(data)
81
+ except Exception as e:
82
+ raise ConnectFailedError(str(e)) from e
83
+
84
+ def get_bytes(
85
+ self,
86
+ location: Union[str, Path],
87
+ **kwargs: Any,
88
+ ) -> bytes:
89
+ path = self._resolve_path(location)
90
+ try:
91
+ with path.open("rb") as f:
92
+ data = f.read()
93
+ return data
94
+ except Exception as e:
95
+ raise ConnectFailedError(str(e)) from e
96
+
97
+ def get_object(
98
+ self,
99
+ location: str,
100
+ **kwargs: Any,
101
+ ) -> bytes:
102
+ return self.get_bytes(
103
+ location,
104
+ **kwargs,
105
+ )
106
+
107
+ def put_object(
108
+ self,
109
+ data: bytes,
110
+ location: str,
111
+ **kwargs: Any,
112
+ ) -> ConnectRef:
113
+ self.put_bytes(
114
+ data,
115
+ location,
116
+ **kwargs,
117
+ )
118
+ return ConnectRef(
119
+ location=str(location),
120
+ kind=self.kind,
121
+ )