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,544 @@
1
+ """
2
+ 描述:
3
+ - ConnectLike 协议的单元测试。
4
+ - 测试协议的结构、实现和运行时类型检查。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ import pytest
12
+
13
+ from xfintech.connect.common.connect import ConnectLike
14
+ from xfintech.connect.common.connectref import ConnectRef
15
+
16
+ # =============================================================================
17
+ # Protocol Structure Tests
18
+ # =============================================================================
19
+
20
+
21
+ def test_connectlike_is_protocol():
22
+ """测试 ConnectLike 是一个协议类"""
23
+ from typing import Protocol
24
+
25
+ assert issubclass(ConnectLike.__class__, type(Protocol))
26
+
27
+
28
+ def test_connectlike_is_runtime_checkable():
29
+ """测试 ConnectLike 是运行时可检查的"""
30
+ # Check for protocol marker attributes that exist in Python 3.8+
31
+ assert hasattr(ConnectLike, "_is_protocol") or hasattr(ConnectLike, "__protocol_attrs__")
32
+
33
+
34
+ def test_connectlike_has_get_object_method():
35
+ """测试 ConnectLike 定义了 get_object 方法"""
36
+ assert hasattr(ConnectLike, "get_object")
37
+
38
+
39
+ def test_connectlike_has_put_object_method():
40
+ """测试 ConnectLike 定义了 put_object 方法"""
41
+ assert hasattr(ConnectLike, "put_object")
42
+
43
+
44
+ def test_connectlike_method_signatures():
45
+ """测试方法签名"""
46
+ import inspect
47
+
48
+ # Check get_object signature
49
+ get_sig = inspect.signature(ConnectLike.get_object)
50
+ get_params = list(get_sig.parameters.keys())
51
+ assert "self" in get_params
52
+ assert "location" in get_params
53
+ assert "kwargs" in get_params
54
+
55
+ # Check put_object signature
56
+ put_sig = inspect.signature(ConnectLike.put_object)
57
+ put_params = list(put_sig.parameters.keys())
58
+ assert "self" in put_params
59
+ assert "data" in put_params
60
+ assert "location" in put_params
61
+ assert "kwargs" in put_params
62
+
63
+
64
+ # =============================================================================
65
+ # Implementation Tests - Valid Implementations
66
+ # =============================================================================
67
+
68
+
69
+ def test_valid_implementation_basic():
70
+ """测试基本的有效实现"""
71
+
72
+ class ValidConnect(ConnectLike):
73
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
74
+ return b"data"
75
+
76
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
77
+ return ConnectRef(location=location)
78
+
79
+ instance = ValidConnect()
80
+ assert isinstance(instance, ConnectLike)
81
+
82
+
83
+ def test_valid_implementation_can_call_get_object():
84
+ """测试有效实现可以调用 get_object"""
85
+
86
+ class ValidConnect(ConnectLike):
87
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
88
+ return b"test_data"
89
+
90
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
91
+ return ConnectRef(location=location)
92
+
93
+ connect = ValidConnect()
94
+ result = connect.get_object("test_location")
95
+ assert result == b"test_data"
96
+
97
+
98
+ def test_valid_implementation_can_call_put_object():
99
+ """测试有效实现可以调用 put_object"""
100
+
101
+ class ValidConnect:
102
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
103
+ return b"data"
104
+
105
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
106
+ return ConnectRef(location=location, kind="test")
107
+
108
+ connect = ValidConnect()
109
+ result = connect.put_object(b"test_data", "test_location")
110
+ assert isinstance(result, ConnectRef)
111
+ assert result.location == "test_location"
112
+ assert result.kind == "test"
113
+
114
+
115
+ def test_valid_implementation_with_kwargs():
116
+ """测试有效实现支持 kwargs"""
117
+
118
+ class ValidConnect:
119
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
120
+ encoding = kwargs.get("encoding", "utf-8")
121
+ return f"data:{encoding}".encode()
122
+
123
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
124
+ kind = kwargs.get("kind", "default")
125
+ return ConnectRef(location=location, kind=kind)
126
+
127
+ connect = ValidConnect()
128
+
129
+ # Test get_object with kwargs
130
+ result = connect.get_object("location", encoding="ascii")
131
+ assert result == b"data:ascii"
132
+
133
+ # Test put_object with kwargs
134
+ ref = connect.put_object(b"data", "location", kind="custom")
135
+ assert ref.kind == "custom"
136
+
137
+
138
+ def test_valid_implementation_with_state():
139
+ """测试包含状态的有效实现"""
140
+
141
+ class StatefulConnect:
142
+ def __init__(self):
143
+ self.kind = "stateful"
144
+ self.call_count = 0
145
+
146
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
147
+ self.call_count += 1
148
+ return b"data"
149
+
150
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
151
+ self.call_count += 1
152
+ return ConnectRef(location=location)
153
+
154
+ connect = StatefulConnect()
155
+ assert isinstance(connect, ConnectLike)
156
+ assert connect.call_count == 0
157
+
158
+ connect.get_object("loc")
159
+ assert connect.call_count == 1
160
+
161
+ connect.put_object(b"data", "loc")
162
+ assert connect.call_count == 2
163
+
164
+
165
+ def test_valid_implementation_with_extra_methods():
166
+ """测试包含额外方法的有效实现"""
167
+
168
+ class RichConnect:
169
+ def __init__(self):
170
+ self.kind = "rich"
171
+
172
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
173
+ return b"data"
174
+
175
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
176
+ return ConnectRef(location=location)
177
+
178
+ def delete_object(self, location: str) -> None:
179
+ pass
180
+
181
+ def list_objects(self) -> list:
182
+ return []
183
+
184
+ connect = RichConnect()
185
+ assert isinstance(connect, ConnectLike)
186
+
187
+
188
+ # =============================================================================
189
+ # Implementation Tests - Invalid Implementations
190
+ # =============================================================================
191
+
192
+
193
+ def test_invalid_implementation_missing_get_object():
194
+ """测试缺少 get_object 方法的实现"""
195
+
196
+ class InvalidConnect:
197
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
198
+ return ConnectRef(location=location)
199
+
200
+ instance = InvalidConnect()
201
+ assert not isinstance(instance, ConnectLike)
202
+
203
+
204
+ def test_invalid_implementation_missing_put_object():
205
+ """测试缺少 put_object 方法的实现"""
206
+
207
+ class InvalidConnect:
208
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
209
+ return b"data"
210
+
211
+ instance = InvalidConnect()
212
+ assert not isinstance(instance, ConnectLike)
213
+
214
+
215
+ def test_invalid_implementation_missing_both():
216
+ """测试缺少所有方法的实现"""
217
+
218
+ class InvalidConnect:
219
+ pass
220
+
221
+ instance = InvalidConnect()
222
+ assert not isinstance(instance, ConnectLike)
223
+
224
+
225
+ def test_invalid_implementation_wrong_method_names():
226
+ """测试方法名错误的实现"""
227
+
228
+ class InvalidConnect:
229
+ def get(self, location: str, **kwargs: Any) -> bytes:
230
+ return b"data"
231
+
232
+ def put(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
233
+ return ConnectRef(location=location)
234
+
235
+ instance = InvalidConnect()
236
+ assert not isinstance(instance, ConnectLike)
237
+
238
+
239
+ # =============================================================================
240
+ # Type Checking Tests
241
+ # =============================================================================
242
+
243
+
244
+ def test_isinstance_with_valid_class():
245
+ """测试 isinstance 检查有效类"""
246
+
247
+ class MyConnect:
248
+ def __init__(self):
249
+ self.kind = "test"
250
+
251
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
252
+ return b""
253
+
254
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
255
+ return ConnectRef(location=location)
256
+
257
+ assert isinstance(MyConnect(), ConnectLike)
258
+
259
+
260
+ def test_isinstance_with_invalid_class():
261
+ """测试 isinstance 检查无效类"""
262
+
263
+ class NotConnect:
264
+ def __init__(self):
265
+ self.kind = "test"
266
+
267
+ def other_method(self):
268
+ pass
269
+
270
+ assert not isinstance(NotConnect(), ConnectLike)
271
+
272
+
273
+ def test_isinstance_with_builtin_types():
274
+ """测试 isinstance 检查内置类型"""
275
+ assert not isinstance(str(), ConnectLike)
276
+ assert not isinstance(int(), ConnectLike)
277
+ assert not isinstance(list(), ConnectLike)
278
+ assert not isinstance(dict(), ConnectLike)
279
+
280
+
281
+ def test_isinstance_with_none():
282
+ """测试 isinstance 检查 None"""
283
+ assert not isinstance(None, ConnectLike)
284
+
285
+
286
+ # =============================================================================
287
+ # Inheritance Tests
288
+ # =============================================================================
289
+
290
+
291
+ def test_can_inherit_from_protocol():
292
+ """测试可以继承协议"""
293
+
294
+ class BaseConnect(ConnectLike):
295
+ def __init__(self):
296
+ self.kind = "test"
297
+
298
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
299
+ return b"base"
300
+
301
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
302
+ return ConnectRef(location=location)
303
+
304
+ instance = BaseConnect()
305
+ assert isinstance(instance, ConnectLike)
306
+
307
+
308
+ def test_inherited_class_can_override():
309
+ """测试继承类可以重写方法"""
310
+
311
+ class BaseConnect(ConnectLike):
312
+ def __init__(self):
313
+ self.kind = "test"
314
+
315
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
316
+ return b"base"
317
+
318
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
319
+ return ConnectRef(location=location, kind="base")
320
+
321
+ class DerivedConnect(BaseConnect):
322
+ def __init__(self):
323
+ self.kind = "test"
324
+
325
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
326
+ return b"derived"
327
+
328
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
329
+ return ConnectRef(location=location, kind="derived")
330
+
331
+ derived = DerivedConnect()
332
+ assert isinstance(derived, ConnectLike)
333
+ assert derived.get_object("loc") == b"derived"
334
+ assert derived.put_object(b"data", "loc").kind == "derived"
335
+
336
+
337
+ # =============================================================================
338
+ # Real-World Usage Tests
339
+ # =============================================================================
340
+
341
+
342
+ def test_s3_like_implementation():
343
+ """测试类似 S3 的实现"""
344
+
345
+ class S3MockConnect:
346
+ def __init__(self):
347
+ self.kind = "test"
348
+ self.storage = {}
349
+
350
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
351
+ if location not in self.storage:
352
+ raise KeyError(f"Object not found: {location}")
353
+ return self.storage[location]
354
+
355
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
356
+ self.storage[location] = data
357
+ return ConnectRef(location=location, kind="s3")
358
+
359
+ connect = S3MockConnect()
360
+ assert isinstance(connect, ConnectLike)
361
+
362
+ # Put and get
363
+ ref = connect.put_object(b"test_data", "s3://bucket/key")
364
+ assert ref.location == "s3://bucket/key"
365
+
366
+ data = connect.get_object("s3://bucket/key")
367
+ assert data == b"test_data"
368
+
369
+
370
+ def test_filesystem_like_implementation():
371
+ """测试类似文件系统的实现"""
372
+
373
+ class FileSystemConnect:
374
+ def __init__(self):
375
+ self.kind = "test"
376
+ self.files = {}
377
+
378
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
379
+ return self.files.get(location, b"")
380
+
381
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
382
+ self.files[location] = data
383
+ return ConnectRef(location=location, kind="filesystem")
384
+
385
+ connect = FileSystemConnect()
386
+ assert isinstance(connect, ConnectLike)
387
+
388
+ # Test operations
389
+ ref = connect.put_object(b"file_content", "/path/to/file")
390
+ assert ref.kind == "filesystem"
391
+
392
+ content = connect.get_object("/path/to/file")
393
+ assert content == b"file_content"
394
+
395
+
396
+ def test_error_handling_implementation():
397
+ """测试包含错误处理的实现"""
398
+
399
+ class ErrorHandlingConnect:
400
+ def __init__(self):
401
+ self.kind = "test"
402
+
403
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
404
+ if not location:
405
+ raise ValueError("Location cannot be empty")
406
+ return b"data"
407
+
408
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
409
+ if not data:
410
+ raise ValueError("Data cannot be empty")
411
+ if not location:
412
+ raise ValueError("Location cannot be empty")
413
+ return ConnectRef(location=location)
414
+
415
+ connect = ErrorHandlingConnect()
416
+ assert isinstance(connect, ConnectLike)
417
+
418
+ # Test error cases
419
+ with pytest.raises(ValueError, match="Location cannot be empty"):
420
+ connect.get_object("")
421
+
422
+ with pytest.raises(ValueError, match="Data cannot be empty"):
423
+ connect.put_object(b"", "location")
424
+
425
+
426
+ def test_async_style_implementation():
427
+ """测试异步风格的实现(同步模拟)"""
428
+
429
+ class AsyncStyleConnect:
430
+ def __init__(self):
431
+ self.kind = "test"
432
+ self.pending = []
433
+
434
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
435
+ # Simulate async operation
436
+ self.pending.append(("get", location))
437
+ return b"async_data"
438
+
439
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
440
+ # Simulate async operation
441
+ self.pending.append(("put", location))
442
+ return ConnectRef(location=location, kind="async")
443
+
444
+ connect = AsyncStyleConnect()
445
+ assert isinstance(connect, ConnectLike)
446
+
447
+ connect.get_object("loc1")
448
+ connect.put_object(b"data", "loc2")
449
+
450
+ assert len(connect.pending) == 2
451
+ assert connect.pending[0] == ("get", "loc1")
452
+ assert connect.pending[1] == ("put", "loc2")
453
+
454
+
455
+ # =============================================================================
456
+ # Protocol Attribute Tests
457
+ # =============================================================================
458
+
459
+
460
+ def test_protocol_has_correct_attributes():
461
+ """测试协议具有正确的属性"""
462
+ # Check protocol defines required methods
463
+ assert hasattr(ConnectLike, "get_object")
464
+ assert hasattr(ConnectLike, "put_object")
465
+ # Verify it's marked as a protocol
466
+ assert hasattr(ConnectLike, "_is_protocol") or hasattr(ConnectLike, "__protocol_attrs__")
467
+
468
+
469
+ def test_protocol_module():
470
+ """测试协议所属模块"""
471
+ assert ConnectLike.__module__ == "xfintech.connect.common.connect"
472
+
473
+
474
+ def test_protocol_name():
475
+ """测试协议名称"""
476
+ assert ConnectLike.__name__ == "ConnectLike"
477
+
478
+
479
+ def test_protocol_has_docstring():
480
+ """测试协议有文档字符串"""
481
+ assert ConnectLike.__doc__ is not None
482
+ assert len(ConnectLike.__doc__) > 0
483
+
484
+
485
+ # =============================================================================
486
+ # Edge Cases
487
+ # =============================================================================
488
+
489
+
490
+ def test_implementation_with_optional_parameters():
491
+ """测试带可选参数的实现"""
492
+
493
+ class OptionalConnect:
494
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
495
+ return b"data"
496
+
497
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
498
+ return ConnectRef(
499
+ location=location,
500
+ kind=kwargs.get("kind"),
501
+ )
502
+
503
+ connect = OptionalConnect()
504
+ assert isinstance(connect, ConnectLike)
505
+
506
+ ref = connect.put_object(b"data", "loc", kind="custom")
507
+ assert ref.kind == "custom"
508
+
509
+
510
+ def test_implementation_with_default_values():
511
+ """测试带默认值的实现"""
512
+
513
+ class DefaultConnect:
514
+ def get_object(self, location: str = "default", **kwargs: Any) -> bytes:
515
+ return location.encode()
516
+
517
+ def put_object(self, data: bytes = b"", location: str = "default", **kwargs: Any) -> ConnectRef:
518
+ return ConnectRef(location=location)
519
+
520
+ connect = DefaultConnect()
521
+ assert isinstance(connect, ConnectLike)
522
+
523
+
524
+ def test_multiple_instances():
525
+ """测试多个实例"""
526
+
527
+ class SimpleConnect:
528
+ def __init__(self, name: str):
529
+ self.name = name
530
+
531
+ def get_object(self, location: str, **kwargs: Any) -> bytes:
532
+ return self.name.encode()
533
+
534
+ def put_object(self, data: bytes, location: str, **kwargs: Any) -> ConnectRef:
535
+ return ConnectRef(location=location, kind=self.name)
536
+
537
+ connect1 = SimpleConnect("first")
538
+ connect2 = SimpleConnect("second")
539
+
540
+ assert isinstance(connect1, ConnectLike)
541
+ assert isinstance(connect2, ConnectLike)
542
+
543
+ assert connect1.get_object("loc") == b"first"
544
+ assert connect2.get_object("loc") == b"second"