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,207 @@
1
+ import pytest
2
+
3
+ from xfintech.fabric.column.info import ColumnInfo, ColumnKind
4
+
5
+
6
+ def test_columninfo_basic_init():
7
+ col = ColumnInfo(
8
+ name="price",
9
+ kind="Float",
10
+ desc=" 股票价格 ",
11
+ meta={"unit": "CNY"},
12
+ )
13
+ assert col.name == "price"
14
+ assert col.kind == ColumnKind.FLOAT
15
+ assert col.desc == "股票价格"
16
+ assert col.meta == {"unit": "CNY"}
17
+
18
+
19
+ def test_columninfo_name_must_be_valid():
20
+ with pytest.raises(ValueError):
21
+ ColumnInfo(name="1invalid")
22
+
23
+
24
+ def test_columninfo_name_is_lowercase():
25
+ col = ColumnInfo(name="PriceHigh")
26
+ assert col.name == "pricehigh"
27
+
28
+
29
+ def test_columninfo_kind_from_datakind_instance():
30
+ col = ColumnInfo(name="qty", kind=ColumnKind.INTEGER)
31
+ assert col.kind == ColumnKind.INTEGER
32
+ assert col.name == "qty"
33
+ assert col.meta is None
34
+
35
+
36
+ def test_columninfo_kind_from_str_case_insensitive():
37
+ col = ColumnInfo(name="qty", kind="integer")
38
+ assert col.kind == ColumnKind.INTEGER
39
+ assert col.name == "qty"
40
+
41
+ col2 = ColumnInfo(name="qty", kind="InTeGeR")
42
+ assert col2.kind == ColumnKind.INTEGER
43
+ assert col2.name == "qty"
44
+
45
+
46
+ def test_columninfo_invalid_kind():
47
+ col = ColumnInfo(name="x", kind="NOT_A_TYPE")
48
+ assert col.kind == ColumnKind.STRING
49
+ assert col.desc == ""
50
+ assert col.meta is None
51
+
52
+
53
+ def test_columninfo_default_kind_string():
54
+ col = ColumnInfo(name="remark")
55
+ assert col.kind == ColumnKind.STRING
56
+ assert col.meta is None
57
+
58
+
59
+ def test_columninfo_desc_strip():
60
+ col = ColumnInfo(
61
+ name="remark",
62
+ desc=" Something Here ",
63
+ )
64
+ assert col.desc == "Something Here"
65
+ assert col.meta is None
66
+
67
+
68
+ def test_columninfo_desc_empty_when_none():
69
+ col = ColumnInfo(name="remark", desc=None)
70
+ assert col.desc == ""
71
+ assert col.meta is None
72
+
73
+
74
+ def test_columninfo_meta_bytes_to_str():
75
+ col = ColumnInfo(
76
+ name="flag",
77
+ meta={
78
+ b"bin": b"yes",
79
+ "code": b"ok",
80
+ },
81
+ )
82
+ assert col.meta == {"bin": "yes", "code": "ok"}
83
+ assert col.desc == ""
84
+
85
+
86
+ def test_columninfo_meta_str_normal():
87
+ col = ColumnInfo(name="flag", meta={"x": 1})
88
+ assert col.meta == {"x": 1}
89
+ assert col.desc == ""
90
+
91
+
92
+ def test_columninfo_update_kind_desc_meta():
93
+ col = ColumnInfo(
94
+ name="price",
95
+ kind="float",
96
+ desc="old",
97
+ meta={"unit": "CNY"},
98
+ )
99
+ col.update(
100
+ kind="integer",
101
+ desc="new-desc",
102
+ meta={"precision": 2},
103
+ )
104
+ assert col.kind == ColumnKind.INTEGER
105
+ assert col.desc == "new-desc"
106
+ assert col.meta == {"unit": "CNY", "precision": 2}
107
+ assert col.name == "price"
108
+
109
+
110
+ def test_columninfo_add_methods():
111
+ col = ColumnInfo(name="level")
112
+ col.add_desc("some desc")
113
+ assert col.desc == "some desc"
114
+
115
+ col.add_meta("k", "v")
116
+ assert col.meta["k"] == "v"
117
+
118
+ col.add_kind("Boolean")
119
+ assert col.kind == ColumnKind.BOOLEAN
120
+
121
+
122
+ def test_full_columninfo_to_dict_and_describe():
123
+ col = ColumnInfo(
124
+ name="amount",
125
+ kind="Float",
126
+ desc="amt",
127
+ meta={"unit": "usd"},
128
+ )
129
+ d1 = col.to_dict()
130
+ assert d1["name"] == "amount"
131
+ assert d1["kind"] == "Float"
132
+ assert d1["desc"] == "amt"
133
+ assert d1["meta"] == {"unit": "usd"}
134
+
135
+ d2 = col.describe()
136
+ assert d2["name"] == "amount"
137
+ assert d2["kind"] == "Float"
138
+ assert d2["desc"] == "amt"
139
+ assert d2["meta"] == {"unit": "usd"}
140
+
141
+
142
+ def test_partial_columninfo_to_dict_and_describe():
143
+ col2 = ColumnInfo(
144
+ name="flag",
145
+ kind="Boolean",
146
+ )
147
+ d3 = col2.to_dict()
148
+ assert d3["name"] == "flag"
149
+ assert d3["kind"] == "Boolean"
150
+ assert d3["desc"] == ""
151
+ assert d3["meta"] is None
152
+
153
+ d4 = col2.describe()
154
+ assert d4["name"] == "flag"
155
+ assert d4["kind"] == "Boolean"
156
+ assert "desc" not in d4
157
+ assert "meta" not in d4
158
+
159
+
160
+ def test_columninfo_str_and_repr():
161
+ col = ColumnInfo(name="price", kind="Float")
162
+ s = str(col)
163
+ assert "price: Float" in s
164
+
165
+ r = repr(col)
166
+ assert "name" in r
167
+ assert "price" in r
168
+ assert "Float" in r
169
+
170
+
171
+ def test_columninfo_identifier_is_deterministic():
172
+ col1 = ColumnInfo(
173
+ name="amount",
174
+ kind="Float",
175
+ desc="amt",
176
+ meta={"unit": "usd"},
177
+ )
178
+ col2 = ColumnInfo(
179
+ name="amount",
180
+ kind="Float",
181
+ desc="amt",
182
+ meta={"unit": "usd"},
183
+ )
184
+ assert col1.identifier == col2.identifier
185
+
186
+
187
+ def test_columninfo_identifier_not_change_with_meta():
188
+ col1 = ColumnInfo(
189
+ name="amount",
190
+ kind="Float",
191
+ desc="amt",
192
+ meta={"unit": "usd"},
193
+ )
194
+ col2 = ColumnInfo(
195
+ name="amount",
196
+ kind="Float",
197
+ desc="amt",
198
+ meta={"unit": "eur"},
199
+ )
200
+ col3 = ColumnInfo(
201
+ name="volume",
202
+ kind="Float",
203
+ desc="amt",
204
+ meta={"unit": "eur"},
205
+ )
206
+ assert col1.identifier == col2.identifier
207
+ assert col1.identifier != col3.identifier
@@ -0,0 +1,80 @@
1
+ from __future__ import annotations
2
+
3
+ from xfintech.fabric.column.kind import ColumnKind
4
+
5
+
6
+ def test_datakind_members_exist():
7
+ assert ColumnKind.INTEGER.value == "Integer"
8
+ assert ColumnKind.FLOAT.value == "Float"
9
+ assert ColumnKind.STRING.value == "String"
10
+ assert ColumnKind.BOOLEAN.value == "Boolean"
11
+ assert ColumnKind.DATETIME.value == "Datetime"
12
+ assert ColumnKind.CATEGORICAL.value == "Categorical"
13
+ assert ColumnKind.DATE.value == "Date"
14
+
15
+
16
+ def test_from_str_basic_cases():
17
+ assert ColumnKind.from_str("Integer") == ColumnKind.INTEGER
18
+ assert ColumnKind.from_str("Float") == ColumnKind.FLOAT
19
+ assert ColumnKind.from_str("String") == ColumnKind.STRING
20
+ assert ColumnKind.from_str("Boolean") == ColumnKind.BOOLEAN
21
+ assert ColumnKind.from_str("Datetime") == ColumnKind.DATETIME
22
+ assert ColumnKind.from_str("Categorical") == ColumnKind.CATEGORICAL
23
+
24
+
25
+ def test_from_str_case_insensitive():
26
+ assert ColumnKind.from_str("integer") == ColumnKind.INTEGER
27
+ assert ColumnKind.from_str("FLOAT") == ColumnKind.FLOAT
28
+ assert ColumnKind.from_str("sTrInG") == ColumnKind.STRING
29
+ assert ColumnKind.from_str("boolean") == ColumnKind.BOOLEAN
30
+ assert ColumnKind.from_str("DATETIME") == ColumnKind.DATETIME
31
+ assert ColumnKind.from_str("cAtEgOrIcAl") == ColumnKind.CATEGORICAL
32
+
33
+
34
+ def test_from_str_unknown_returns_unknown():
35
+ assert ColumnKind.from_str("SomethingElse") == ColumnKind.STRING
36
+ assert ColumnKind.from_str("") == ColumnKind.STRING
37
+ assert ColumnKind.from_str("???") == ColumnKind.STRING
38
+
39
+
40
+ def test_str_representation():
41
+ assert str(ColumnKind.INTEGER) == "Integer"
42
+ assert str(ColumnKind.STRING) == "String"
43
+ assert str(ColumnKind.DATE) == "Date"
44
+
45
+
46
+ def test_repr_representation():
47
+ assert repr(ColumnKind.INTEGER) == "ColumnKind.INTEGER"
48
+ assert repr(ColumnKind.CATEGORICAL) == "ColumnKind.CATEGORICAL"
49
+
50
+
51
+ def test_equality_with_string():
52
+ assert ColumnKind.INTEGER == "Integer"
53
+ assert ColumnKind.FLOAT == "float"
54
+ assert ColumnKind.STRING != "Boolean"
55
+ assert ColumnKind.DATETIME != "datetime2"
56
+ assert ColumnKind.CATEGORICAL == "CATEGORICAL"
57
+
58
+
59
+ def test_inequality_with_string():
60
+ assert ColumnKind.INTEGER != "Float"
61
+ assert ColumnKind.BOOLEAN != "boolean2"
62
+ assert ColumnKind.DATE != "DateTime"
63
+
64
+
65
+ def test_equality_with_enum():
66
+ assert ColumnKind.INTEGER == ColumnKind.INTEGER
67
+ assert ColumnKind.FLOAT != ColumnKind.STRING
68
+ assert ColumnKind.DATE == ColumnKind.DATE
69
+
70
+
71
+ def test_inequality_with_enum():
72
+ assert ColumnKind.INTEGER != ColumnKind.FLOAT
73
+ assert ColumnKind.BOOLEAN != ColumnKind.DATETIME
74
+ assert ColumnKind.CATEGORICAL != ColumnKind.DATE
75
+
76
+
77
+ def test_missing_method():
78
+ assert ColumnKind("integer") == ColumnKind.INTEGER
79
+ assert ColumnKind("FLOAT") == ColumnKind.FLOAT
80
+ assert ColumnKind("unknown_value") == ColumnKind.STRING
@@ -0,0 +1,5 @@
1
+ from .info import TableInfo
2
+
3
+ __all__ = [
4
+ "TableInfo",
5
+ ]
@@ -0,0 +1,263 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import re
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from xfintech.fabric.column.info import ColumnInfo
9
+ from xfintech.fabric.column.kind import ColumnKind
10
+
11
+
12
+ class TableInfo:
13
+ """
14
+ 描述:
15
+ - 表信息。
16
+
17
+ 参数:
18
+ - name: str, optional, 表名称。 默认为空字符串。
19
+ - desc: str, optional, 表描述信息。 默认为空字符串。
20
+ - meta: Dict[str, Any], optional, 表元数据。 默认为None。
21
+ - columns: List[ColumnInfo], optional, 列字段信息列表。 默认为空。
22
+
23
+ 属性:
24
+ - name: str, 表名称,统一为小写。
25
+ - desc: str, 表描述信息。
26
+ - meta: Dict[str, Any], 表元数据。
27
+ - columns: Dict[str, ColumnInfo], 列字段信息字典,键为列名称(小写)。
28
+
29
+ 方法:
30
+ - from_dict(data): 从字典创建 TableInfo 实例。
31
+ - get_column(name): 根据列名称获取 ColumnInfo 实例。
32
+ - remove_column(name): 根据列名称移除 ColumnInfo 实例。
33
+ - add_column(column): 添加 ColumnInfo 实例。
34
+ - update_column(name, new, kind, desc, meta): 更新列字段信息。
35
+ - rename_column(old, new): 重命名列字段。
36
+ - list_columns(): 列出所有 ColumnInfo 实例。
37
+ - describe(): 返回表信息的描述字典。
38
+ - to_dict(): 返回表信息的字典表示。
39
+
40
+ 例子:
41
+ ```python
42
+ from xfintech.fabric.table.info import TableInfo
43
+ from xfintech.fabric.column.info import ColumnInfo
44
+ from xfintech.fabric.column.kind import ColumnKind
45
+
46
+ table = TableInfo(
47
+ desc="日线行情表",
48
+ meta={"source": "tushare"},
49
+ columns=[
50
+ ColumnInfo(
51
+ name="price",
52
+ kind="Float",
53
+ desc="收盘价",
54
+ ),
55
+ ColumnInfo(
56
+ name="volume",
57
+ kind=ColumnKind.INTEGER,
58
+ desc="成交量",
59
+ meta={"unit": "shares"},
60
+ ),
61
+ ],
62
+ )
63
+ print(table.describe())
64
+ ```
65
+ """
66
+
67
+ _NAME_PATTERN = re.compile(r"^[A-Za-z_][A-Za-z0-9_-]*$")
68
+
69
+ @classmethod
70
+ def from_dict(
71
+ cls,
72
+ data: Dict[str, Any],
73
+ ) -> "TableInfo":
74
+ return cls(
75
+ name=data.get("name"),
76
+ desc=data.get("desc"),
77
+ meta=data.get("meta"),
78
+ columns=data.get("columns"),
79
+ )
80
+
81
+ def __init__(
82
+ self,
83
+ name: Optional[str] = None,
84
+ desc: Optional[str] = None,
85
+ meta: Optional[Dict[str, Any]] = None,
86
+ columns: Optional[List[ColumnInfo | Dict[str, Any]]] = None,
87
+ ):
88
+ self.name = self._resolve_name(name)
89
+ self.desc = self._resolve_desc(desc)
90
+ self.meta = self._resolve_meta(meta)
91
+ self.columns = self._resolve_columns(columns)
92
+
93
+ def _resolve_name(
94
+ self,
95
+ value: Optional[str],
96
+ ) -> str:
97
+ if not value:
98
+ return ""
99
+ else:
100
+ value = value.strip()
101
+ if not self._NAME_PATTERN.match(value):
102
+ raise ValueError(f"Invalid table name: {value}")
103
+ else:
104
+ return value.lower()
105
+
106
+ def _resolve_desc(
107
+ self,
108
+ value: Optional[str],
109
+ ) -> Optional[str]:
110
+ if value is None:
111
+ return ""
112
+ else:
113
+ return value.strip()
114
+
115
+ def _resolve_meta(
116
+ self,
117
+ meta: Optional[Dict[str, Any]],
118
+ ) -> Optional[Dict[str, Any]]:
119
+ if meta is None:
120
+ return None
121
+ resolved: Dict[str, Any] = {}
122
+ for k, v in meta.items():
123
+ if isinstance(v, bytes):
124
+ v = v.decode("utf8")
125
+ if isinstance(k, bytes):
126
+ k = k.decode("utf8")
127
+ resolved[k] = v
128
+ return resolved
129
+
130
+ def _resolve_columns(
131
+ self,
132
+ columns: Optional[List[ColumnInfo | Dict[str, Any]]],
133
+ ) -> Dict[str, ColumnInfo]:
134
+ if columns is None:
135
+ return {}
136
+
137
+ resolved: Dict[str, ColumnInfo] = {}
138
+ for item in columns:
139
+ if isinstance(item, ColumnInfo):
140
+ resolved[item.name] = item
141
+ elif isinstance(item, dict):
142
+ col = ColumnInfo.from_dict(item)
143
+ resolved[col.name] = col
144
+ else:
145
+ raise TypeError(f"Invalid column type: {type(item)}")
146
+ return resolved
147
+
148
+ @property
149
+ def identifier(self) -> str:
150
+ result = {}
151
+ result["name"] = self.name
152
+ result["desc"] = self.desc
153
+ result["columns"] = []
154
+ values = sorted(
155
+ self.columns.values(),
156
+ key=lambda c: c.name,
157
+ )
158
+ for col in values:
159
+ result["columns"].append(
160
+ {
161
+ "name": col.name,
162
+ "kind": col.kind.value,
163
+ }
164
+ )
165
+ dna = json.dumps(
166
+ result,
167
+ sort_keys=True,
168
+ ensure_ascii=False,
169
+ separators=(",", ":"),
170
+ )
171
+ return hashlib.sha256(dna.encode("utf-8")).hexdigest()
172
+
173
+ def __str__(self) -> str:
174
+ return self.columns.__str__()
175
+
176
+ def __repr__(self) -> str:
177
+ return f"{self.__class__.__name__}(name={self.name})"
178
+
179
+ def get_column(
180
+ self,
181
+ name: str,
182
+ ) -> Optional[ColumnInfo]:
183
+ return self.columns.get(name.lower())
184
+
185
+ def remove_column(
186
+ self,
187
+ name: str,
188
+ ) -> "TableInfo":
189
+ key = name.lower()
190
+ if key in self.columns:
191
+ del self.columns[key]
192
+ return self
193
+
194
+ def add_column(
195
+ self,
196
+ column: ColumnInfo | Dict[str, Any],
197
+ ) -> "TableInfo":
198
+ if isinstance(column, dict):
199
+ column = ColumnInfo.from_dict(column)
200
+ self.columns[column.name] = column
201
+ return self
202
+
203
+ def update_column(
204
+ self,
205
+ name: str,
206
+ new: Optional[str] = None,
207
+ kind: Optional[ColumnKind | str] = None,
208
+ desc: Optional[str] = None,
209
+ meta: Optional[Dict[str, Any]] = None,
210
+ ) -> "TableInfo":
211
+ oldkey = name.lower()
212
+ if oldkey in self.columns:
213
+ self.columns[oldkey].update(
214
+ kind=kind,
215
+ desc=desc,
216
+ meta=meta,
217
+ )
218
+ if new is not None:
219
+ self.rename_column(
220
+ old=name,
221
+ new=new,
222
+ )
223
+ return self
224
+
225
+ def rename_column(
226
+ self,
227
+ old: str,
228
+ new: str,
229
+ ) -> "TableInfo":
230
+ oldkey = old.lower()
231
+ newkey = new.lower()
232
+ if oldkey in self.columns:
233
+ self.columns[oldkey].update(name=new)
234
+ self.columns[newkey] = self.columns[oldkey]
235
+ del self.columns[oldkey]
236
+ return self
237
+
238
+ def list_columns(self) -> List[ColumnInfo]:
239
+ return list(self.columns.values())
240
+
241
+ def list_column_names(self) -> List[str]:
242
+ return list(self.columns.keys())
243
+
244
+ def describe(self) -> Dict[str, Any]:
245
+ result = {}
246
+ if self.name:
247
+ result["name"] = self.name
248
+ if self.desc:
249
+ result["desc"] = self.desc
250
+ if self.meta:
251
+ result["meta"] = self.meta
252
+ if self.columns:
253
+ result["columns"] = [c.describe() for c in self.list_columns()]
254
+ return result
255
+
256
+ def to_dict(self) -> Dict[str, Any]:
257
+ return {
258
+ "identifier": self.identifier,
259
+ "name": self.name,
260
+ "desc": self.desc,
261
+ "meta": self.meta,
262
+ "columns": [c.to_dict() for c in self.list_columns()],
263
+ }
File without changes