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,633 @@
1
+ import pandas as pd
2
+ import pytest
3
+
4
+ from xfintech.data.source.tushare.stock.companybusiness import CompanyBusiness
5
+ from xfintech.data.source.tushare.stock.companybusiness.constant import (
6
+ KEY,
7
+ NAME,
8
+ PAGINATE,
9
+ SOURCE,
10
+ TARGET,
11
+ )
12
+
13
+ # Test Fixtures
14
+
15
+
16
+ class FakeConnection:
17
+ """Fake Tushare connection for testing"""
18
+
19
+ def __init__(self, frame: pd.DataFrame):
20
+ self.frame = frame
21
+
22
+ def fina_mainbz_vip(self, **kwargs):
23
+ """Mock fina_mainbz_vip API call"""
24
+ return self.frame
25
+
26
+
27
+ class FakeSession:
28
+ """Fake session for testing"""
29
+
30
+ def __init__(self, connection: FakeConnection):
31
+ self.connection = connection
32
+
33
+
34
+ @pytest.fixture
35
+ def mock_session():
36
+ """Create a mock session with empty data"""
37
+ fake_conn = FakeConnection(frame=pd.DataFrame())
38
+ return FakeSession(fake_conn)
39
+
40
+
41
+ @pytest.fixture
42
+ def sample_source_data():
43
+ """Sample company business composition data in Tushare format"""
44
+ return pd.DataFrame(
45
+ {
46
+ "ts_code": ["000001.SZ", "000001.SZ", "000002.SZ"],
47
+ "end_date": ["20200331", "20200331", "20200331"],
48
+ "bz_item": ["产品A", "产品B", "产品C"],
49
+ "bz_sales": ["100000000.50", "80000000.75", "50000000.25"],
50
+ "bz_profit": ["15000000.30", "12000000.40", "6000000.15"],
51
+ "bz_cost": ["85000000.20", "68000000.35", "44000000.10"],
52
+ "curr_type": ["CNY", "CNY", "CNY"],
53
+ "update_flag": ["1", "1", "1"],
54
+ }
55
+ )
56
+
57
+
58
+ # Initialization Tests
59
+
60
+
61
+ def test_companybusiness_init_basic(mock_session):
62
+ """Test basic initialization with required session"""
63
+ business = CompanyBusiness(session=mock_session)
64
+ assert business.name == NAME
65
+ assert business.key == KEY
66
+ assert business.source == SOURCE
67
+ assert business.target == TARGET
68
+ assert business.paginate == PAGINATE
69
+
70
+
71
+ def test_companybusiness_init_with_params_dict(mock_session):
72
+ """Test initialization with params as dict"""
73
+ params = {"ts_code": "000001.SZ", "period": "20201231", "type": "P"}
74
+ business = CompanyBusiness(session=mock_session, params=params)
75
+ assert business.params.get("ts_code") == "000001.SZ"
76
+ assert business.params.get("period") == "20201231"
77
+ assert business.params.get("type") == "P"
78
+
79
+
80
+ def test_companybusiness_init_with_params_object(mock_session):
81
+ """Test initialization with params as Params object"""
82
+ from xfintech.data.common.params import Params
83
+
84
+ params = Params(ts_code="000001.SZ", period="20201231")
85
+ business = CompanyBusiness(session=mock_session, params=params)
86
+ assert business.params.get("ts_code") == "000001.SZ"
87
+
88
+
89
+ def test_companybusiness_init_with_type_param(mock_session):
90
+ """Test initialization with type parameter"""
91
+ params = {"ts_code": "000001.SZ", "type": "P"}
92
+ business = CompanyBusiness(session=mock_session, params=params)
93
+ assert business.params.get("type") == "P"
94
+
95
+
96
+ def test_companybusiness_init_with_cache_bool_true(mock_session):
97
+ """Test initialization with cache enabled"""
98
+ business = CompanyBusiness(session=mock_session, cache=True)
99
+ assert business.cache is not None
100
+
101
+
102
+ def test_companybusiness_init_with_cache_bool_false(mock_session):
103
+ """Test initialization with cache disabled"""
104
+ business = CompanyBusiness(session=mock_session, cache=False)
105
+ assert business.cache is None
106
+
107
+
108
+ def test_companybusiness_init_with_cache_dict(mock_session):
109
+ """Test initialization with cache config dict"""
110
+ cache_config = {"path": "/tmp/cache", "key": "test"}
111
+ business = CompanyBusiness(session=mock_session, cache=cache_config)
112
+ assert business.cache is not None
113
+
114
+
115
+ def test_companybusiness_init_default_paginate_limit(mock_session):
116
+ """Test that default pagination limit is set correctly"""
117
+ business = CompanyBusiness(session=mock_session)
118
+ assert business.paginate.pagesize
119
+ assert business.paginate.pagelimit
120
+
121
+
122
+ def test_companybusiness_init_with_all_params(mock_session):
123
+ """Test initialization with all parameters"""
124
+ params = {"ts_code": "000001.SZ", "period": "20201231", "type": "P"}
125
+ coolant = {"interval": 0.5}
126
+ retry = {"max_attempts": 3}
127
+ cache = True
128
+
129
+ business = CompanyBusiness(session=mock_session, params=params, coolant=coolant, retry=retry, cache=cache)
130
+ assert business.params.get("ts_code") == "000001.SZ"
131
+ assert business.cache is not None
132
+
133
+
134
+ def test_companybusiness_constants():
135
+ """Test that constants are correctly defined"""
136
+ assert NAME == "companybusiness"
137
+ assert KEY == "/tushare/companybusiness"
138
+ assert SOURCE.name == "fina_mainbz_vip"
139
+ assert TARGET.name == "companybusiness"
140
+ assert PAGINATE.pagesize
141
+
142
+
143
+ # Transform Tests
144
+
145
+
146
+ def test_companybusiness_transform_basic(sample_source_data):
147
+ """Test basic transformation of business composition data"""
148
+ fake_conn = FakeConnection(frame=sample_source_data)
149
+ session = FakeSession(fake_conn)
150
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
151
+
152
+ result = business.transform(sample_source_data)
153
+
154
+ assert len(result) == 3
155
+ assert "code" in result.columns
156
+ assert "date" in result.columns
157
+ assert "datecode" in result.columns
158
+
159
+
160
+ def test_companybusiness_transform_code_mapping(sample_source_data):
161
+ """Test that ts_code is correctly mapped to code"""
162
+ fake_conn = FakeConnection(frame=sample_source_data)
163
+ session = FakeSession(fake_conn)
164
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
165
+
166
+ result = business.transform(sample_source_data)
167
+
168
+ assert result.iloc[0]["code"] == "000001.SZ"
169
+ assert result.iloc[2]["code"] == "000002.SZ"
170
+
171
+
172
+ def test_companybusiness_transform_date_format(sample_source_data):
173
+ """Test that dates are properly formatted"""
174
+ fake_conn = FakeConnection(frame=sample_source_data)
175
+ session = FakeSession(fake_conn)
176
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
177
+
178
+ result = business.transform(sample_source_data)
179
+
180
+ assert pd.api.types.is_datetime64_any_dtype(result["date"]) is False
181
+ assert result.iloc[0]["date"] == "2020-03-31"
182
+
183
+
184
+ def test_companybusiness_transform_datecode_preserved(sample_source_data):
185
+ """Test that datecode is correctly created from end_date"""
186
+ fake_conn = FakeConnection(frame=sample_source_data)
187
+ session = FakeSession(fake_conn)
188
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
189
+
190
+ result = business.transform(sample_source_data)
191
+
192
+ assert result.iloc[0]["datecode"] == "20200331"
193
+ assert result.iloc[1]["datecode"] == "20200331"
194
+
195
+
196
+ def test_companybusiness_transform_numeric_conversions(sample_source_data):
197
+ """Test that numeric fields are properly converted"""
198
+ fake_conn = FakeConnection(frame=sample_source_data)
199
+ session = FakeSession(fake_conn)
200
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
201
+
202
+ result = business.transform(sample_source_data)
203
+
204
+ assert result.iloc[0]["bz_sales"] == 100000000.50
205
+ assert result.iloc[0]["bz_profit"] == 15000000.30
206
+ assert pd.api.types.is_numeric_dtype(result["bz_sales"])
207
+
208
+
209
+ def test_companybusiness_transform_string_fields(sample_source_data):
210
+ """Test that string fields are properly converted"""
211
+ fake_conn = FakeConnection(frame=sample_source_data)
212
+ session = FakeSession(fake_conn)
213
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
214
+
215
+ result = business.transform(sample_source_data)
216
+
217
+ assert result.iloc[0]["bz_item"] == "产品A"
218
+ assert result.iloc[0]["curr_type"] == "CNY"
219
+ assert result.iloc[0]["update_flag"] == "1"
220
+
221
+
222
+ def test_companybusiness_transform_empty_dataframe():
223
+ """Test transformation with empty dataframe"""
224
+ fake_conn = FakeConnection(frame=pd.DataFrame())
225
+ session = FakeSession(fake_conn)
226
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
227
+
228
+ result = business.transform(pd.DataFrame())
229
+
230
+ assert isinstance(result, pd.DataFrame)
231
+ assert result.empty
232
+ assert len(result.columns) == len(TARGET.list_column_names())
233
+
234
+
235
+ def test_companybusiness_transform_none_input():
236
+ """Test transformation with None input"""
237
+ fake_conn = FakeConnection(frame=pd.DataFrame())
238
+ session = FakeSession(fake_conn)
239
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
240
+
241
+ result = business.transform(None)
242
+
243
+ assert isinstance(result, pd.DataFrame)
244
+ assert result.empty
245
+
246
+
247
+ def test_companybusiness_transform_handles_invalid_dates():
248
+ """Test that invalid dates are handled gracefully"""
249
+ data = pd.DataFrame(
250
+ {
251
+ "ts_code": ["000001.SZ"],
252
+ "end_date": ["invalid"],
253
+ "bz_item": ["产品A"],
254
+ "bz_sales": ["100000.00"],
255
+ "curr_type": ["CNY"],
256
+ "update_flag": ["1"],
257
+ }
258
+ )
259
+
260
+ fake_conn = FakeConnection(frame=data)
261
+ session = FakeSession(fake_conn)
262
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
263
+
264
+ result = business.transform(data)
265
+
266
+ assert len(result) == 1
267
+ assert pd.isna(result.iloc[0]["date"])
268
+
269
+
270
+ def test_companybusiness_transform_removes_duplicates(sample_source_data):
271
+ """Test that duplicate rows are removed"""
272
+ # Create data with duplicates
273
+ data = pd.concat([sample_source_data, sample_source_data.iloc[[0]]], ignore_index=True)
274
+
275
+ fake_conn = FakeConnection(frame=data)
276
+ session = FakeSession(fake_conn)
277
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
278
+
279
+ result = business.transform(data)
280
+
281
+ # Should have 3 unique rows, not 4
282
+ assert len(result) == 3
283
+
284
+
285
+ def test_companybusiness_transform_sorts_by_code_and_date(sample_source_data):
286
+ """Test that output is sorted by code and date"""
287
+ fake_conn = FakeConnection(frame=sample_source_data)
288
+ session = FakeSession(fake_conn)
289
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
290
+
291
+ result = business.transform(sample_source_data)
292
+
293
+ # Check first row is 000001.SZ
294
+ assert result.iloc[0]["code"] == "000001.SZ"
295
+ assert result.iloc[0]["date"] == "2020-03-31"
296
+ # Check last row is 000002.SZ
297
+ assert result.iloc[2]["code"] == "000002.SZ"
298
+
299
+
300
+ def test_companybusiness_transform_resets_index():
301
+ """Test that index is reset after transformation"""
302
+ data = pd.DataFrame(
303
+ {
304
+ "ts_code": ["000001.SZ", "000002.SZ"],
305
+ "end_date": ["20200331", "20200331"],
306
+ "bz_item": ["产品A", "产品B"],
307
+ "bz_sales": ["100000.00", "50000.00"],
308
+ "curr_type": ["CNY", "CNY"],
309
+ "update_flag": ["1", "1"],
310
+ },
311
+ index=[5, 10],
312
+ )
313
+
314
+ fake_conn = FakeConnection(frame=data)
315
+ session = FakeSession(fake_conn)
316
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
317
+
318
+ result = business.transform(data)
319
+
320
+ assert result.index.tolist() == [0, 1]
321
+
322
+
323
+ def test_companybusiness_transform_only_target_columns(sample_source_data):
324
+ """Test that only target columns are in output"""
325
+ fake_conn = FakeConnection(frame=sample_source_data)
326
+ session = FakeSession(fake_conn)
327
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
328
+
329
+ result = business.transform(sample_source_data)
330
+
331
+ expected_cols = set(TARGET.list_column_names())
332
+ actual_cols = set(result.columns)
333
+
334
+ assert actual_cols == expected_cols
335
+
336
+
337
+ # Run Method Tests
338
+
339
+
340
+ def test_companybusiness_run_with_cache_hit(sample_source_data):
341
+ """Test that run() returns cached data when available"""
342
+ fake_conn = FakeConnection(frame=sample_source_data)
343
+ session = FakeSession(fake_conn)
344
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"}, cache=True)
345
+
346
+ # First run should fetch and cache
347
+ result1 = business.run()
348
+
349
+ # Second run should return cached data
350
+ result2 = business.run()
351
+
352
+ pd.testing.assert_frame_equal(result1, result2)
353
+
354
+
355
+ def test_companybusiness_run_basic_date_range(sample_source_data):
356
+ """Test run() with date range parameters"""
357
+ fake_conn = FakeConnection(frame=sample_source_data)
358
+ session = FakeSession(fake_conn)
359
+ business = CompanyBusiness(
360
+ session=session,
361
+ params={"ts_code": "000001.SZ", "start_date": "20200101", "end_date": "20201231"},
362
+ )
363
+
364
+ result = business.run()
365
+
366
+ assert isinstance(result, pd.DataFrame)
367
+ assert len(result) > 0
368
+
369
+
370
+ def test_companybusiness_run_with_period_param(sample_source_data):
371
+ """Test run() with period parameter"""
372
+ fake_conn = FakeConnection(frame=sample_source_data)
373
+ session = FakeSession(fake_conn)
374
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ", "period": "20200331"})
375
+
376
+ result = business.run()
377
+
378
+ assert isinstance(result, pd.DataFrame)
379
+
380
+
381
+ def test_companybusiness_run_with_datetime_params(sample_source_data):
382
+ """Test run() with datetime objects as parameters"""
383
+ from datetime import datetime
384
+
385
+ fake_conn = FakeConnection(frame=sample_source_data)
386
+ session = FakeSession(fake_conn)
387
+ business = CompanyBusiness(
388
+ session=session,
389
+ params={
390
+ "ts_code": "000001.SZ",
391
+ "start_date": datetime(2020, 1, 1),
392
+ "end_date": datetime(2020, 12, 31),
393
+ },
394
+ )
395
+
396
+ result = business.run()
397
+
398
+ assert isinstance(result, pd.DataFrame)
399
+
400
+
401
+ def test_companybusiness_run_preserves_fields_param(sample_source_data):
402
+ """Test that run() preserves fields parameter if provided"""
403
+ fake_conn = FakeConnection(frame=sample_source_data)
404
+ session = FakeSession(fake_conn)
405
+ custom_fields = "ts_code,end_date,bz_item,bz_sales"
406
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ", "fields": custom_fields})
407
+
408
+ # Monkey patch _fetchall to capture params
409
+ captured_params = {}
410
+
411
+ def mock_fetchall(api, **kwargs):
412
+ captured_params.update(kwargs)
413
+ return sample_source_data
414
+
415
+ business._fetchall = mock_fetchall
416
+ business.run()
417
+
418
+ assert captured_params["fields"] == custom_fields
419
+
420
+
421
+ def test_companybusiness_run_sets_cache(sample_source_data):
422
+ """Test that run() saves result to cache"""
423
+ fake_conn = FakeConnection(frame=sample_source_data)
424
+ session = FakeSession(fake_conn)
425
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"}, cache=True)
426
+
427
+ result = business.run()
428
+
429
+ # Cache should be set after run
430
+ cached = business._load_cache()
431
+ assert cached is not None
432
+ pd.testing.assert_frame_equal(result, cached)
433
+
434
+
435
+ def test_companybusiness_run_calls_transform(sample_source_data):
436
+ """Test that run() calls transform method"""
437
+ fake_conn = FakeConnection(frame=sample_source_data)
438
+ session = FakeSession(fake_conn)
439
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
440
+
441
+ # Monkey patch transform to track if it was called
442
+ original_transform = business.transform
443
+ transform_called = {"called": False}
444
+
445
+ def mock_transform(data):
446
+ transform_called["called"] = True
447
+ return original_transform(data)
448
+
449
+ business.transform = mock_transform
450
+ business.run()
451
+
452
+ assert transform_called["called"] is True
453
+
454
+
455
+ def test_companybusiness_run_uses_fina_mainbz_vip_api(sample_source_data):
456
+ """Test that run() uses fina_mainbz_vip API"""
457
+ fake_conn = FakeConnection(frame=sample_source_data)
458
+ session = FakeSession(fake_conn)
459
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
460
+
461
+ # Monkey patch _fetchall to capture API
462
+ captured_api = {"api": None}
463
+
464
+ def mock_fetchall(api, **kwargs):
465
+ captured_api["api"] = api
466
+ return sample_source_data
467
+
468
+ business._fetchall = mock_fetchall
469
+ business.run()
470
+
471
+ assert captured_api["api"] == session.connection.fina_mainbz_vip
472
+
473
+
474
+ # Integration Tests
475
+
476
+
477
+ def test_companybusiness_full_workflow(sample_source_data):
478
+ """Test complete workflow from initialization to output"""
479
+ fake_conn = FakeConnection(frame=sample_source_data)
480
+ session = FakeSession(fake_conn)
481
+
482
+ business = CompanyBusiness(
483
+ session=session,
484
+ params={"ts_code": "000001.SZ", "period": "20200331", "type": "P"},
485
+ cache=True,
486
+ )
487
+
488
+ result = business.run()
489
+
490
+ # Verify output structure
491
+ assert isinstance(result, pd.DataFrame)
492
+ assert len(result) == 3
493
+ assert "code" in result.columns
494
+ assert "date" in result.columns
495
+ assert "bz_item" in result.columns
496
+ assert "bz_sales" in result.columns
497
+
498
+ # Verify data types
499
+ assert pd.api.types.is_numeric_dtype(result["bz_sales"])
500
+ assert result.iloc[0]["code"] == "000001.SZ"
501
+
502
+
503
+ def test_companybusiness_cache_persistence(sample_source_data):
504
+ """Test that cache persists across multiple runs"""
505
+ fake_conn = FakeConnection(frame=sample_source_data)
506
+ session = FakeSession(fake_conn)
507
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"}, cache=True)
508
+
509
+ # Run once to populate cache
510
+ result1 = business.run()
511
+
512
+ # Clear in-memory data to simulate fresh load
513
+ business2 = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"}, cache=True)
514
+ result2 = business2.run()
515
+
516
+ pd.testing.assert_frame_equal(result1, result2)
517
+
518
+
519
+ def test_companybusiness_params_uniqueness(mock_session):
520
+ """Test that different params produce different cache keys"""
521
+ business1 = CompanyBusiness(
522
+ session=mock_session,
523
+ params={"ts_code": "000001.SZ", "period": "20200331"},
524
+ cache=True,
525
+ )
526
+ business2 = CompanyBusiness(
527
+ session=mock_session,
528
+ params={"ts_code": "000001.SZ", "period": "20210331"},
529
+ cache=True,
530
+ )
531
+
532
+ # Test that different params are properly stored
533
+ assert business1.params.get("period") == "20200331"
534
+ assert business2.params.get("period") == "20210331"
535
+ assert business1.params.get("period") != business2.params.get("period")
536
+
537
+
538
+ def test_companybusiness_different_stocks(sample_source_data):
539
+ """Test that different stock codes are handled correctly"""
540
+ fake_conn = FakeConnection(frame=sample_source_data)
541
+ session = FakeSession(fake_conn)
542
+
543
+ business1 = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
544
+ result1 = business1.run()
545
+
546
+ business2 = CompanyBusiness(session=session, params={"ts_code": "000002.SZ"})
547
+ result2 = business2.run()
548
+
549
+ # Both should have data for their respective stocks
550
+ assert "000001.SZ" in result1["code"].values
551
+ assert "000002.SZ" in result2["code"].values
552
+
553
+
554
+ def test_companybusiness_empty_result_handling():
555
+ """Test handling of empty API results"""
556
+ empty_data = pd.DataFrame()
557
+ fake_conn = FakeConnection(frame=empty_data)
558
+ session = FakeSession(fake_conn)
559
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
560
+
561
+ result = business.run()
562
+
563
+ assert isinstance(result, pd.DataFrame)
564
+ assert result.empty
565
+ assert len(result.columns) > 0
566
+
567
+
568
+ def test_companybusiness_large_dataset_handling():
569
+ """Test handling of large datasets"""
570
+ # Create large dataset
571
+ large_data = pd.DataFrame(
572
+ {
573
+ "ts_code": ["000001.SZ"] * 1000,
574
+ "end_date": ["20200331"] * 1000,
575
+ "bz_item": ["产品A"] * 1000,
576
+ "bz_sales": ["100000.00"] * 1000,
577
+ "curr_type": ["CNY"] * 1000,
578
+ "update_flag": ["1"] * 1000,
579
+ }
580
+ )
581
+
582
+ fake_conn = FakeConnection(frame=large_data)
583
+ session = FakeSession(fake_conn)
584
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
585
+
586
+ result = business.run()
587
+
588
+ # Should deduplicate to 1 row
589
+ assert len(result) == 1
590
+
591
+
592
+ def test_companybusiness_without_cache(sample_source_data):
593
+ """Test that class works correctly without caching"""
594
+ fake_conn = FakeConnection(frame=sample_source_data)
595
+ session = FakeSession(fake_conn)
596
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"}, cache=False)
597
+
598
+ result = business.run()
599
+
600
+ assert isinstance(result, pd.DataFrame)
601
+ assert len(result) > 0
602
+ assert business.cache is None
603
+
604
+
605
+ def test_companybusiness_handles_missing_numeric_fields():
606
+ """Test that missing numeric fields don't break transformation"""
607
+ # Data with only subset of fields
608
+ minimal_data = pd.DataFrame(
609
+ {
610
+ "ts_code": ["000001.SZ"],
611
+ "end_date": ["20200331"],
612
+ "bz_item": ["产品A"],
613
+ "bz_sales": ["100000.00"],
614
+ "curr_type": ["CNY"],
615
+ "update_flag": ["1"],
616
+ }
617
+ )
618
+
619
+ fake_conn = FakeConnection(frame=minimal_data)
620
+ session = FakeSession(fake_conn)
621
+ business = CompanyBusiness(session=session, params={"ts_code": "000001.SZ"})
622
+
623
+ result = business.run()
624
+
625
+ # Should complete without error
626
+ assert len(result) == 1
627
+ # Missing fields should be NaN
628
+ assert pd.isna(result.iloc[0]["bz_profit"])
629
+
630
+
631
+ def test_companybusiness_api_doc_reference():
632
+ """Test that class correctly references API documentation"""
633
+ assert "doc_id=81" in CompanyBusiness.__doc__
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from xfintech.data.source.tushare.stock.companycashflow.companycashflow import (
4
+ CompanyCashflow,
5
+ )
6
+ from xfintech.data.source.tushare.stock.companycashflow.constant import (
7
+ KEY,
8
+ NAME,
9
+ PAGINATE,
10
+ SOURCE,
11
+ TARGET,
12
+ )
13
+
14
+ __all__ = [
15
+ "CompanyCashflow",
16
+ "KEY",
17
+ "NAME",
18
+ "PAGINATE",
19
+ "SOURCE",
20
+ "TARGET",
21
+ ]